Angular $scope не е наличен извън моята функция

Донякъде ново за Angular и javascript. Имам следния написан контролер, използвайки фабрична услуга за достъп до локален JSON файл. По-голямата част от този код е извлечен (или изцяло взет) от тази публикация от Дан Уолин. Нямам достъп до променливата $scope.books извън функцията и не мога да разбера защо. console.log вътре във функцията ми дава обекта, който търся, но този отвън връща недефиниран. Какво правя грешно тук? Благодаря.

app.controller('FormController', ['$scope', 'tocFactory', function ($scope, tocFactory) {

  $scope.books;

  getBooks();

      function getBooks() {
        tocFactory.getBooks().
          success(function(data, status, headers, config) {
            $scope.books = data;
            console.log($scope.books);
          }).
          error(function(data, status, headers, config) {
            // log error
     })
  }
  console.log($scope.books);
  }]);

person GMarsh    schedule 18.08.2015    source източник
comment
Всичко е наред, console.log вътре в success връща правилния обект. Добре дошли в света на асинхронните методи.   -  person Krzysztof Safjanowski    schedule 18.08.2015
comment
Предполагам, че това зависи от вашето определение за ОК. Не мога да се свържа с него в моя HTML или да го използвам в други части на моя контролер в текущата му форма. Как да направя така, че да мога?   -  person GMarsh    schedule 18.08.2015
comment
Целият смисъл на обвързването на данни за потребителския интерфейс е, че всеки път, когато вашите данни се променят, потребителският интерфейс отразява това автоматично. Обвързването ви трябва да не е правилно.   -  person David Zech    schedule 18.08.2015


Отговори (3)


Защото правите ajax и след това изпълнявате следващия ред код. Което не означава, че имате гаранция, че вашият ajax отговор е готов при изпълнение на следващия ред код.

Винаги можете да получите стойността на отговора му във функцията за успех на $http, която се извиква, когато извикването на ajax се изпълни успешно.

Прочетете тук Как работи асинхронното повикване?

person Pankaj Parkar    schedule 18.08.2015

всъщност това не е въпрос на обхват, а на време. Функцията getBooks се изпълнява асинхронно, така че когато регистрационният ви файл на конзолата се случи, той най-вероятно няма да е обвързан с нищо. Можете да тествате това лесно с интервали, за да видите как се случва това:

app.controller('FormController', ['$scope', 'tocFactory', function($scope, tocFactory) {
  $scope.books;
  getBooks();
  function getBooks() {
    tocFactory.getBooks()
      .success(function(data, status, headers, config) {
        $scope.books = data;
        console.log($scope.books);
      })
      .error(function(data, status, headers, config) {
        // log error
      })
  }
  setInterval(function(){
    console.log($scope.books);
  }, 1000);
}]);
person wesww    schedule 18.08.2015
comment
какво ще стане, ако отговорът отнеме повече от 1 секунда? - person Pankaj Parkar; 18.08.2015
comment
моят бърз демо код предлага игра с setInterval, а не setTimeout. Той просто ще повтаря записването му на всяка 1 секунда завинаги, така че най-вероятно ще изведе undefined веднъж или повече и след това ще изведе някаква стойност след извикването на .success - person wesww; 18.08.2015
comment
хаха без притеснения, реших. Вашият отговор е също толкова добро обяснение на проблема, гласувах го в подкрепа - person wesww; 18.08.2015
comment
Направих и твоя.. Наздраве :) - person Pankaj Parkar; 18.08.2015

Можете да използвате $q услуга за обработка на асинхронен код с обещания:

app.controller('FormController', ['$scope', '$q', 'tocFactory', function ($scope,  $q, tocFactory)
{

    var getBooks = function()
    {
        var deferred = $q.defer();

        tocFactory.getBooks().
        success( function(data, status, headers, config)
        {
            $scope.books = data;
            deferred.resolve();
        } ).
        error( function(data, status, headers, config)
        {
            deferred.reject();
        } );

        return deferred.promise;
    };

    getBooks().then( function(res)
    {
        console.log($scope.books); // success : your data
    }, function(res)
    {
        console.log($scope.books); // error : undefined
    } );

    console.log($scope.books); // undefined

} ] );

Не съм тествал този код, но трябва да работи и да ви покаже принципа на обещанията. Повече за услугата $q: https://docs.angularjs.org/api/ng/service/$q

person Ziad    schedule 18.08.2015
comment
Няма нужда да използвате $q, тъй като $http вече връща обещание. Нещо повече – методите за успех и грешка вече са отхвърлени – https://docs.angularjs.org/api/ng/service/$http – Наследените $http обещаващи методи успех и грешка са остарели. Вместо това използвайте стандартния метод. Ако $httpProvider.useLegacyPromiseExtensions е зададено на false, тогава тези методи ще генерират $http/legacy грешка. - person Krzysztof Safjanowski; 18.08.2015