2015-10-02 3 views
0

У меня есть следующий код в функции связи моей директивы:Наблюдение за изменением модели

link: function (scope, elem, attrs, ngModel) { 
     $(elem).datagrid({ 
      columns: [[ 
       { field: 'ck', checkbox: 'true' }, 
       { field: 'ProjectID', title: 'Project ID', width: '30%' }, 
       { field: 'Name', title: 'Name' } 
      ]]     
     }); 
     ngModel.$render = function (value) { 
      $(elem).datagrid('loadData', ngModel.$viewValue); 
     }; 
     scope.$watch('projectList', function (newValue, oldValue) { 
      $(elem).datagrid('loadData', ngModel.$viewValue); 
     }); 

    } 

Когда массив $ scope.projectList изначально назначены данные как слушатели обожженных. Где-то в моем контроллере (только для тестирования) я добавляю еще один элемент $ scope.projectList:

$scope.test = function() { 
    var project = $scope.projectList[0]; 
    $scope.projectList.push(project); 
} 

На данный момент ни один из слушателей fired.Can кто-то пожалуйста, объясните, почему это происходит?

Благодаря

ответ

1

Это происходит потому, что нормальная функция $ часы смотрит на равенство ссылок, так что если вы сделали что-то вроде этого:

var project = $scope.projectList[0]; 
$scope.newProjectList = []; 
$scope.newProjectList.push(project); 
$scope.projectList = $scope.newProjectList; 

Тогда это вызвало бы ваши часы, так как ссылка на объект в $ scope.projectList изменилось.

Если вы хотите ваш пример:

var project = $scope.projectList[0]; 
$scope.projectList.push(project); 

, чтобы вызвать часы, то вы должны либо сделать

scope.$watch('projectList', function (newValue, oldValue) { 
    $(elem).datagrid('loadData', ngModel.$viewValue); 
}, true); 

(Передача верно в качестве последнего аргумента $ часы вызывает $ смотреть на провести глубокое сравнение равенства, которое может быть медленным с большими объектами или большими списками)

OR

scope.$watchCollection('projectList', function (newValue, oldValue) { 
    $(elem).datagrid('loadData', ngModel.$viewValue); 
}); 

(Это похоже на обычные $ watch в плане равенства, но оно было сделано специально для списков. Таким образом, в дополнение к основной контрольной проверке, он также выполняет контрольную проверку каждого из элементов в коллекции или массиве, поэтому он будет запускаться из таких вещей, как .push и.pop)

Все они имеют свои преимущества, в зависимости от того, какие проверки вы ищете. Кроме того, помните, что $ watch возвращает функцию отмены регистрации, которую вы можете использовать, чтобы очистить ее, что вы обычно делаете внутри области. $ On ('$ destroy'. Если вы этого не сделаете, они просто останутся на некоторое время и может быть утечка, если у вас есть много.

Вот хороший article на все различия между 3 вкусами часов

2

$watch только проверка, если ссылка к projectList массива изменился, он не выполняет глубокий часы на коллекции. Когда вы назначаете массив переменной области видимости, вы изменяете эту ссылку, но впоследствии ее изменение оставляет неизменным. В вашем случае использование метода $watchCollection() представляется более подходящим.

Стоит отметить, однако, что $watchCollection проверяет, изменились ли ссылки на элемент коллекции, например. путем добавления/удаления/замены элемента. Он не проверяет, были ли эти элементы изменены.

Если вы хотите иметь глубокие часы в своей коллекции, отправьте true в качестве третьего параметра в $watch().

scope.$watch('projectList', function (newValue, oldValue) { 
    $(elem).datagrid('loadData', ngModel.$viewValue); 
}, true); // <--- note the objectEquality flag set to true 

Заметим, однако, что это может повлиять на производительность, если элементы в коллекции являются сложными и требуют больше времени, чтобы сравнить их.

Вы также можете проверить Angular docs для $ scope для получения дополнительной информации (прокрутите немного вниз по $watch() и $watchCollection() описаниям методов).

+0

Похоже меняется до $ watchCollection сделал это. большое спасибо за помощь! – Mark

+0

Я Я тоже это услышал. Я также обновил ответ с дополнительным объяснением того, что происходит за кулисами, и когда даже '$ watchCollection()' может быть недостаточно (в зависимости от того, какие изменения необходимо обнаружить). – plamut

+0

Еще одна вещь. Почему ngModel. $ Render не срабатывает ни n Я изменяю коллекцию? – Mark

Смежные вопросы