AngularJS - comment forcer un champ d'application pour la mise à jour (promesse pour l'élément de tableau)
J'ai créé un contrôleur Angulaire qui ressemble à ceci (édité par souci de concision):
function AppCtrl($scope, $http, $location, $dataService) {
$scope.projects = $dataService.data.projects;
}
Qui correctement les charges de la $scope.projects
promesse de mon $dataService
service.
app.service('$dataService', function($q, $http, $location, $rootScope) {
var dataService = this; //Provides access 'this' inside functions below
var projectsDeferred = $q.defer();
$http.get('/api').success(function(data, status, headers, config) {
projectsDeferred.resolve(data.projects);
}).error(function(err) {
projectsDeferred.reject(err);
});
this.data = {projects: projectsDeferred.promise};
//UPDATE FUNCTION
function updateObjectInArray(array, object, newData) {
for(i in array) {
if(array[i] == object) {
if(newData != undefined) {
array[i] = newData;
} else {
return array[i];
}
}
}
return undefined;
}
this.updateProject = function(project, updateData) {
$http.put('/api/projects/' + project._id, updateData)
.success(function(data, status, headers, config) {
updateObjectInArray(dataService.data.projects.$$v, project, data);
}).error(function(data, status, headers, config) {});
};
});
J'ai créé un autre contrôleur qui ressemble à ceci, qui sélectionne un seul projet à partir de la matrice des projets sur la base de l'URL actuelle:
function ProjectCtrl($scope, $route) {
//Getting the current project from the array of projects
$scope.project = $scope.projects.then(function(projects) {
for(i in projects) {
if(projects[i]._id == $route.current.params.projectId) {
return projects[i];
}
}
});
}
Lorsque j'essaie de lancer mon updateObjectInArray()
fonction (sur le succès de mon $http.put()
demande), mon $scope.projects
dans AppCtrl
est correctement mis à jour (l'éventail de projets) mais mon $scope.project
dans ProjectCtrl
est pas mis à jour. Je peux me connecter array[i]
à l'intérieur de la updateObjectInArray()
fonction et il va enregistrer exactement ce que j'attends, et je peux me connecter $scope.projects
dans AppCtrl
et il mettra à jour en conséquence, mais quand j'essaie de me connecter $scope.project
dans mon ProjectCtrl
contrôleur, il n'est pas mis à jour en conséquence.
Je pensais que la raison était parce que je venais de faire appel $rootScope.$apply()
ou $rootScope.$digest()
après j'ai mis à jour le array[i]
objet dans updateObjectInArray()
, cependant, je reçois le message d'erreur que $digest is already in progress
.
Que dois-je faire pour que mon $scope.project
élément d'un tableau est mis à jour dans mon ProjectCtrl
? Ai-je besoin pour résoudre une nouvelle promesse pour elle?
Non, je veux l'appeler après la résolution de
$dataService.data.projects
. La fonction première est qu'il tire de données à partir du serveur lorsque la page se charge tout d'abord, et un utilisateur peut effectuer une action qui va envoyer la mise à jour du serveur, et en cas de succès, la mise à jour de la portée avec les nouvelles données retournées par le serveur.Je voulais dire après 🙂 Trop tôt encore.
Je l'appelle dans mon contrôleur lorsque l'utilisateur clique sur un bouton. Oui, je suis positif, il a déjà résolu. Comme je l'ai dit, je peux me connecter
array[i]
après la mise à jour de l'objet et il a été mis à jour exactement comme je l'attend, mais la journalisation de mon champ d'action montre qu'il n'a pas été mis à jour à ce $dataService.projects
désormais d'égal à égal.(Je voulais le type
$dataService.data.projects
)OriginalL'auteur Matt Reyer | 2013-01-14
Vous devez vous connecter pour publier un commentaire.
Dès que le
projects
sont chargés, vous êtes à l'aide de l'un des éléments de la matrice deprojects[i]
, nous allons théoriquement supposons qu'elle est l'objet0x1
dans la mémoire. Le problème est que lorsqu'un nouvel élément est chargé (supposons0x2
), et de mettre à jour le tableau, vous êtes à la modification de l'objet qui se trouve dans la position de tableau (le0x1
), mais$scope.project
fait toujours référence à la désormais abandonné objet0x1
. Vous ne pouvez pas les modifier dans le tableau, vous devez le modifier, de sorte que vous n'avez pas besoin de relier la$scope.project
variable.La meilleure solution est de changement
array[i] = newData
àangular.extend(array[i], newData)
. De cette façon, vous allez juste de modifier toutes les propriétés de tableau[i], et que votre$scope.project
points pour le même objet en mémoire, il sera mis à jour.De toute façon, je crois aussi que vous pouvez changement
if(array[i] == object) {
àif(array[i]._id === object._id) {
et votre de comparaison d'égalité (==
) à strictement l'égalité des comparaisons (===
). Cetteif
convient le mieux à votre cause, comme le nouvel objet créé n'est pas le même que l'ancien.angular.extend()
avant, mais il fonctionne très bien. Est-ce plus efficace que d'appeler$scope.watch('projects', ...
parce que l'appel de$watch
signifie que angulaire a faire plus de travail? Très bonne suggestion sur l'égalité stricte, je vais être en utilisant.C'est probablement le meilleur pour les performances, parce que vous ne fusionner les objets du moment où il change. Chaque inscrit
$watch
s'exécute sur tous portée digérer cycle. Vous devez payer attention à l'endroit où vous l'utilisez, en particulier lorsque vous avez besoin d'un récursif$watch
, que serait votre cas.angular.extends
est bien fondée surjQuery.extend
. À tout moment.Mec tu ne peux pas croire que le bien que vous avez fait. J'avais tout mélangé dans ma tête avec la liaison et l'extension de variables. Merci beaucoup pour cette et de clarifier ma situation. Millions de grâce.
Le problème me semble, logements anciens ne sera pas effacé si le nouvel objet n'est pas la valeur à remplacer?
OriginalL'auteur Caio Cunha
Êtes-vous à l'aide de la
$scope.projects
dans une liaison? Ou quelque part d'autre dans le code?Demander, car vous êtes de retour, et une promesse est jamais modifiée par conséquent, bien que vous pouvez lier des promesses directement à la page HTML attend son contenu. Cela se produit parce que, en interne, Angulaire semble regarder pour la suite.
Donc, si vous êtes à l'aide de cette variable quelque part d'autre, alors vous devez utiliser
$q.quand($champ d'application.les projets)
. Vous obtiendrez une nouvelle promesse qui sera résolu instantanément si elle a déjà été résolu.AppCtrl
, le$scope.projects
est toujours mis à jour correctement sans aucun travail supplémentaire. Mais, quand j'essaie de tirer un seul élément de ce tableau (enProjectCtrl
, il n'est pas mis à jour. Oui, en passant, je suis le lie à l'HTML et il fonctionne très bien lorsque je passe l'ensemble du tableau. Je vous remercie beaucoup pour votre aide, vous êtes génial.Voir ma réponse ci-dessous. J'ai créé un nouveau car il était trop grand pour le commentaire.
OriginalL'auteur Caio Cunha