Игра в демки, пиар ангуляра и обучение.
Идея ! Предлагаю попубликовать мелкие но интересные приложения написанные на этом фреймворке вами лично.
Профит= пропиарим фреймворк + обменяемся опытом. Присоединяйтесь :) Начнём с простого. Калькулятор калорий. <!doctype html> <html ng-app> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> function СompCnt($scope) { //todo массив из значений $scope.mass=50; $scope.stature=170; $scope.age=20; $scope.calories=0; $scope.computing=function(){ $scope.calories=10 * $scope.mass + 6.25*$scope.stature-5*$scope.age+5; } //запустим чтобы калории посчитались из значений по умолчанию $scope.computing(); } </script> </head> <body> <H3>Калькулятор потребности в калориях</h3> <div ng-controller="СompCnt"> Вес:<input type="text" ng-model="mass" ng-change="computing()"> Рост:<input type="text" ng-model="stature" ng-change="computing()"> Возраст:<input type="text" ng-model="age" ng-change="computing()"> <hr/> Потребность мужчины в калориях: <b>{{calories}}</b> калорий в день </div> </body> </html> |
микроскопическая todo
<!doctype html> <html ng-app> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> function TodoCntl($scope) { //todo массив из значений $scope.todo = []; //Метод добавляем в массив значение и сбрасывает $scope.add=function(name){ $scope.todo.push({text:$scope.text}); $scope.text=""; } //Метод remove удаляет все задачи $scope.remove=function(name){ $scope.todo=[]; } } </script> </head> <body> <div ng-controller="TodoCntl"> <form ng-submit="add()"> <input type="text" ng-model="text"> <input class="btn-primary" type="submit" value="add"> </form> <hr/> <ul> <li ng-repeat="item in todo | filter:query" > {{item.text}} </li> </ul> <button ng-click="remove()">Очистить</button> </div> </body> </html> |
Тренажёр для запоминания английских слов.
<!doctype html> <html ng-app> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> function LangCntl($scope) { // Данные для теста, вопрос, варианты и правильный ответ var data=[ { word:"for", translate:["для","после","цикл","этот"], realTranslate:"для" }, { word:"mix", translate:["имельчить","смешать","взболтать","гоголь моголь"], realTranslate:"смешать" }, { word:"angular", translate:["яркий","пушистый","умный","гранёный"], realTranslate:"гранёный" } ]; // выставим первый вопрос $scope.quest=data[0]; //счётчик $scope.count=0; //функция проверяющая ответы пользователя $scope.respond=function(variant){ // проверим ответ if(variant==$scope.quest.realTranslate) alert('Верно!'); else alert('увы, но правильный ответ '+$scope.quest.realTranslate); //зададим следующий вопрос, но только если вопросы некончились if($scope.count<data.length-1){ $scope.count++; $scope.quest=data[$scope.count]; } else{ alert("тестирование окончено"); } } } </script> </head> <body> <div ng-controller="LangCntl"> вопрос {{count+1}} ( кликайте по правильному ответу)<br/> Как переводится <b>{{quest.word}}</b> <hr/> <ul> <li ng-repeat="item in quest.translate | filter:query" ng-click="respond(item)"> {{item}} </li> </ul> </div> </body> </html> |
интересная штука этот ангуляр. Это я говорю не после того, как увидел твои примеры, а после прочтения некоторой части доки http://angular.ru/guide/overview
еще статья http://habrahabr.ru/post/172975/ |
Отличная идея! Пока возьму пару примеров оттуда, а потом отсюда что-нибудь туда :-)
Редактируемый древовидный список <!doctype html> <html ng-app="myApp"> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script> angular.module("myApp", []); function TreeController($scope) { $scope.delete = function(data) { data.nodes = []; }; $scope.add = function(data) { var post = data.nodes.length + 1; var newName = data.name + '-' + post; data.nodes.push({name: newName,nodes: []}); }; $scope.tree = [ {name: 'Узел', nodes: [ {name: 'Морской', nodes: []}, {name: 'Устричный', nodes: []} ]} ]; }; </script> </head> <body> <script type="text/ng-template" id="item.html" ng-init="data.edit=false" > <span ng-show="data.edit"> <input type="text" value="{{data.name}}" ng-model="data.name"/> <button ng-click="data.edit=false">сохр.</button> </span> <span ng-hide="data.edit"> {{data.name}} <button ng-click="data.edit=true">ред.</button> </span> <button ng-click="add(data)">Добавить узел</button> <button ng-click="delete(data)" ng-show="data.nodes.length > 0">Удалить узел</button> <ul> <li ng-repeat="data in data.nodes" ng-include="'item.html'" class="node"></li> </ul> </script> <ul ng-controller="TreeController"> <li ng-repeat="data in tree" ng-include="'item.html'" class="node"></li> </ul> </body> </html> |
Цитата:
График и таблица связанные общими данными, демонстрирует наследование scope контролами tableController и chartController от mainController <!doctype html> <html ng-app> <head> <style> .bar{ width:50px; background-color:#0F0; margin-right:5px; float:left; } </style> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> function mainController($scope) { // здесь будем хранить данные, // благодаря тому что они обьявлены здесь ими могут пользоваться оба контролёра унаследовавших scope $scope.items=[ {label:"Африка",val:25}, {label:"Европа",val:20} ]; } function tableController($scope) { //добавляет строку в таблицу $scope.add=function(){ $scope.items.push({val:0}); }; // метод не позволяет выставить больше 100% $scope.verife=function(item){ if (item.val>100) item.val=100; if (item.val<0) item.val=0; }; } function chartController2($scope) { } </script> </head> <body ng-controller="mainController"> <div ng-controller="chartController2"> <div style="height:310px;background-color:#000;padding:5px;"> <div class="bar" ng-repeat="item in items" style="height:{{item.val*3}}px; margin-top:{{300-item.val*3}}px;"> {{item.val}}% </div> </div> </div> <div ng-controller="tableController"> <table> <tr ng-repeat="item in items"> <td> <input ng-model="item.label"/></td> <td><input ng-model="item.val" ng-change="verife(item)"/>% </td> </tr> </table> <button ng-click="add()">Добавить запись </button> </div> </body> </html> |
|
Цитата:
|
Это вроде как оптимизация
http://jsperf.com/apply-vs-call-vs-invoke |
Ага. Правда, по тестам мне сложно сказать что там лучше, но учитывая, что этих тестов 15 ревизий и последняя была два дня назад, разработчики знают что делают :-)
|
Тот же самый пример что и в посте 6, но написан он иначе.
во первых теперь есть модуль вместо mainControler использована фабрика(factory) А контроллеры объявляются в модуле <!doctype html> <html ng-app="myApp"> <head> <style> .bar{ width:50px; background-color:#0F0; margin-right:5px; float:left; } </style> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //Обьявим модуль var myApp=angular.module('myApp', []); //Используем фабрику myApp.factory('Items',function(){ return [ {label:"Африка",val:25}, {label:"Европа",val:20} ] }) //контролёр таблицы myApp.controller('tableController',function($scope,Items){ $scope.items=Items; //добавляет строку в таблицу $scope.add=function(){ $scope.items.push({val:0}); }; // метод не позволяет выставить больше 100% $scope.verife=function(item){ if (item.val>100) item.val=100; if (item.val<0) item.val=0; }; }); //контролёр графика myApp.controller('chartController',function($scope,Items){ $scope.items=Items; }); </script> </head> <body> <div ng-controller="chartController"> <div style="height:310px;background-color:#000;padding:5px;"> <div class="bar" ng-repeat="item in items" style="height:{{item.val*3}}px; margin-top:{{300-item.val*3}}px;"> {{item.val}}% </div> </div> </div> <div ng-controller="tableController"> <table> <tr ng-repeat="item in items"> <td> <input ng-model="item.label"/></td> <td><input ng-model="item.val" ng-change="verife(item)"/>% </td> </tr> </table> <button ng-click="add()">Добавить запись </button> </div> </body> </html> |
dragable при помощи деректив
идея простая если к любому элементу добавить dragable, то его можно перемещать мышью <!doctype html> <html ng-app="myApp"> <head> <style> .noselect { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none; } .block{ width:50px; height:50px; cursor:move; } </style> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //Обьявим модуль var myApp=angular.module('myApp', []); //создадим дерективу myApp.directive('dragable',function(){ return function(scope,element,attr){ //метод срабатывает при mouseMove function move(e){ element[0].style.top=e.y+"px"; element[0].style.left=e.x+"px"; }; // срабатывает при отпускании мыши function mouseUp(){ document.removeEventListener('mousemove',move); document.removeEventListener('mouseUp',mouseUp); } //подпишимся на клик по элементу element.bind('mousedown',function(){ //выставим позицию в absolute вдруг нестоит :) element[0].style.position="absolute"; //подпишимся на перемещения мыши document.addEventListener('mousemove',move); //подпишимся на отпускание мыши document.addEventListener('mouseup',mouseUp); }) } }); </script> </head> <body class="noselect"> <div dragable style="background-color:#999;" class="block">drag me</div> <div dragable style="background-color:#99F;" class="block">drag me</div> <div dragable style="background-color:#F99;" class="block">drag me</div> <div dragable style="background-color:#9F9;" class="block">drag me</div> <div style="background-color:#000;color:white; cursor:auto;" class="block">no drag</div> </body> </html> |
Панель инструментов. Пример, как обернуть jQuery-плагин директивой AngularJS
<!doctype html> <html ng-app="Toolbar"> <head> <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script> <script src="http://paulkinzett.github.com/toolbar/js/jquery.toolbar.js"></script> <script> angular.module('Toolbar', []) .directive('toolbarTip', function() { return { link: function(scope, element, attrs) { // Функция link отдает в качестве параметра элемент, помеченный нашим атрибутом. // Оборачиваем этот элемент jQuery, и получаем из attrs значение атрибута. // Функция scope.$eval() вычисляет переданное ей выражение. В нашем случае // просто превращает строку в массив с параметрами плагина $(element).toolbar(scope.$eval(attrs.toolbarTip)); } }; }); </script> <link rel="stylesheet" type="text/css" href="http://paulkinzett.github.com/toolbar/css/toolbars.css"> <style> #format-toolbar { margin-left: auto; margin-right: auto; } #format-toolbar-options { display: none; } .settings-button { width: 36px; height: 28px; border-radius: 5px; border: 1px solid #161615; box-shadow: inset 0px 1px 3px 0px rgba(0, 0, 0, .26), 0px 1px 0px 0px rgba(255, 255, 255, .15); opacity: 0.3; background-color: #343433; z-index: 2; display: block; margin: 60px 44px; } .settings-button:hover, .pressed { background-color: #343433; opacity: 0.7; cursor: pointer; z-index: 2; } .settings-button img { margin: 5px auto 0px auto; display: block; z-index: -1; } </style> </head> <body> <!-- Место, куда нужно щелкать, чтобы показалась панель инструментов --> <div id="format-toolbar" class="settings-button" toolbar-tip="{content: '#format-toolbar-options', position: 'top'}"> <img src="http://paulkinzett.github.com/toolbar/img/icon-cog-small.png"> </div> <!-- Код панели инструментов --> <div id="format-toolbar-options"> <a href="#"><i class="icon-align-left"></i></a> <a href="#"><i class="icon-align-center"></i></a> <a href="#"><i class="icon-align-right"></i></a> </div> </body> </html> |
Цитата:
Цитата:
Еще пример практически "из коробки". Позволяет делать элементы редактируемыми. <!doctype html> <html ng-app="directive"> <head> <script src="http://code.angularjs.org/1.1.4/angular.min.js"></script> <script> angular.module('directive', []).directive('contenteditable', function() { return { require: 'ngModel', link: function(scope, elm, attrs, ctrl) { // вид -> модель elm.bind('blur', function() { scope.$apply(function() { ctrl.$setViewValue(elm.html()); }); }); // модель -> вид ctrl.$render = function(value) { elm.html(value); }; // загрузка начального значения из DOM ctrl.$setViewValue(elm.html()); } }; }); </script> <style> div[contentEditable] { cursor: pointer; background-color: #D0D0D0; margin-bottom: 1em; padding: 1em; } </style> </head> <body> <div contentEditable="true" ng-model="content">Измените текст</div> <pre>model = {{content}}</pre> </body> </html> |
кстати, буквально рядом лежит тема на мой взгляд достаточно интересная http://javascript.ru/forum/angular/3...angularjs.html
|
|
Ещё одну демку набросал
можно менять стили div щелчок по div работает аналогично reset Демонстрирует как менять стили демонстрирует использование контролёра в директиве демонстрирует применение watch а также тонкости взаимодействия control и link в частности необходимость вызова $scope.$apply() если меняешь scope из link Демонстрирует применение шаблонов <!doctype html> <html ng-app="myApp"> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //Обьявим модуль var myApp=angular.module('myApp', []); //создадим дерективу myApp.directive('demo',function(){ return { //значит что это элемент, тоесть демо <demo> restrict:"E", //здесь можно установить связь атрбутов со свойствами scope scope:{ }, //печалька метод find содержит всего одну строчку element.getElementsByTagName(selector), нету поиска по классу link:function($scope,el,attrs,ctrl){ el.find('div')[0].addEventListener('click',function(){ //вызовем метод сброса $scope.reset(); //затем чтобы данные из изменённого scope применились к html придётся вызвать метод $apply $scope.$apply(); }); }, controller:function($scope){ //здесь храним стиль $scope.divstyle={}; //Сьрасывает свойство на настройки по умолчанию $scope.reset=function(){ $scope.width="100"; $scope.height="100"; $scope.border="1"; $scope.divstyle["background-color"]="#0f0"; } $scope.reset(); // я отслеживаю изменения свойств при помощи $watch, // так как к некотрым свойствам нужно дописывать px или что то ещё //добавляем px к width $scope.$watch('width', function() { $scope.divstyle.width=$scope.width+"px"; }); //добавляем px к height $scope.$watch('height', function() { $scope.divstyle.height=$scope.height+"px"; }); //формируем border $scope.$watch('border', function() { $scope.divstyle.border="solid "+$scope.border+"px"; }); // Вместо нескольких $watch мы могли использовать и один // $scope.$watch(function(){ // $scope.divstyle.border="solid "+$scope.border+"px"; // $scope.divstyle.height=$scope.height+"px"; // $scope.divstyle.width=$scope.width+"px"; // }); }, //шаблон котрый будет помещён в демо template: "<div ng-style='divstyle' class='demobox'></div>"+ "<div style='position:absolute;right:10px;top:0px;'>"+ "width:<input ng-model='width' type='range' max='800'/><br/>"+ "height:<input ng-model='height' type='range' max='800'/><br/>"+ "background-color:<input ng-model='divstyle["+'"background-color"'+"]' type='color'/><br/>"+ "border:<input ng-model='border' type='range' max='50'/><br/>"+ "<button ng-click='reset()'>reset</button>"+ "</div>" } }); </script> </head> <body > <!-- вот так вот дериктива используется в приложении --> <demo> </demo> </body> </html> |
Тоже с $watch играюсь. Хочу, чтобы он отслеживал изменение всего списка, но при этом показывал какой именно элемент изменился. Пока приходится делать отдельный $watch для каждого элемента, что не очень нравится.
<!doctype html> <html ng-app="myApp"> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script> angular.module('myApp',[]) function TodoCtrl($scope) { $scope.todos = [ {done: true, text: "foo"}, {done: false, text: "bar"} ]; } function TodoItemCtrl($scope) { $scope.$watch('todos[$index]', function(newval, oldval, scope) { alert( "Изменен:" + $scope.todos[$scope.$index].text ); }, true); } </script> </head> <body> <div ng-controller="TodoCtrl"> <ul> <li ng-repeat="todo in todos" ng-controller="TodoItemCtrl"> <input type="checkbox" ng-model="todo.done"> {{todo.text}} </li> </ul> </div> </body> </html> |
Это несовсем демка, это небольшой опыт показывающий изоляцию scope. Если кто то собирается писать на ангуляре это одна из базовых вещей которую вы обязаны понимать.
есть три директивы experement1, experement2, demo experement1 и experement2 вложены в demo у каждой директивы свой scope experement 1 имеет полный доступ к scope demo experement 2 имеет доступ только к одному параметру родительского scope и какой это именно будет параметр определяется через атрибут param1 эксперементы кликабельны а главный scope можно сбросить. <!doctype html> <html ng-app="myApp"> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //Обьявим модуль var myApp=angular.module('myApp', []); //создадим дерективу myApp.directive('test',function(){ return { restrict:"E", scope:{}, controller:function($scope){ $scope.reset=function(){ $scope.test1='root scope'; $scope.test2='root scope'; } $scope.reset(); } } }); // первый эксперемент 1 // имеет полный доступ к родительскому scope (так как нет scope:{} ) myApp.directive('experement1',function(){ return { restrict:"E", controller:function($scope,$element){ $element.bind('click',function(){ $scope.test1="experement1"; $scope.test2="experement1"; $scope.$apply(); }) $scope.$watch ( function(){ //alert('test1='+$scope.test1 +' test2='+ $scope.test2); }); } } }); // эксперемент 2 // имеет доступ только к однуму из свойств родительского scope, свойство будет доступен через param1 myApp.directive('experement2',function(){ return { restrict:"E", scope:{ //через param1 будет устанавливаться связь с родительским scope param1:"=" }, controller:function($scope,$element){ $element.bind('click',function(){ $scope.param1="experement2"; $scope.test2="experement2"; $scope.$apply(); }) $scope.$watch ( function(){ //alert('param1='+$scope.param1 +' test2='+ $scope.test2); }); } } }); </script> </head> <body > <test> <experement1 > {{'test1="'+test1 +'" test2="'+ test2+'"'}} </experement1> <br/><br/> <experement2 param1="test1" > {{'param1="'+param1 +'" test2="'+ test2+'"'}} </experement2> <br/><br/> <button ng-click="reset()">reset</button> </test> </body> </html> в двух словах что вы видите. experement1 полность отображает то что содержится в родительском scope при клике он поменяет содержимое родительский scope изменение родительского scope повлияет только на param1 из experement2 experement2 отображает только один из параметров test1 родительского scope, при помощи param1 при клике он поменяет только test1 изначально test2 пуст так как он несвязан с родительским scope если в test2 будет установлено значение то оно не как не будет связано с родительским scope, тоесть свойство будет принадлежать именно scope experement2 |
Опираясь на вышеприведённый материал
я переписал демку таблицы и графика теперь таблица и графики это независимые, никак несвязанные компоненты, которые можно применять в любом приложении независимо друг от друга. Также можно применять вместе и соединять из в произвольном порядке. компоненты будут связаны если у них будет общий datasource <!doctype html> <html ng-app="myApp"> <head> <style> .bar{ width:50px; background-color:#0F0; margin-right:5px; float:left; } </style> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //====================================================================================// //==================================== ПРИЛОЖЕНИЕ ====================================// //====================================================================================// //Обьявим модуль var myApp=angular.module('myApp', ['qChart','qTable']); //данные myApp.factory('Items',function(){ return [ {label:"Африка",val:25}, {label:"Европа",val:20} ] }) //контролер приложения myApp.controller('appCtrl',function($scope,Items){ $scope.items=Items; }); //====================================================================================// //=================================== мОДУЛЬ TABLE===================================// //====================================================================================// var qTable=angular.module('qTable', []); qTable.directive('qtable',function(){ return { restrict:"E", scope:{ datasource:"=" }, controller:function($scope){ //добавляет строку в таблицу $scope.add=function(){ $scope.datasource.push({val:0}); }; // метод не позволяет выставить больше 100% $scope.verife=function(item){ if (item.val>100) item.val=100; if (item.val<0) item.val=0; }; }, template: '<table>' +'<tr ng-repeat="item in datasource">' +'<td> ' +'<input ng-model="item.label"/></td> <td><input ng-model="item.val" ng-change="verife(item)"/>%' +'</td>' +'</tr> ' +'</table>' +'<button ng-click="add()">Добавить запись </button>' } }); //====================================================================================// //=================================== мОДУЛЬ CHART===================================// //====================================================================================// var qChart=angular.module('qChart', []); qChart.directive('qchart',function(){ return { restrict:"E", scope:{ //через param1 будет устанавливаться связь с родительским scope datasource:"=" }, template: '<div style="height:310px;background-color:#000;padding:5px;">'+ '<div class="bar" ng-repeat="item in datasource" style="height:{{item.val*3}}px; margin-top:{{300-item.val*3}}px;">'+ '{{item.val}}%'+ '</div>'+ '</div>' } }); </script> </head> <body ng-controller="appCtrl"> <qchart datasource="items"> </qchart> <qtable datasource="items"> </qtable> </body> </html> |
Антипаттерн или способ убить scope
watch отслеживает изменения scope, и меняет одно из отслеживаемых значений затем сам же реагирует на своё изменение, тоесть уходит в бесконечный цикл. Создатели фреймворка глубину рекурсии искуственно ограничили 10ю вызовами, после 10 бросают исключение. <!doctype html> <html ng-app="myApp"> <head> <style> </style> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //Обьявим модуль var myApp=angular.module('myApp', []); //создадим дерективу myApp.directive('test',function(){ return { restrict:"E", scope:{}, controller:function($scope){ $scope.count=0; $scope.$watch ( function(){ alert('реагирую на count=' +$scope.count); $scope.count++; }); } } }); </script> </head> <body > <test>count={{count}}</test> </body> </html> |
Ещё один опыт интересный
Я задался вопорсом в каком порядке срабатывают watch в scope, при учёте что scope неизолирован. Впринципе нечего сверхестественного судя по логу watch срабатывают сверху внизсогласно вложенности деректив Если watch неизменил значение(выставил такое же как и было) тогда лог становится пустым, нет измененией watch несрабатывают поэтому лог пустой Также нет никакого значения откуда пришло изменение Я нехотел прослушивать log, чтобы неполучить бесконечную рекурсию, ведь каждый watch мняет лог, поэтому witch слушает только hello. <!doctype html> <html ng-app="myApp"> <head> <style> test2{ padding-left:50px; display:block; } </style> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //Обьявим модуль var myApp=angular.module('myApp', []); //создадим дерективу myApp.directive('test',function(){ return { restrict:"E", scope:{}, controller:function($scope){ $scope.hello=0; $scope.log=[]; $scope.$watch ('hello', function(){ $scope.log.push('main'); }); } } }); //создадим дерективу myApp.directive('test2',function(){ return { restrict:"E", controller:function($scope,$element,$attrs){ $element.bind('click',function(e){ $scope.hello=$attrs['name']; //сбросим лог $scope.log=[]; //опубликуем изменения //$scope.$digest(); $scope.$apply(); e.stopPropagation(); }) $scope.$watch ('hello', function(){ $scope.log.push($attrs['name']+" run"); }); } } }); </script> </head> <body > <h3> ClickZone </h3> <test> <test2 name="t1">(click t1)</test2> <test2 name="t2">(click t2)</test2> <test2 name="t3">(click t3)</test2> <test2 name="t4"> <test2 name="t4-1">(click t4-1)</test2> <test2 name="t4-2">(click t4-2)</test2> <test2 name="t4-3">(click t4-3) <test2 name="t4-3-1">(click t4-3-1)</test2> <test2 name="t4-3-2">(click t4-3-2)</test2> </test2> </test2> <test2 name="t5">(click t6)</test2> <br/><br/> <h3> LogZone </h3> {{log}} <br/><br/> <h3>hello= {{hello}} </h3> </test> </body> </html> |
Следуюший вопрос это порядок срабатывания watch в случае если scope изолирован. Чтобы было чему всплывать я сделаю связывание через аттрибут hello2
Как видно из опыта всплытие не происходит выше уровня родительского scope. Надо сказать такое поведение сперва здорово озадачивает. Но если вдуматься то scope ведь изолированный, и если hello обьявлен не в нём то он просто напросто недоступен. А если свойство недоступно то ангуляр создаёт это свойство. Вот поэтому (test4-1 test4-2 test4-3) и (test4-3-1 test4-3-2) имеют своё собственное значение, ведь у них свой собственной персональный hello Зато всё прекрасно всплывает из (t6-1 и t6-2) всё дело в том что мы их подписали на hello2 который есть у t6, а в t6 hello2 связан с hello. Что касается всплытия то вначале срабатывает watch кликнутого элемента, затем watch родителя, затем соседи кликнутого элемента, и потом переходим к родителю родителя, потом соседи родителя кликнутого элемента. Если кто хочет знать моём мнение, то оно такое. Scope сделан генеально ! <!doctype html> <html ng-app="myApp"> <head> <style> test2{ padding-left:50px; display:block; } </style> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //Обьявим модуль var myApp=angular.module('myApp', []); //создадим дерективу myApp.directive('test',function(){ return { restrict:"E", scope:{}, controller:function($scope){ $scope.hello="main "; $scope.log=[]; $scope.$watch ('hello', function(){ $scope.log.push('main'); }); } } }); //создадим дерективу myApp.directive('test2',function(){ return { restrict:"E", scope:{ hello2:"=", log:"=" }, controller:function($scope,$element,$attrs){ $element.bind('click',function(e){ $scope.hello2=$attrs['name']; //alert($scope.hello2); //сбросим лог $scope.log=[]; //опубликуем изменения $scope.$apply(); //предотвратим всплытие e.stopPropagation(); }) $scope.$watch ('hello2', function(){ $scope.log.push($attrs['name']); }); } } }); </script> </head> <body > <h3> ClickZone </h3> <test> <test2 hello2="hello" log="log" name="t1">(click t1) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t2">(click t2) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t3">(click t3) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t4"> <test2 hello2="hello" log="log" name="t4-1">(click t4-1) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t4-2">(click t4-2) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t4-3">(click t4-3) hello2={{hello2}} <test2 hello2="hello" log="log" name="t4-3-1">(click t4-3-1) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t4-3-2">(click t4-3-2) hello2={{hello2}}</test2> </test2> </test2> <test2 log="log" hello2="hello" log="log" name="t5">(click t5) hello2={{hello2}}</test2> <test2 log="log" hello2="hello" log="log" name="t6">(click t6) hello2={{hello2}} <test2 hello2="hello2" log="log" name="t6-1">(click t6-1) hello2={{hello2}} (связка hello2->hello2->hello) </test2> <test2 hello2="hello2" log="log" name="t6-2">(click t6-2) hello2={{hello2}} (связка hello2->hello2->hello) </test2> </test2> <br/><br/> <h3> LogZone </h3> {{log}} <br/><br/> <h3>hello= {{hello}} </h3> </test> </body> </html> |
В javascript все обьекты передаются по ссылке и отследить их изменние непростая задача (даже с Object.define)
Как с этим справится angular? Я очень подло засунул значение в обьект hihi, тот в свою очередь в haha, а тот в hello. короче получилось hello.haha.hihi.hello="main" Печалька но ангуляр несправился. измененения публикуются, но публикуются только благодаря $apply $watch срабатывает только при первом запуске, $watch попросту не в состоянии отследить изменения в обьекте. Если бы он мог отследить то заполнялся бы log, а лог пуст. Так же стоит обратить внимание что кликать на всё что ниже t4 бесполезно, это потому что hello2=undefined соответственно писать hello.бла бесполезно. В консоли мы увидим Cannot read property 'haha' of undefined Может watchCollection попробывать ? Увы болт ! watchCollection тоже неможет отследить такую глубокую вложенность. Хотя для отслеживания массива вполне годен. Короче чуда не произошло. Ну и фиг с ним, и так круто в конце концов watchCollection сможет отслеживать измениния в обьекте или в массиве, а без отслеживания обьектов в обьекте мы как нибудь проживём. К тому же watch или watchCollection всегда можно выставить на интерисующие свойство. <!doctype html> <html ng-app="myApp"> <head> <style> test2{ padding-left:50px; display:block; } </style> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //Обьявим модуль var myApp=angular.module('myApp', []); //создадим дерективу myApp.directive('test',function(){ return { restrict:"E", scope:{}, controller:function($scope){ $scope.hello={ haha:{ hihi:{ hello:"main" } } }; $scope.log=[]; $scope.$watch ('hello', function(){ $scope.log.push('main'); }); } } }); //создадим дерективу myApp.directive('test2',function(){ return { restrict:"E", scope:{ hello2:"=", log:"=" }, controller:function($scope,$element,$attrs){ $element.bind('click',function(e){ $scope.hello2.haha.hihi.hello=$attrs['name'] ; //alert($scope.hello2); //сбросим лог $scope.log=[]; //опубликуем изменения $scope.$apply(); //предотвратим всплытие e.stopPropagation(); }); $scope.$watch ('hello2', function(){ $scope.log.push($attrs['name']); }); $scope.$watchCollection('hello2',function(){ $scope.log.push( $attrs['name'] ); }); // Заремариный код будет работать, так как он отслеживает значение а не обьект //$scope.$watch ('hello2.haha.hihi.hello', function(){ // $scope.log.push($attrs['name']); //}); } } }); </script> </head> <body > <h3> ClickZone </h3> <test> <test2 hello2="hello" log="log" name="t1">(click t1) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t2">(click t2) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t3">(click t3) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t4"> <test2 hello2="hello" log="log" name="t4-1">(click t4-1) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t4-2">(click t4-2) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t4-3">(click t4-3) hello2={{hello2}} <test2 hello2="hello" log="log" name="t4-3-1">(click t4-3-1) hello2={{hello2}}</test2> <test2 hello2="hello" log="log" name="t4-3-2">(click t4-3-2) hello2={{hello2}}</test2> </test2> </test2> <test2 log="log" hello2="hello" log="log" name="t5">(click t5) hello2={{hello2}}</test2> <test2 log="log" hello2="hello" log="log" name="t6">(click t6) hello2={{hello2}} <test2 hello2="hello2" log="log" name="t6-1">(click t6-1) hello2={{hello2}} (связка hello2->hello2->hello) </test2> <test2 hello2="hello2" log="log" name="t6-2">(click t6-2) hello2={{hello2}} (связка hello2->hello2->hello) </test2> </test2> <br/><br/> <h3> LogZone </h3> {{log}} <br/><br/> <h3>hello= {{hello}} </h3> </test> </body> </html> |
DjDiablo, клёво! Изучаю твои примеры :-) В том, где experement1, experement2, demo «reset» ничего не сбрасывает, кстати.
Дополнил прошлый пример про $watch. Показал наследование областей видимости <!doctype html> <html ng-app> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> function UserListCtrl($scope) { $scope.users = [{name: 'Oleg', age: 27}, {name: 'Diana', age: 25}, {name: 'Bob', age: 30}]; $scope.last = {name: 'нет'}; } function UserItemCtrl($scope) { $scope.$watch('users[$index]', function(newValue, oldValue, scope) { if (newValue === oldValue) return; $scope.last.name = $scope.users[$scope.$index].name; //Мы используем параметр 'name' из объекта 'last', чтобы Angular, не найдя 'last' //в текущей области видимости, стал бы искать в родительской (где объявлен объект 'last') //Если бы мы задавали 'name' напрямую ($scope.name = 'нет'), то Angular просто создал бы //такой же параметр со значением $scope.users[$scope.$index].name в дочерней области видимости, //перекрыв им значение из родительской области }, true); } </script> </head> <body> <div ng-app ng-controller="UserListCtrl"> <ul> <li ng-repeat="user in users" ng-controller="UserItemCtrl" ng-model="users"> <input ng-model="user.name"/> </li> </ul> <div> Последнее изменение: {{last.name}} </div> </div> </body> </html> |
Небольшой опыт демонстрирующий порядок инициализации директив.
важно если используешь compile функция link несработает если compile не использовать то сначало сработает controller зетем link Если нечего не путаю то link это аналог compile post В укороченной записи срабатывает именно link myApp.directive('demo',function(){ return function(){ //я линк } }); собственно сам опыт <!doctype html> <html ng-app="myApp"> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> //Обьявим модуль var myApp=angular.module('myApp', []); //создадим дерективу myApp.directive('demo',function(){ return { //значит что это элемент, тоесть демо <demo> restrict:"E", //здесь можно установить связь атрбутов со свойствами scope scope:{}, compile:function(){ alert("compile"); return{ pre:function($scope, $element, $attrs, $controller){ alert('pre'); }, post:function($scope, $element, $attrs, $controller){ alert('post'); } } }, link:function($scope,el,attrs,ctrl){ alert("link"); }, controller:function($scope){ alert("controller"); $scope.test="test"; }, template:"{{test}}{{test}}" } }); </script> </head> <body > <demo>{{test}} </demo> </body> </html> |
Всё так. Подобный пример видел здесь: http://jsfiddle.net/vojtajina/8yzbZ/
Кстати, разработчики планируют упростить АПИ директив, так что в будущем недопониманий будет меньше |
Создание пустого экземпляра ресурса
Иногда требуется получить пустой ресурсный объект, не связанный с БД. Что отправляется на сервер можно посмотреть в консоли браузера
<!doctype html> <html ng-app="myApp"> <head> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script src="http://code.angularjs.org/1.1.5/angular-resource.js"></script> <script language="javascript" type="text/javascript"> angular.module('myApp', ['ngResource']) .factory('Res', function($resource){ return $resource('action.php') }) function myCtrl($scope, Res) { var res = blankRes(); $scope.res = res.value $scope.send = function () { res.$save() } function blankRes () { var resource = new Res resource.value = 'default' return resource } } </script> </head> <body> <div ng-controller="myCtrl"> Ресурс: <input ng-model="res" /> <button ng-click="send()">Сохранить</buton> </div> </body> </html> |
Цитата:
|
Цитата:
|
Делал демо angularjs animations with animate.css, слайдер получился :)
http://nervgh.github.io/pages/angularjs-and-animatecss/ |
|
калькулятор для подбора типоразмера шин
<!doctype html> <html ng-app> <head> <meta charset="utf-8"> <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet"> <script src="http://code.angularjs.org/1.1.5/angular.min.js"></script> <script language="javascript" type="text/javascript"> function TireController($scope) { //набор 1 var IVALUE = 25.4; var I2VALUE = 0.02; $scope.sectionWidthSet1 = 0; $scope.aspectRatioSet1 = 0; $scope.rimDiameter_Inch_Set1 = 0; //набор 2 $scope.sectionWidthSet2 = 0; $scope.aspectRatioSet2 = 0; $scope.rimDiameter_Inch_Set2 = 0; //расчетные данные $scope.rimHeight_mm_Set1; $scope.innDiameterSet1; $scope.extDiameterSet1; $scope.rimHeight_mm_Set2; $scope.innDiameterSet2; $scope.extDiameterSet2; $scope.roadClearance; $scope.computing=function(){ // Внутренний диаметр, мм $scope.innDiameterSet1 = Math.round($scope.rimDiameter_Inch_Set1 * IVALUE); $scope.innDiameterSet2 = Math.round($scope.rimDiameter_Inch_Set2 * IVALUE); // Внешний диаметр, мм $scope.extDiameterSet1 = Math.round($scope.sectionWidthSet1 * $scope.aspectRatioSet1 * I2VALUE + $scope.innDiameterSet1); $scope.extDiameterSet2 = Math.round($scope.sectionWidthSet2 * $scope.aspectRatioSet2 * I2VALUE + $scope.innDiameterSet2); //Высота профиля, мм $scope.rimHeight_mm_Set1 = Math.round(($scope.extDiameterSet1 - $scope.innDiameterSet1)/2); $scope.rimHeight_mm_Set2 = Math.round(($scope.extDiameterSet2 - $scope.innDiameterSet2)/2); //Изменение значения клиренса $scope.roadClearance = ( $scope.extDiameterSet2 - $scope.extDiameterSet1 )/2; } //do calculation $scope.computing(); } </script> </head> <body> <div ng-controller="TireController"> <div class="container"> <div class="row"> <div class="panel panel-default"> <div class="panel-body"> <div class="col-md-5 col-md-offset-1"> <b>Старый размер</b>: <select class="form-control" ng-model="sectionWidthSet1" ng-change="computing()"> <option value="145">145</option> <option value="155">155</option> <option value="165">165</option> <option selected="selected" value="175">175</option> <option value="185">185</option> <option value="195">195</option> <option value="205">205</option> <option value="215">215</option> <option value="225">225</option> <option value="235">235</option> <option value="245">245</option> <option value="255">255</option> <option value="265">265</option> <option value="275">275</option> <option value="285">285</option> <option value="295">295</option> <option value="305">305</option> <option value="315">315</option> <option value="325">325</option> </select> / <select class="form-control" ng-model="aspectRatioSet1" ng-change="computing()"> <option value="0">—</option> <option value="25">25</option> <option value="30">30</option> <option value="35">35</option> <option value="40">40</option> <option value="45">45</option> <option value="50">50</option> <option value="55">55</option> <option value="60">60</option> <option value="65">65</option> <option selected="selected" value="70">70</option> <option value="75">75</option> <option value="80">80</option> <option value="85">85</option> </select> R <select class="form-control" ng-model="rimDiameter_Inch_Set1" ng-change="computing()"> <option value="12">12</option> <option selected="selected" value="13">13</option> <option value="14">14</option> <option value="15">15</option> <option value="16">16</option> <option value="17">17</option> <option value="18">18</option> <option value="19">19</option> <option value="20">20</option> <option value="21">21</option> <option value="22">22</option> <option value="23">23</option> <option value="24">24</option> </select> <br> </div> <div class="col-md-5"> <b>Новый размер</b>: <select class="form-control" ng-model="sectionWidthSet2" ng-change="computing()"> <option value="145">145</option> <option value="155">155</option> <option value="165">165</option> <option selected="selected" value="175">175</option> <option value="185">185</option> <option value="195">195</option> <option value="205">205</option> <option value="215">215</option> <option value="225">225</option> <option value="235">235</option> <option value="245">245</option> <option value="255">255</option> <option value="265">265</option> <option value="275">275</option> <option value="285">285</option> <option value="295">295</option> <option value="305">305</option> <option value="315">315</option> <option value="325">325</option> </select> / <select class="form-control" ng-model="aspectRatioSet2" ng-change="computing()"> <option value="0">—</option> <option value="25">25</option> <option value="30">30</option> <option value="35">35</option> <option value="40">40</option> <option value="45">45</option> <option value="50">50</option> <option value="55">55</option> <option value="60">60</option> <option value="65">65</option> <option selected="selected" value="70">70</option> <option value="75">75</option> <option value="80">80</option> <option value="85">85</option> </select> R <select class="form-control" ng-model="rimDiameter_Inch_Set2" ng-change="computing()"> <option value="12">12</option> <option selected="selected" value="13">13</option> <option value="14">14</option> <option value="15">15</option> <option value="16">16</option> <option value="17">17</option> <option value="18">18</option> <option value="19">19</option> <option value="20">20</option> <option value="21">21</option> <option value="22">22</option> <option value="23">23</option> <option value="24">24</option> </select> </div> </div> </div> </div> |
часть 2 калькулятора - почему то ограничение на 10000 символов в посте. <div class="row"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">Расчетные данные</h3> </div> <div class="panel-body"> <div class="col-md-12 clearfix"> <p> Клиренс изменится на: <span class="badge badge-info">{{ roadClearance }}</span> </p> </div> <div class="col-md-12 center-block"> <table class="table table-hover table-bordered"> <thead> <tr> <th> Размер </th> <th> Старый вариант </th> <th> Новый вариант </th> <th> Разница </th> </tr> </thead> <tbody> <tr> <td> Ширина шины, мм (A) </td> <td> {{ sectionWidthSet1 }} </td> <td> {{ sectionWidthSet2 }} </td> <td> {{ sectionWidthSet1 - sectionWidthSet2 }} </td> </tr> <tr> <td> Высота профиля, мм (B) </td> <td> {{ rimHeight_mm_Set1 }} </td> <td> {{ rimHeight_mm_Set2 }} </td> <td> {{ rimHeight_mm_Set1 - rimHeight_mm_Set2 }} </td> </tr> <tr> <td> Внутренний диаметр, мм (C) </td> <td> {{ innDiameterSet1 }} </td> <td> {{ innDiameterSet2 }} </td> <td> {{ innDiameterSet1 - innDiameterSet2 }} </td> </tr> <tr> <td> Внешний диаметр, мм (D) </td> <td> {{ extDiameterSet1 }} </td> <td> {{ extDiameterSet2 }} </td> <td> {{ extDiameterSet1 - extDiameterSet2 }} </td> </tr> </tbody> </table> </div> </div> </div> </div> </div> </div> </body> </html> |
Нужно было сделать такую "анимацию": кликаем, стили применяются сразу. Кликаем ещё раз, стили пропадают через время. То бишь, эдакий addClass через таймаут, но без JS-императива.
Всё проклял, пока не понял простую вещь - для определения параметров анимации ангуляр читает стили. нужно читать доки :) в общем, вот пример : элемент станет красным мгновенно, а синим- через время (одну секунду) <html><head> <style>.test { color: #00f; font-size: 48px; -webkit-transition-property: color, font-size; transition-property: color, font-size; -webkit-transition-duration: 1s; transition-duration: 1s; -webkit-transition-timing-function: steps(1); transition-timing-function: steps(1); } .hidden-add { -webkit-transition-duration: 0s; transition-duration: 0s; } .hidden { color: #f00; font-size: 36px; }</style> <style type="text/css"></style></head> <body> <div ng-app="app" ng-init="hidden = true" class="ng-scope"> <button ng-click="hidden = !hidden">Toggle</button> <div ng-class="{hidden: hidden}" class="test-animation test hidden">myEl</div> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script><script src="https://code.angularjs.org/1.2.16/angular-animate.min.js"></script> <script> var app = angular.module('app', ['ngAnimate']); </script> </body></html> Тут зарыт трюк, поэтому его поясню. Зарыт он в стилях. Префиксы уберу за простотой. /* Начальные стили - цвет и размер шрифта */ .test { color: #00f; font-size: 48px; } /* конечные стили - другие цвет и размер шрифта */ .hidden { color: #f00; font-size: 36px; } /* Параметры анимации */ .test { transition-property: color, font-size; /* Анимируем изменение свойств цвет и размер шрифта */ transition-duration: 1s; /* длительность прописана чисто для ангуляра */ transition-timing-function: steps(1); /* смягчение не нужно - нужно, чтобы стили ставились мгновенно. так что сюда подходит лестничная функция с одной ступенькой с конца */ } /* Анимация добавления класса */ .hidden-add { transition-duration: 0s; /* снимаем время анимации, получаем мгновенное применение стилей */ } |
Цитата:
|
|
kazemir,
что это за ад?) |
Цитата:
|
Цитата:
- direction-links - previous-text - next-text - boundary-links - first-text - last-text которые, по сути, задают отображение в шаблоне. У меня их просто нет, только сервис. Т.е. шаблон настраивается произвольно, как угодно. Иными словами, можно легко сделать враппер-директиву с нужной разметкой и использовать. Или, как у меня в примере, использовать контроллер с подгружаемыми шаблонами, Или вообще не подгружать шаблоны, а писать его прямо в разметку :) Возможность задавать общие опции для всех экземпляров пагинатора (конфигурировать) Поскольку, сервис - функция, можно расширить ее прототип и доп. методы/свойства будут у всех созданных ею экземпляров. |
Часовой пояс GMT +3, время: 07:40. |