example - AngularJS: ng-repeat list no se actualiza cuando un elemento de modelo se empalma de la matriz de modelo
ng-repeat select (4)
Tengo dos controladores y comparto datos entre ellos con una función app.factory.
El primer controlador agrega un widget en la matriz modelo (pluginsDisplayed) cuando se hace clic en un enlace. El widget se inserta en la matriz y este cambio se refleja en la vista (que usa ng-repeat para mostrar el contenido de la matriz):
<div ng-repeat="pluginD in pluginsDisplayed">
<div k2plugin pluginname="{{pluginD.name}}" pluginid="{{pluginD.id}}"></div>
</div>
El widget se basa en tres directivas, k2plugin, eliminar y cambiar el tamaño. La directiva remove agrega un tramo a la plantilla de la directiva k2plugin. Cuando se hace clic en dicho intervalo, el elemento correcto en el conjunto compartido se elimina con Array.splice()
. La matriz compartida se actualiza correctamente, pero el cambio no se refleja en la vista. Sin embargo, cuando se agrega otro elemento, después de la eliminación, la vista se actualiza correctamente y no se muestra el elemento eliminado previamente.
¿Qué me estoy equivocando? ¿Podrías explicarme por qué esto no funciona? ¿Hay una mejor manera de hacer lo que estoy tratando de hacer con AngularJS?
Este es mi index.html:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js">
</script>
<script src="main.js"></script>
</head>
<body>
<div ng-app="livePlugins">
<div ng-controller="pluginlistctrl">
<span>Add one of {{pluginList.length}} plugins</span>
<li ng-repeat="plugin in pluginList">
<span><a href="" ng-click="add()">{{plugin.name}}</a></span>
</li>
</div>
<div ng-controller="k2ctrl">
<div ng-repeat="pluginD in pluginsDisplayed">
<div k2plugin pluginname="{{pluginD.name}}" pluginid="{{pluginD.id}}"></div>
</div>
</div>
</div>
</body>
</html>
Este es mi 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: "<div>{{pluginname}} <span resize>_</span> <span remove>X</span>" +
"<div>Plugin DIV</div>" +
"</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);
})
};
});
Cada vez que realice alguna operación fuera de AngularJS, como realizar una llamada Ajax con jQuery, o vincular un evento a un elemento como el que tiene aquí, debe informar a AngularJS para que se actualice solo. Aquí está el cambio de código que debe hacer:
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();
})
};
});
Aquí está la documentación: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply
Hay una manera fácil de hacer eso. Muy fácil. Desde que noté eso
$scope.yourModel = [];
elimina toda la lista de arreglos de $ scope.yourModel que puede hacer de esta manera
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;
}
El $ scope.yourModel se actualizará con clonedObjects.
Espero que ayude.
Si agrega un $scope.$apply();
justo después de $scope.pluginsDisplayed.splice(index,1);
entonces funciona
No estoy seguro de por qué sucede esto, pero básicamente cuando AngularJS no sabe que el $ scope ha cambiado, se requiere llamar $ apply manualmente. También soy nuevo en AngularJS así que no puedo explicar esto mejor. También necesito mirar más adentro.
Encontré este asombroso artículo que lo explica bastante bien. Nota: Creo que sería mejor usar ng-click (docs) lugar de vincularse a "mousedown". Escribí una aplicación simple aquí ( http://avinash.me/losh , fuente http://github.com/hardfire/losh ) basada en AngularJS. No está muy limpio, pero podría ser de ayuda.
Tuve el mismo problema. El problema era porque ''ng-controller'' se definió dos veces (en el enrutamiento y también en el HTML).