AngularJS: ng-repeat list não é atualizada quando um elemento do modelo é dividido a partir da matriz do modelo

Eu tenho dois controladores e compartilho dados entre eles com uma function app.factory.

O primeiro controlador adiciona um widget na matriz do modelo (pluginsDisplayed) quando um link é clicado. O widget é inserido na matriz e essa alteração é refletida na exibição (que usa ng-repeat para mostrar o conteúdo da matriz):

O widget é construído sobre três diretivas, k2plugin, remover e resize. A diretiva remove adiciona um intervalo ao modelo da diretiva k2plugin. Quando o span é clicado, o elemento direito na matriz compartilhada é excluído com Array.splice() . A matriz compartilhada é atualizada corretamente, mas a alteração não é refletida na exibição. No entanto, quando outro elemento é adicionado, após a remoção, a visualização é atualizada corretamente e o elemento excluído anteriormente não é mostrado.

O que estou errado? Você poderia me explicar por que isso não funciona? Existe uma maneira melhor de fazer o que estou tentando fazer com o AngularJS?

Este é o meu index.html:

         
Add one of {{pluginList.length}} plugins
  • {{plugin.name}}
  • Esta é minha main.js:

     var app = angular.module ("livePlugins",[]); app.factory('Data', function () { return {pluginsDisplayed: []}; }); app.controller ("pluginlistctrl", function ($scope, Data) { $scope.pluginList = [{name: "plugin1"}, {name:"plugin2"}, {name:"plugin3"}]; $scope.add = function () { console.log ("Called add on", this.plugin.name, this.pluginList); var newPlugin = {}; newPlugin.id = this.plugin.name + '_' + (new Date()).getTime(); newPlugin.name = this.plugin.name; Data.pluginsDisplayed.push (newPlugin); } }) app.controller ("k2ctrl", function ($scope, Data) { $scope.pluginsDisplayed = Data.pluginsDisplayed; $scope.remove = function (element) { console.log ("Called remove on ", this.pluginid, element); var len = $scope.pluginsDisplayed.length; var index = -1; // Find the element in the array for (var i = 0; i < len; i += 1) { if ($scope.pluginsDisplayed[i].id === this.pluginid) { index = i; break; } } // Remove the element if (index !== -1) { console.log ("removing the element from the array, index: ", index); $scope.pluginsDisplayed.splice(index,1); } } $scope.resize = function () { console.log ("Called resize on ", this.pluginid); } }) app.directive("k2plugin", function () { return { restrict: "A", scope: true, link: function (scope, elements, attrs) { console.log ("creating plugin"); // This won't work immediately. Attribute pluginname will be undefined // as soon as this is called. scope.pluginname = "Loading..."; scope.pluginid = attrs.pluginid; // Observe changes to interpolated attribute attrs.$observe('pluginname', function(value) { console.log('pluginname has changed value to ' + value); scope.pluginname = attrs.pluginname; }); // Observe changes to interpolated attribute attrs.$observe('pluginid', function(value) { console.log('pluginid has changed value to ' + value); scope.pluginid = attrs.pluginid; }); }, template: "
    {{pluginname}} _ X" + "
    Plugin DIV
    " + "
    ", replace: true }; }); app.directive("remove", function () { return function (scope, element, attrs) { element.bind ("mousedown", function () { scope.remove(element); }) }; }); app.directive("resize", function () { return function (scope, element, attrs) { element.bind ("mousedown", function () { scope.resize(element); }) }; });

    Sempre que você fizer alguma forma de operação fora do AngularJS, como fazer uma chamada Ajax com jQuery, ou ligar um evento a um elemento como o que você tem aqui, você precisa informar ao AngularJS para se atualizar. Aqui está a mudança de código que você precisa fazer:

     app.directive("remove", function () { return function (scope, element, attrs) { element.bind ("mousedown", function () { scope.remove(element); scope.$apply(); }) }; }); app.directive("resize", function () { return function (scope, element, attrs) { element.bind ("mousedown", function () { scope.resize(element); scope.$apply(); }) }; }); 

    Aqui está a documentação: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply

    Se você adicionar um $scope.$apply(); logo após $scope.pluginsDisplayed.splice(index,1); então funciona.

    Não sei por que isso está acontecendo, mas, basicamente, quando o AngularJS não sabe que o $ scope foi alterado, ele precisa chamar $ apply manualmente. Eu também sou novo no AngularJS, então não posso explicar isso melhor. Eu preciso também olhar mais para isso.

    Eu encontrei este artigo incrível que explica isso corretamente. Nota: Eu acho que pode ser melhor usar ng-click (docs) ao invés de vincular a “mousedown”. Eu escrevi um aplicativo simples aqui ( http://avinash.me/losh , fonte http://github.com/hardfire/losh ) baseado no AngularJS. Não é muito limpo, mas pode ser útil.

    Eu tive o mesmo problema. O problema foi porque ‘ng-controller’ foi definido duas vezes (no roteamento e também no HTML).

    Existe uma maneira fácil de fazer isso. Muito fácil. Desde que notei que

     $scope.yourModel = []; 

    remove toda a lista de array $ scope.yourModel que você pode fazer assim

     function deleteAnObjectByKey(objects, key) { var clonedObjects = Object.assign({}, objects); for (var x in clonedObjects) if (clonedObjects.hasOwnProperty(x)) if (clonedObjects[x].id == key) delete clonedObjects[x]; $scope.yourModel = clonedObjects; } 

    O $ scope.yourModel será atualizado com os clonedObjects.

    Espero que ajude.

    Remove “track by index” da repetição ng e atualiza o DOM