Как вернуть объект $http.post() с заводской функцией?

#javascript #angularjs #object #error-handling #angular-factory

Вопрос:

Когда я попытался вернуть объект $http.post() из заводской функции с помощью Angular, он выдает мне эту ошибку:

введите описание изображения здесь

Ниже приведен мой код:

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

Как правильно вернуть объект $http.post ()?

Комментарии:

1. Пожалуйста, покажите, как вы вводили admin.js, поэтому покажите конструктор контроллера.

2. this.create(url, obj, errors, not_show_error_toast) Возвращает ли обещание?

3. Можете ли вы также опубликовать реализацию ошибок обработки, вы недостаточно разделили проблемы , вместо этого вы поместили асинхронный пользовательский интерфейс, влияющий на код, внутри заводского метода, у которого нет доступа к области UI$. При переезде в заводской осуществления вы не можете нормально просто взять геймпад код и вставьте его на завод определению, вы должны удалить все зависимости в пользовательском интерфейсе, тот факт, что вы проходите через errors объект является одним из ключевых индикаторов или красный флаг , что звонить не верно, ошибки должна исходить от обещаем, мы не сдать их.

Ответ №1:

Внимательно изучив сообщение об ошибке:

 TypeError: AngularUtils.save(...).then is not a function
 

Это говорит о том, что нет функции с именем then() , из которой возвращалась AngularUtils.save(...) бы функция . Что указывает на то, что save() функция действительно выполнялась, но она не вернула обещание, как ожидалось.

Таким образом, ваш фабричный метод действительно был выполнен, но поскольку вы не вернули обещание, мы можем только предполагать, к какому из путей в конечном итоге привело выполнение.

Обновление: синтаксическая ошибка в исходном сценарии

Пытаясь обосновать свое решение для вас, я обнаружил, что у вашего $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);
            });
 

Тонкий, но важный момент: если у вас нет строгой компиляции, то заводская функция была просто неправильно скомпилирована, что может привести к вашей ошибке.


В заводских методах, где один или несколько путей будут возвращать асинхронные отсрочки обещаний (фьючерсы), тогда шаблон по умолчанию, хотя и подробный, должен возвращать одну отсрочку, охватывающую все выполнение метода, затем для каждого из путей ответа вы можете разрешить или отклонить ответ с помощью исходного обещания, возвращенного функцией.

для этого существуют различные библиотеки и методы, см. Раздел AngularJS и Обещания с помощью сервиса $http Рика Страла для ознакомления с общими реализациями.

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

Примечание: Вызывайте только операцию запуска или отображения утилиты или состояния в той же области, которая также вызывает взаимное завершение/скрытие/остановку/закрытие. Код может работать, если вы не будете следовать этому правилу, но его становится все труднее поддерживать по мере развития вашего проекта, по этой причине я переместил loaderShow(); вызов в ветку, которая, как мы знаем, всегда будет вызывать loaderHide() . Эта функциональная область не может предполагать, что create() функция в конечном итоге вызовет loaderHide() нас.

Это распространенная, но плохая привычка, из которой нам всем нужно вырасти 😉

Комментарии:

1. Большое спасибо, это работает! Отличное объяснение и советы