对AngularJS资源保存动作的承诺

Promise on AngularJS resource save action

本文关键字:承诺 保存 AngularJS 资源      更新时间:2023-09-26

我目前正在做一个REST + AngularJS应用。

关于节约资源的承诺,我有一个小问题。

我的工厂:

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;
});

我的控制器:

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");
        });
    }
}); 

现在的问题是,我得到以下异常:

TypeError: Cannot call method '$then' of undefined

奇怪的是,如果我添加相同的回调到一个查找器(例如findById),一切工作正常。但是"return course.$save()"的返回值是undefined,而"return course.get({courseId:id});"的返回值是"Object Object "

我想要的是在保存操作完全执行时设置FlashMessage,而不是在此之前。

对此有什么想法吗?来自我的REST服务的响应是正确的。它返回保存的对象。

问候Marc

有两种稍有不同的API,一种用于处理资源实例,另一种——没有更好的词——更通用的版本。主要区别在于使用$前缀方法(get vs $get)

ngResource/resource.js中$前缀的方法。代理调用并直接返回承诺。

在资源实例化之前,您只能使用正常的get访问资源。

var promise = Resource.get().$promise;
promise.then(function(res)  { console.log("success: ", res); });
promise.catch(function(res) { console.log("error: ", res); });

对于实例化的资源,$前缀的方法是可用的:

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") });

如果你看一下angular的资源文档,它会提到

重要的是要意识到调用$resource对象方法立即返回一个空引用(对象或数组)isArray)。一旦数据从服务器返回,现有的引用用实际数据填充。

这很可能意味着你对$save的调用将返回空引用。此外,在Angular 1.2之前,then在资源api中是不可用的,因为资源不是基于promise的。

您应该更改您的saveCourse方法调用,以接受一个函数参数以获得成功,并在那里执行必要的操作。

这是针对Angularjs 1.0.8的

在我的服务中有以下几点:

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;
      }
    };
}]);

In my controller:

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

我在控制器中添加了一个方法,使资源在执行CRUD操作时拥有一个承诺。

方法如下:

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

调用示例如下:

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

这是一个延迟响应,但你可以在$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");
});