如何使用工厂函数 return $http.post() 对象?
How to return $http.post() object with factory function?
当我尝试使用 Angular 从工厂函数 return 一个 $http.post() 对象时,它抛出了这个错误:
下面是我的代码:
AngularUtils.js
Fenrir.factory('AngularUtils', function ($http, $log, $window) {
var AngularUtils = {
save: function(url, obj, errors, not_show_error_toast) {
not_show_error_toast = typeof not_show_error_toast !== 'undefined' ? not_show_error_toast : false;
loaderShow();
if (angular.isDefined(obj.id)) {
return $http.put(url + obj.id + '/', obj).
then(function onSuccess(response) {
loaderHide();
angular.extend(obj, response);
errors = {};
}), function onError(response) {
loaderHide();
handleErrors(response, status, errors, not_show_error_toast);
};
} else {
return this.create(url, obj, errors, not_show_error_toast);
}
},
create: function(url, obj, errors, not_show_error_toast) {
not_show_error_toast = typeof not_show_error_toast !== 'undefined' ? not_show_error_toast : false;
return $http.post(url, obj).
then(function onSuccess(response) {
loaderHide();
angular.extend(obj, response);
errors = {};
}), function onError(response) {
loaderHide();
handleErrors(response, status, errors, not_show_error_toast);
};
},
}
return AngularUtils
})
Admin.js
var Fenrir = angular.module('Fenrir', []);
Fenrir.controller('AdminController', function ($scope, $http, AngularUtils) {
$scope.createScreen = function () {
AngularUtils.save('/admin/saveScreen', $scope.record, '', '').then(function (hubs) {
$scope.hubs = hubs;
console.log('In ctrl ' + $scope.hubs);
});
}
})
如何正确 return $http.post() 对象?
仔细查看错误信息:
TypeError: AngularUtils.save(...).then is not a function
这表示没有名为 then()
的函数是 return 从 AngularUtils.save(...)
编辑而来的。这表明 save()
函数确实执行了,但它没有像预期的那样 return promise。
所以你的工厂方法确实执行了,但因为你没有 return 承诺,我们只能推测执行最终导致了哪条路径。
更新:原脚本语法错误
在尝试为您证明我的解决方案时,我发现您的 $put().then()
响应处理程序存在语法问题,错误的地方有一个括号,onError
函数应该是then
函数的第二个参数,而不是在它之后。您的代码应如下所示:
return $http.put(url + obj.id + '/', obj).
then(function onSuccess(response) {
loaderHide();
angular.extend(obj, response);
errors = {};
}, function onError(response) {
loaderHide();
handleErrors(response, status, errors, not_show_error_toast);
});
微妙,但很重要,如果你没有严格编译,那么工厂函数根本就没有被正确编译,这可能会导致你的错误。
在 one 或 some 路径的工厂方法中 return async promise deferrals (futures) 然后是默认模式,虽然冗长,但 return 一个单一的延迟包裹了整个方法执行,然后对于每个响应路径,您可以选择通过 return 编辑的原始承诺来解决或拒绝响应函数。
可以使用不同的库和技术来执行此操作,see AngularJs and Promises with the $http Service by Rick Strahl 了解常见实现的演练。
save: function(url, obj, errors, not_show_error_toast) {
var defer = $.Deferred();
not_show_error_toast = typeof not_show_error_toast !== 'undefined' ? not_show_error_toast : false;
if (angular.isDefined(obj.id)) {
loaderShow(); // NOTE: let create manage the loader start if it needs to
$http.put(url + obj.id + '/', obj).
then(function onSuccess(response) {
loaderHide();
// HACK: because .then is used instead of .success, you probably want the response.data, please review this
angular.extend(obj, response.data);
defer.resolve(obj);
}, function onError(response) {
loaderHide();
handleErrors(response, status, errors, not_show_error_toast);
defer.reject(response);
});
} else {
// If create is a deferral, it should be safe to return it directly
return this.create(url, obj, errors, not_show_error_toast);
}
return defer.promise();
},
Note: Only call a start or show utility or state operation in the same scope that also calls the reciprocal end/hide/stop/close. The code can work if you do not follow this rule but it gets harder to maintain as your project evolves, for that reason I've moved the loaderShow();
call into the branch that we know will always call loaderHide()
. This functional scope can not make the assumption that the create()
function will eventually call loaderHide()
for us.
This is a common, but bad habbit we all need to grow out of ;)
当我尝试使用 Angular 从工厂函数 return 一个 $http.post() 对象时,它抛出了这个错误:
下面是我的代码:
AngularUtils.js
Fenrir.factory('AngularUtils', function ($http, $log, $window) {
var AngularUtils = {
save: function(url, obj, errors, not_show_error_toast) {
not_show_error_toast = typeof not_show_error_toast !== 'undefined' ? not_show_error_toast : false;
loaderShow();
if (angular.isDefined(obj.id)) {
return $http.put(url + obj.id + '/', obj).
then(function onSuccess(response) {
loaderHide();
angular.extend(obj, response);
errors = {};
}), function onError(response) {
loaderHide();
handleErrors(response, status, errors, not_show_error_toast);
};
} else {
return this.create(url, obj, errors, not_show_error_toast);
}
},
create: function(url, obj, errors, not_show_error_toast) {
not_show_error_toast = typeof not_show_error_toast !== 'undefined' ? not_show_error_toast : false;
return $http.post(url, obj).
then(function onSuccess(response) {
loaderHide();
angular.extend(obj, response);
errors = {};
}), function onError(response) {
loaderHide();
handleErrors(response, status, errors, not_show_error_toast);
};
},
}
return AngularUtils
})
Admin.js
var Fenrir = angular.module('Fenrir', []);
Fenrir.controller('AdminController', function ($scope, $http, AngularUtils) {
$scope.createScreen = function () {
AngularUtils.save('/admin/saveScreen', $scope.record, '', '').then(function (hubs) {
$scope.hubs = hubs;
console.log('In ctrl ' + $scope.hubs);
});
}
})
如何正确 return $http.post() 对象?
仔细查看错误信息:
TypeError: AngularUtils.save(...).then is not a function
这表示没有名为 then()
的函数是 return 从 AngularUtils.save(...)
编辑而来的。这表明 save()
函数确实执行了,但它没有像预期的那样 return promise。
所以你的工厂方法确实执行了,但因为你没有 return 承诺,我们只能推测执行最终导致了哪条路径。
更新:原脚本语法错误
在尝试为您证明我的解决方案时,我发现您的 $put().then()
响应处理程序存在语法问题,错误的地方有一个括号,onError
函数应该是then
函数的第二个参数,而不是在它之后。您的代码应如下所示:
return $http.put(url + obj.id + '/', obj).
then(function onSuccess(response) {
loaderHide();
angular.extend(obj, response);
errors = {};
}, function onError(response) {
loaderHide();
handleErrors(response, status, errors, not_show_error_toast);
});
微妙,但很重要,如果你没有严格编译,那么工厂函数根本就没有被正确编译,这可能会导致你的错误。
在 one 或 some 路径的工厂方法中 return async promise deferrals (futures) 然后是默认模式,虽然冗长,但 return 一个单一的延迟包裹了整个方法执行,然后对于每个响应路径,您可以选择通过 return 编辑的原始承诺来解决或拒绝响应函数。
可以使用不同的库和技术来执行此操作,see AngularJs and Promises with the $http Service by Rick Strahl 了解常见实现的演练。
save: function(url, obj, errors, not_show_error_toast) {
var defer = $.Deferred();
not_show_error_toast = typeof not_show_error_toast !== 'undefined' ? not_show_error_toast : false;
if (angular.isDefined(obj.id)) {
loaderShow(); // NOTE: let create manage the loader start if it needs to
$http.put(url + obj.id + '/', obj).
then(function onSuccess(response) {
loaderHide();
// HACK: because .then is used instead of .success, you probably want the response.data, please review this
angular.extend(obj, response.data);
defer.resolve(obj);
}, function onError(response) {
loaderHide();
handleErrors(response, status, errors, not_show_error_toast);
defer.reject(response);
});
} else {
// If create is a deferral, it should be safe to return it directly
return this.create(url, obj, errors, not_show_error_toast);
}
return defer.promise();
},
Note: Only call a start or show utility or state operation in the same scope that also calls the reciprocal end/hide/stop/close. The code can work if you do not follow this rule but it gets harder to maintain as your project evolves, for that reason I've moved the
loaderShow();
call into the branch that we know will always callloaderHide()
. This functional scope can not make the assumption that thecreate()
function will eventually callloaderHide()
for us.This is a common, but bad habbit we all need to grow out of ;)