2015-08-25 4 views
0

фона

Я пытаюсь построить AngularJS директивы с 2 путем, связанной изолят областью видимости собственностью. Эта директива должна мутировать данные в массив, чтобы иметь возможность правильно отображать его с помощью ng-repeat. Я знаю, что бесконечный цикл дайджеста произойдет, когда вы вернете новый массив из функции get, потому что это новый массив, и AngularJS будет продолжать рассматривать модель неустойчивой и продолжать переваривать.AngularJS директивы мутировать изолят данные областей

Эта проблема может быть решена путем использования функции «get» для возврата нового массива ... но это не вариант для меня, потому что мне нужно, чтобы измененный массив изменялся всякий раз, когда изменяется исходный массив. Это функция, предоставляемая областью выделения, и я бы не хотел использовать $scope.$watch(), потому что это потребовало бы, чтобы я ввел $scope, из чего я пытаюсь избавиться, используя синтаксис bindToController: true.

Вопрос

Так что мой вопрос, учитывая фон выше: Что такое правильный способ мутирует изолят данные областей внутри AngularJS директивы?

Код

в Jsfiddle: link (обратите внимание на бесконечную переваривать ошибку цикла, когда вы открываете консоль инструментов разработчика)

HTML:

<div ng-app="IsolateScopeExample" ng-controller="MainController as vm"> 
    <h4>Original data</h4> 
    {{vm.dataToMutate}} 
    <h4>Mutated data</h4> 
    <div mutator data="vm.dataToMutate"></div> 
</div> 

Javascript (AngularJS версия: 1.3.14) :

angular.module('IsolateScopeExample', []) 
    .controller('MainController', function(){ 
     this.dataToMutate = [{a: 1},{a: 2},{a: 3}]; 
    }) 
    .directive('mutator', function(){ 
     return { 
      scope: { 
       data: '=', 
      }, 
      template: '<span ng-repeat="item in mvm.mutateData()">{{item}}</span>', 
      bindToController: true, 
      controller: function(){ 
       this.mutateData = function(){ 
        console.log('Mutating'); 
        var newData = []; 
        this.data.forEach(function(d){newData.push({b: d.a + 1});}); 
        return newData; 
       }; 
      }, 
      controllerAs: 'mvm' 
     }; 
    }); 

ответ

0

Не совсем уверен, почему это работает, но именно так я обычно пишу Angular с директивами. Разница, которую я вижу, заключается в том, что я использую $scope. Я передаю директиву dataToMutate. В директиве link я изменяю dataToMutate. Так как это один и тот же объект в контроллере, шаблон обновляется соответствующим образом. https://jsfiddle.net/b7ekv4tm/2/

HTML

<div ng-app="IsolateScopeExample" ng-controller="MainController"> 
    <h4>Original data</h4> 
    {{dataToMutate}} 
    <h4>Mutated data</h4> 
    <div mutator data="dataToMutate"></div> 
</div> 

JS

angular.module('IsolateScopeExample', []) 
    .controller('MainController', ['$scope', function ($scope) { 
    $scope.dataToMutate = [{ 
     a: 1 
    }, { 
     a: 2 
    }, { 
     a: 3 
    }]; 
}]) 
    .directive('mutator', function() { 
    return { 
     scope: { 
      data: '=', 
     }, 
     template: '<span ng-repeat="item in data">{{item}}</span>', 
     link: function ($scope) { 
      var data = $scope.data.map(function (d) { 
       return { 
        b: d.a + 1 
       }; 
      }); 
      $scope.data = $scope.data.concat(data); 
     } 
    }; 
}); 
+0

Он не нужен или даже нежелательным, что директива мутирует исходную ссылку на данные. Просто нужно изменить данные для своей собственной области (например, создав новый массив), но оставить исходный массив таким, какой он есть. –

+0

@YanikCeulemans О, так что это похоже на вычислительную собственность. Вы можете посмотреть исходный массив, а затем создать другой массив в области директивы, содержащий пересчитанные данные. Затем запустите шаблон директивы. Вот пример: https://jsfiddle.net/b7ekv4tm/3/ Не совсем уверен, почему вы избегаете смотреть. – Joseph

+1

Да, это точно как вычисленное свойство. Причина, по которой я пытаюсь избежать использования '$ scope', заключается в том, что я пытаюсь использовать синтаксис bindToController для AngularJS 1.3+ (который предотвращает общие проблемы деконфигурации данных с родительскими иерархиями' $ scope', как объясняется в статье, связанной Xeon в другом ответе). Этот новый синтаксис должен позаботиться о том, чтобы автоматически обновлять атрибуты директивы, связанные с двумя способами, на свой контроллер. Необходимость использовать '$ scope' для просмотра всех свойств с двумя способами связана с громоздкой, когда мы имеем дело не только с одним свойством. –

0

@Joseph the Dreamer ответ правильный, но если вы действительно хотите избавиться от $ объема и использовать bindToController (кстати. great article about this here) вы» Мне нужно повторно использовать ссылку на тот же массив.

На самом деле это именно то, что говорят документы. Страница, где ссылка на ошибку указывает на:

Общей ошибкой является привязка к функции, которая генерирует новый массив каждый раз, когда он вызывается. Например:

<div ng-repeat="user in getUsers()">{{ user.name }}</div> 

С getUsers() возвращает новый массив , Угловое определяет, что модель отличается от каждого $ переваривать цикла, что приводит к ошибке.Решение состоит в том, чтобы вернуть тот же массив объект, если элементы не изменились:

var users = [ { name: 'Hank' }, { name: 'Francisco' } ]; 

$scope.getUsers = function() { 
    return users; 
}; 

Так что ваш soulution будет что-то вроде этого:

controller: function(){ 
      var mutated = []; 
      this.mutateData = function(){ 
       console.log('Mutating'); 
       var newData = []; 
       this.data.forEach(function(d){newData.push({b: d.a + 1});}); 
       mutated.length = 0; 
       mutated.push.apply(newData, mutated); 
       return mutated; 
      }; 
     }, 
+0

Я понимаю, что использование одного и того же объекта массива, если элементы не изменились, решит мою проблему. Моя проблема заключается в том, чтобы определить, когда данные ** были изменены ** –