web-dev-qa-db-fra.com

Promise on AngularJS action de sauvegarde des ressources

Je travaille actuellement sur une application REST + AngularJS.

J'ai un petit problème concernant les promesses relatives à la sauvegarde des ressources.

Mon usine:

App.factory('Course', function($resource) {
    var course = $resource('/AppServer/admin/courses/:courseId', {}, {});

    course.findAll = function() {
        return course.query();
    };

    course.findById = function(id) {
        return course.get({
            courseId : id
        });

    };

    course.saveCourse = function(course) {
        return course.$save();
    }

    return course;
});

Mon contrôleur:

App.controller('CourseEditController', function($scope, $routeParams, $location, Course, FlashMessage) {
    // load course into edit form
    $scope.course = Course.findById($routeParams.courseId);

    // save edited course and print flash message
    $scope.saveCourse = function() {
        var savedCourse = Course.saveCourse($scope.course);

        savedCourse.$then(function(httpResponse) {
            FlashMessage.set("Die Änderungen am Kurs <i>" + savedCourse.title + "</i> wurden erfolgreich gespeichert.");
            $location.path("/kurse/verwalten");
        });
    }
}); 

Maintenant, le problème est que je reçois l'exception suivante:

TypeError: Cannot call method '$then' of undefined

La chose étrange est que si j'ajoute le même rappel à l'un des détecteurs (par exemple, findById), tout fonctionne correctement. Mais la valeur de retour de "return course. $ Save ()" n'est pas définie, comparée à la valeur de retour de "return course.get ({courseId: id});" qui est "objet objet".

Ce que je veux, c'est définir FlashMessage lorsque l'action de sauvegarde a été entièrement exécutée et pas avant.

Des idées à ce sujet? La réponse de mon service REST est correcte. Il retourne l'objet enregistré.

Greets Marc

19
mooonli

Il y a deux API légèrement différentes, une pour travailler avec une instance de ressource et - en l'absence de mots meilleurs - une version plus générique. La principale différence entre l'utilisation de méthodes préfixées par $- (get et $get)

Méthodes préfixées par $- dans ngResource/resource.js . Procure l'appel et renvoie la promesse directement.

Comme je le sache avant que la ressource ne soit instanciée, vous ne pouvez accéder aux ressources avec la variable get normale. 

var promise = Resource.get().$promise;

promise.then(function(res)  { console.log("success: ", res); });
promise.catch(function(res) { console.log("error: ", res); });

Avec ressource instanciée, les méthodes préfixées par $- sont disponibles:

var res = new Resource({foo: "bar"});

res.$save()
    .then(function(res)  { console.log("authenticated") })
    .catch(function(req) { console.log("error saving obj"); })
    .finally(function()  { console.log("always called") });
42
lafa

Si vous regardez la documentation angulaire sur ressource elle mentionne

Il est important de réaliser que l'invocation d'une méthode d'objet $ resource renvoie immédiatement une référence vide (objet ou tableau dépendant de isArray). Une fois que les données sont renvoyées du serveur, le fichier .__ existant. la référence est remplie avec les données réelles.

Cela peut très bien signifier que votre appel à $ save renverrait une référence vide. De plus, then n'est pas disponible sur api de ressources avant le Angular 1.2, car les ressources ne sont pas basées sur promise.

Vous devez modifier votre appel à la méthode saveCourse pour accepter un paramètre de fonction et y effectuer les actions nécessaires.

3
Chandermani

Ceci est pour Angularjs 1.0.8

J'ai à mon service:

angular.module('dataProvider', []).
  factory('dataProvider', ['$resource','$q',function($resource,$q) { 
//....
var Student = $resource('/app/student/:studentid',
    {studentid:'@id'}
);
    return {
      newStudent:function(student){
        var deferred = $q.defer();
        var s = new Student({name:student.name,age:parseInt(student.age)});
        s.$save(null,function(student){
            deferred.resolve(student);
        });
        return deferred.promise;
      }
    };
}]);

Dans mon contrôleur:

$scope.createStudent=function(){
  dataProvider.newStudent($scope.newStudent).then(
    function(data){
      $scope.students.Push(data);
  });
};
1
HMR

Ceci est une réponse tardive, mais vous pouvez avoir un rappel sur $ save ... 

var savedCourse = Course.saveCourse($scope.course);

savedCourse.$save(function(savedCourse, putResponseHeaders) {
    FlashMessage.set("Die Änderungen am Kurs <i>" + savedCourse.title + "</i> wurden erfolgreich gespeichert.");
    $location.path("/kurse/verwalten");
});
0
Samuel

J'ai ajouté une méthode dans le contrôleur pour permettre à une ressource d'avoir une promesse lorsqu'elle exécute une opération CRUD.

La méthode est la suivante:

function doCrudOpWithPromise(resourceInstance, crudOpName){
            var def=$q.defer()
            resourceInstance['$'+crudOpName](function(res){def.resolve(res)}, function(err){def.reject(err)})
            return def.promise
}

Un exemple d'invocation est:

var t=new MyResource()
doCrudOpWithPromise(t,'save').then(...)
0
Giovanni Bitliner