30.05.2013, 19:25
|
Профессор
|
|
Регистрация: 04.02.2011
Сообщений: 1,815
|
|
Антипаттерн или способ убить 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>
__________________
Лучше калымить в гандурасе чем гандурасить на колыме
Последний раз редактировалось DjDiablo, 30.05.2013 в 21:16.
|
|
30.05.2013, 20:03
|
Профессор
|
|
Регистрация: 04.02.2011
Сообщений: 1,815
|
|
Ещё один опыт интересный
Я задался вопорсом в каком порядке срабатывают 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>
__________________
Лучше калымить в гандурасе чем гандурасить на колыме
Последний раз редактировалось DjDiablo, 30.05.2013 в 21:19.
|
|
30.05.2013, 20:36
|
Профессор
|
|
Регистрация: 04.02.2011
Сообщений: 1,815
|
|
Следуюший вопрос это порядок срабатывания 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>
__________________
Лучше калымить в гандурасе чем гандурасить на колыме
Последний раз редактировалось DjDiablo, 30.05.2013 в 21:42.
|
|
30.05.2013, 22:07
|
Профессор
|
|
Регистрация: 04.02.2011
Сообщений: 1,815
|
|
В 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, 30.05.2013 в 23:36.
|
|
31.05.2013, 18:24
|
Профессор
|
|
Регистрация: 04.10.2010
Сообщений: 571
|
|
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>
Последний раз редактировалось Shitbox2, 01.06.2013 в 02:53.
|
|
03.06.2013, 00:34
|
Профессор
|
|
Регистрация: 04.02.2011
Сообщений: 1,815
|
|
Небольшой опыт демонстрирующий порядок инициализации директив.
важно
если используешь 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>
__________________
Лучше калымить в гандурасе чем гандурасить на колыме
Последний раз редактировалось DjDiablo, 03.06.2013 в 00:59.
|
|
03.06.2013, 01:00
|
Профессор
|
|
Регистрация: 04.10.2010
Сообщений: 571
|
|
Всё так. Подобный пример видел здесь: http://jsfiddle.net/vojtajina/8yzbZ/
Кстати, разработчики планируют упростить АПИ директив, так что в будущем недопониманий будет меньше
|
|
25.06.2013, 20:28
|
Профессор
|
|
Регистрация: 04.10.2010
Сообщений: 571
|
|
Создание пустого экземпляра ресурса
Иногда требуется получить пустой ресурсный объект, не связанный с БД. Что отправляется на сервер можно посмотреть в консоли браузера
<!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>
|
|
19.07.2013, 01:30
|
|
junior
|
|
Регистрация: 29.11.2011
Сообщений: 3,924
|
|
Сообщение от Shitbox2
|
return {
link: function(scope, element, attrs) {
// Функция link отдает в качестве параметра элемент, помеченный нашим атрибутом.
// Оборачиваем этот элемент jQuery, и получаем из attrs значение атрибута.
// Функция scope.$eval() вычисляет переданное ей выражение. В нашем случае
// просто превращает строку в массив с параметрами плагина
$(element).toolbar(scope.$eval(attrs.toolbarTip));
}
|
немного некропостинга , $element === $()
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
|
|
23.07.2013, 04:28
|
Профессор
|
|
Регистрация: 04.10.2010
Сообщений: 571
|
|
Сообщение от nerv_
|
немного некропостинга , $element === $()
|
Да-да, всё верно, мой косяк)
|
|
|
|