Tengo dos controladores y comparto datos entre ellos con una función app.factory.
El primer controlador agrega un widget en la matriz del 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, remove y resize. La directiva remove agrega un espacio a la plantilla de la directiva k2plugin. Cuando se hace clic en dicho intervalo, se elimina el elemento correcto en la matriz compartida 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 anteriormente.
¿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);
})
};
});
fuente
Si agrega un
$scope.$apply();
derecho después$scope.pluginsDisplayed.splice(index,1);
, funciona.No estoy seguro de por qué sucede esto, pero básicamente cuando AngularJS no sabe que el $ scope ha cambiado, requiere llamar a $ apply manualmente. También soy nuevo en AngularJS, así que no puedo explicar esto mejor. También necesito investigar más.
Encontré este artículo asombroso que lo explica bastante bien. Nota: Creo que sería mejor usar ng-click (docs) en lugar de enlazar 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.
fuente
Tuve el mismo problema. El problema fue porque 'ng-controller' se definió dos veces (en el enrutamiento y también en el HTML).
fuente
Elimine "track by index" de ng-repeat y actualizará el DOM
fuente
Hay una forma sencilla de hacerlo. Muy fácil. Desde que me di cuenta de que
elimina toda la lista de matrices $ scope.yourModel que puede hacer así
$ Scope.yourModel se actualizará con clonedObjects.
Espero que ayude.
fuente