AngularJS: область контроллера не будет синхронизироваться с обещанием

Я взял проект и пытаюсь вернуть некоторые данные из службы в свой контроллер. Я занимался этим около 12 часов и пробовал разные методы. Все они обычно приводят к одному и тому же типу «отсутствующих данных».

я пробовал

  • используя $resource вместо $http
  • поместите $http.get прямо внутри контроллера без использования промисов
  • сервис как реальный сервис (вместо фабрики) без возврата
  • создание фабрики множества различных способов возврата данных в различных форматах
  • используя setTimeout и $apply

Я чувствую, что то, что у меня есть сейчас, простое, насколько я могу это понять, и все, что я читал, говорит, что это должно работать.

angularjs-load-data-from-service

angular-controller-cant-get-data-from-service

angularjs-promises-not-fireing-when-returned-from- услуга

angularjs-promise-not-resolving-properly

angularjs-обещание

Эти ссылки были только сегодня.

Я думал, что может быть проблема с $scope, так как в прошлом я видел, что $scopes не получают данные при использовании нескольких контроллеров, однако сайт просто объявляет контроллер в index.html как <body ng-app="myApp" ng-controller="BodyCtrl"> setup . Основной app.js использует состояния (я полагаю, из ui-router) вот так...

.state('app.view', {
    url: '/view',
    templateUrl: 'views/view.tpl.html',
    controller: 'MyCtrl'
   })

прикрепить контроллеры к разным страницам. Также на сайте есть несколько других контроллеров, получающих данные от сервисов, которые я сначала просмотрел как шаблон, однако данные и возвраты там намного сложнее, чем то, что я пытаюсь получить. В итоге контроллеры получают доступ к данным, предоставляемым службами. Все они используют $resource, как я и начал с этой проблемы. Я остановился на $http, потому что он должен работать, и я хотел бы, чтобы это работало с ним, прежде чем я перейду к чему-то «более высокому уровню». Кроме того, мне нужно только ПОЛУЧИТЬ с конечных точек, поэтому $resource кажется излишним.

сервис

.factory('MyService', ['$http', '$q', '$rootScope', function ($http, $q, $rootScope) {
    var defer = $q.defer();
    var factory = {};
    factory.all = function () {
        $http({method: 'GET', url: 'http://URLtoJSONEndpoint'}).
            success(function (data, status, headers, config) {
                console.log('data success', data);
                defer.resolve(data);
            }).
            error(function (data, status, headers, config) {
                console.log('data error');
                defer.reject(data);
            });

        return defer.promise;
    };
    return factory;
}]);

контроллер

.controller('MyCtrl', ['$scope', '$state', '$stateParams', '$rootScope', 'MyService', '$q', function ($scope, $state, $stateParams, $rootScope, MyService, $q) { 
...
...
$scope.data = null;
$scope.object = MyService;
$scope.promise = MyService.all();

MyService.all().then(function (data) {
    $scope.data = data;
    console.log("data in promise", $scope.data);
})
console.log("data", $scope.data);
console.log("object", $scope.object);
console.log("promise", $scope.promise);

$http({method: 'GET', url: 'http://URL'}).
        success(function (data, status, headers, config) {
            $scope.data = data;
            console.log('data success in ctrl', data);
        }).
        error(function (data, status, headers, config) {
            console.log('data error');
        });

    console.log("data after ctrl", $scope.data);


    angular.forEach($scope.data, function (item) {
        // stuff that I need $scope.data for
    }

журнал консоли

Итак, это мой консольный журнал, и я могу получить много, но не фактические данные! Это то, что мне нужно. Я даже сошел с ума и расширил свой .then(function (data) {, чтобы захватить все функции в контроллере, которым нужен $scope.data. Это было крушение поезда.

***data null***
object Object {all: function}
promise Object {then: function, catch: function, finally: function}
***data success after ctrl null***
data success in ctrl Array[143]
data success Array[143]
data in promise Array[143]
data success Array[143]

Насколько я могу судить, это должно работать, но я не уверен, в чем еще может быть проблема! Может быть, я не понимаю, как обещания работают или разрешаются. Я использовал Angular раньше с другим проектом, но я был там в самом начале и понимал, как он устроен. Этот проект был структурирован по-другому и кажется гораздо более хаотичным. Я хотел бы упростить его, но я даже не могу получить некоторые простые данные для возврата!

Я ценю любую помощь / отзывы, которые вы можете предложить, чтобы определить, почему это не работает, спасибо!

РЕДАКТИРОВАТЬ: Итак, вопрос в том, почему console.log("data", $scope.data) возвращается null/до обещания?

Чуть дальше в контроллере у меня есть это

angular.forEach($scope.data, function (item) {
// stuff
}

и, похоже, у него нет доступа к данным.

EDIT2: я добавил $http.get, который я использовал внутри контроллера, вместе с журналами консоли для него и фактически forEach, который мне нужен $scope.data для

РЕДАКТИРОВАТЬ3:

обновленный сервис

.service('MyService', ['$http', function ($http) {
    function all() {
        return $http({
            url: 'http://URL',
            method: 'GET'
        });
    }

    return {
        all: all
    }
}]);

обновлен контроллер

MyService.all().success(function (data) {
        $scope.data = data;

        angular.forEach($scope.data, function (item) {

            // Turn date value into timestamp, which is needed by NVD3 for mapping dates
            var visitDate = new Date(item.testDate).getTime();

            switch (item.Class) {
                case "TEST":
                    testData.push(
                        [
                            visitDate,
                            item.Total
                        ]
                    );

            }

        });

        console.log("test Data in success", testData);
    });


$scope.testData = [
        {
            "key": "Test",
            "values": testData
        }
    ];

Таким образом, $scope.testData необходимо использовать в представлении (диаграмма nvd3), и он не получает данные.

РЕШЕНИЕ

MyService.all().success(function (data) {
        $scope.data = data;

        angular.forEach($scope.data, function (item) {

            // Turn date value into timestamp, which is needed by NVD3 for mapping dates
            var visitDate = new Date(item.testDate).getTime();

            switch (item.Class) {
                case "TEST":
                    testData.push(
                        [
                            visitDate,
                            item.Total
                        ]
                    );
            }

        });

        console.log("test Data in success", testData);

        $scope.testData = [
        {
            "key": "Test",
            "values": testData
        }
    ];
    });

person mykepwnage    schedule 07.05.2014    source источник
comment
Итак, ваш вопрос: почему console.log("data", $scope.data); // => data null? Если да, то, вероятно, это связано с тем, что журнал выполняется до завершения асинхронного вызова. Обратите внимание, что два вызова MyService.all(); фактически вызовут два запроса. Я думаю, что первое не нужно.   -  person Yoshi    schedule 07.05.2014
comment
Да, точно! Спасибо, что указали на это, было не очень понятно   -  person mykepwnage    schedule 07.05.2014
comment
Я бы начал с того, что заставил его работать внутри вашего контроллера, поэтому в случае успеха выполните $scope.data = data; Когда вы увидите, что вызов работает успешно, начните переделывать сервисы, подумайте, что вы добавляете сложности. $http уже возвращает обещание, поэтому вам не нужно использовать другое обещание. https://docs.angularjs.org/api/ng/service/$http   -  person LightningShield    schedule 07.05.2014
comment
@mykepwnage data в течение некоторого времени не должен быть проблемой. Если это так, вы можете добавить к своему вопросу, как вы используете данные.   -  person Yoshi    schedule 07.05.2014
comment
@LightningShield достаточно честно. Я пробовал это раньше, но получил тот же результат, поэтому решил, что можно просто оставить его в сервисе. Я добавил некоторый код, показывающий, что он по-прежнему не работает, когда я держу его в контроллере.   -  person mykepwnage    schedule 07.05.2014
comment
@Йоши Верно! Я добавил, как данные должны использоваться.   -  person mykepwnage    schedule 07.05.2014
comment
@mykepwnage Поскольку вы имеете дело с асинхронными вещами, прямое использование angular.forEach($scope.data, не сработает. Сделайте это внутри обратного вызова успеха или функции, которая будет вызываться внутри обратного вызова успеха.   -  person Yoshi    schedule 07.05.2014
comment
@Yoshi Это интересно, и я не совсем понимаю. Поэтому я переместил свой angular.forEach внутрь обратного вызова успеха, а затем вывел изменения данных на консоль, и они были там. Однако они не видят этого. Или, может быть, представление визуализируется до того, как данные могут быть сохранены в области...? Я обновлю, чтобы показать.   -  person mykepwnage    schedule 07.05.2014
comment
@Yoshi хорошо, пожалуйста, посмотрите обновленный сервис/контроллер. Я изменил формат в вашем ответе ниже.   -  person mykepwnage    schedule 07.05.2014
comment
@Yoshi хорошо, вот и все, мне просто нужно было поместить все вызовы $scope в обратный вызов успеха! Большое спасибо!!!   -  person mykepwnage    schedule 07.05.2014


Ответы (2)


Это может быть очень простой пример того, как может выглядеть ваш сервис:

app.service('MyService', ['$http', function ($http) {
  function all() {
    return $http({
      url: 'data.json',
      method: 'GET'
    });
  }

  return {
    all: all
  }
}]);

В контроллере вы используете его так:

app.controller('AppCtrl', ['$scope', 'MyService', function ($scope, MyService) {
  $scope.data = null;

  MyService.all().success(function (data) {
    $scope.data = data;

    // init further handling of `.data` here.
  });
}]);

Демо: http://plnkr.co/edit/l8pF8Uaa312A8kPtaCNM?p=preview.


Чтобы ответить на вопрос, почему консоль регистрирует data null: это просто потому, что журнал происходит до завершения асинхронного вызова.

person Yoshi    schedule 07.05.2014

Я столкнулся с той же проблемой. Я решаю эту проблему, используя $rootScope внутри обещания, а не $scope.So $rootScope.data будет доступно в console.log

person Thierry Otis    schedule 03.12.2015