2016-12-14 4 views
2

Я использую Angular 1.5.9 и angular-route 1.5.9. У меня есть рабочее решение, но для меня не имеет смысла, что мне понадобится $scope.$apply(), чтобы обновить DOM.

Я использую фабрику и контроллер для обновления массива, который используется как внутри ng-repeat. Я понимаю, что цикл дайджеста не запускается, поэтому мне нужно использовать $scope.apply(), но я не понимаю, почему. Вот код, который не удается:

myApp.controller('MyGamesController', ['$http', '$firebaseAuth', 'DataFactory', '$scope', function ($http, $firebaseAuth, DataFactory, $scope) { 
    console.log('mygamescontroller running'); 
    var self = this; 
    self.newGame = {} 
    self.games = []; 

    getGames(); 

    function getGames() { 
     DataFactory.getGames().then(function (response) { 
      console.log('returned to controller from factory', response); // logs the correct response including lastest data, but DOM doesn't update 
      self.games = response; // self.games is correctly set, but not updated on the DOM 
      $scope.$apply(); // Updates the DOM 
     }); 
    } //end getgames function 


    self.addGame = function() { 
    DataFactory.addGame(self.newGame).then(getGames); 
    } 

}]); //end controller 

Угловая маршрутизатор обрабатывает мой controllerAs так:

.when('/mygames' ,{ 
    templateUrl: '/views/templates/mygames.html', 
    controller: 'MyGamesController', 
    controllerAs: 'mygames' 
    }) 

И в HTML для нг-повтора части HTML выглядит следующим образом:

<tbody> 
    <tr ng-repeat="game in mygames.games"> 
     <td>{{game.game}}</td> 
     <td>{{game.number_players}}</td> 
     <td>{{game.time_to_play}}</td> 
     <td>{{game.expansion}}</td> 
    </tr> 
    </tbody> 

Как в стороне, я попытался очистить массив self.games и создать цикл, который подтолкнул каждого из них, и это не решило проблему. Мне все еще нужно было $scope.$apply(), чтобы обновить DOM.

У меня есть все репо (связывающую конкретные фиксации) доступный здесь, если это помогает: https://github.com/LukeSchlangen/solo_project/tree/df72ccc298524c5f5a7e63f4a0f9c303b395bafa

+0

Изменение 'вар само = это;' в 'вар себя = $ рамки;' должны обновить массив, 'само. games' – tsuz

ответ

2

Угловой не следит за изменения здесь, потому что выполнение этого кода находится за пределами Первьте угловые в. Самый простой способ иметь угловые часы для результатов обещания - использовать библиотеку $q.

function getGames() { 
    return $q.resolve(DataFactory.getGames().then(function (response) { 
     self.games = response; // self.games is correctly set, but not updated on the DOM 
    })); 
} //end getgames function 

$ Q обещания управляются Угловое, и он будет ожидать, чтобы запустить цикл дайджеста, когда $ д обещание рассасывается.

Вам также необходимо включить и ввести $ q в контроллер.

myApp.controller('MyGamesController', ['$q', '$http', '$firebaseAuth', 'DataFactory', '$scope', function ($q, $http, $firebaseAuth, DataFactory, $scope) { 

Это отличный пост детали, как асинхронные вызовы работают с циклом дайджеста: How do I use $scope.$watch and $scope.$apply in AngularJS?

+0

Это, кажется, отлично работает, когда я запускаю функцию 'addGame', но, похоже, не показывает игры на начальной загрузке - когда я впервые вызываю' getGames() '. Я предполагаю, что я не могу назвать библиотеку '$ q', как это при начальной загрузке? –

+0

Вы должны иметь возможность вызвать его при начальной загрузке, но данные не будут загружены до запуска контроллера. Это означает, что ваш просмотр будет загружен, но вы не увидите игры до тех пор, пока данные не будут получены, и обещание будет устранено. Я бы рекомендовал метод решения для важных данных, как показано в ответе Yaser. Другой вариант - иметь индикаторы контекстной загрузки, которые могут дать хороший UX. – ginman

2

Вместо того, чтобы массив игры в контроллере, вы можете получить на странице загрузки с помощью routeProvider так:

Поскольку ваша страница была отображена в это время загрузки (этот массив пуст), и не будет никакого события, которое вызывает цикл дайджеста.

.when("/news", { 
    templateUrl: '/views/templates/mygames.html', 
    controller: 'MyGamesController', 
    controllerAs: 'mygames' 
    resolve: { 
     games: function(){ 
      return DataFactory.getGames(); 
     } 
    } 
} 

И в контроллере:

app.controller("MyGamesController", function (games) { 
    var self = this; 
    self.newGame = {} 
    self.games = games; 
}); 
+0

Прохладный! Но это устранит проблему этого, не обновляя DOM при вызове 'addgames'? –

+0

Контроллер не инициализируется до тех пор, пока не произойдет разрешение @LukeSchlangen – Yaser

+0

И я думаю, что это действительно сработало бы для моей начальной загрузки страницы. Затем у меня есть функция «addGame», которая называется в нижней части контроллера, которая вызывает фабрику снова. Разве у меня не было бы этой проблемы, если бы он не обновлялся должным образом в этом вызове? –