2016-02-23 3 views
1

Моя цель:Цепные обещания/требуют в AngularJS

Построить AngularJS службу (MapService), который инициализирует (MapService.initMap()) 3-го партийного контроля (Esri ArcGIS Map) и возвращает ссылку на мою карту (MapService.getMap()), так Я могу использовать его во всех моих контроллерах.

Код

<!DOCTYPE html> 
<html ng-app="app"> 
    <body ng-controller="MapController"> 


     <script data-require="[email protected]" data-semver="1.5.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script> 
     <script defer type="text/javascript" src="//js.arcgis.com/4.0beta3/"></script> 

     <script src="angular-esri-loader.js"></script> 
     <script src="script.js"></script> 
    </body> 

</html> 

script.js:

(function(angular) { 
    'use strict'; 

var app = angular.module('app', ['esri.core']); 

angular.module('app') 
    .controller('MapController', function(esriLoader, $scope, MapService) { 

     MapService.getMap().then(function (mapObj) { 
      console.log("resolved!!!"); // this code is never reached 
      alert('show map'); 
      $scope.map = mapObj; 
     }); 

     MapService.initMap(); 

    }); 



angular.module('app') 
    .service('MapService', function($q, esriLoader) { 
     this.deferred = $q.defer(); 

     this.getMap = function(){ 
      return this.deferred.promise; 
     } 
     var self = this; 
     this.initMap = function() { 

     // self.deferred.resolve('test'); // When I uncomment this line, the promise will be successfully resolved and the 'then' runs 

      esriLoader.require([ 
        'esri/Map', 
        'esri/widgets/Search', 
        'esri/widgets/Search/SearchViewModel' 
       ]).then(function(esriModules){ 
        var Map = esriModules[0]; 
        var Search = esriModules[1]; 
        var SearchViewModel = esriModules[2]; 

        // Create the map 
        var map = new Map({ 
         basemap: 'satellite' 
        }); 

        console.log("resolve map"); // this code is reached, however, it still doesn't seem to correctly resolve the promise 

        self.deferred.resolve(map); 

       }); 

     } 

    }); 
})(angular); 

Plunkr

https://plnkr.co/edit/LEhYqHVSpscTZ5kJCfyJ

Проблема:

Обещание, которое возвращает getMap(), поэтому код в пределах MapService.getMap().then() так и не был достигнут.

Когда я разрешаю обещание с некоторой тестовой строкой (self.deferred.resolve('test');) в моем методе initMap(), он работает.

Таким образом, я полагаю, что это проблема метода esriLoader.require(), который является еще одним обещанием, которое после require связано с некоторыми зависимостями компонента карты.

Так что я в основном решаю обещание в рамках обещания. Я добавил код esriLoader в plunkr.

Что я делаю неправильно?

+0

Используйте один метод 'initMap', который будет проверять, если карта инициализируется, то он возвращает экземпляр карты, в противном случае он будет инициализировать и затем вернуть экземпляр. Это не решит проблему. Просто совет для хорошего кода. – karaxuna

+1

Учитывая, что 'esriLoader.require' уже возвращает обещание, вы должны [избегать отложенного антипаттера] (http://stackoverflow.com/q/23803743/1048572)! – Bergi

ответ

1

Проблема заключается в том, что Map реализует некоторый интерфейс обещание. Я рекомендую проверить документацию. Вы можете решить вашу проблему, обернув карту в объект:

var map = { 
    map: new Map({ 
    basemap: 'satellite' 
    }) 
}; 

console.log("resolve map"); // this code is reached 

self.deferred.resolve(map); 

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

 this.initMap = function() { 

     //self.deferred.resolve('test'); // When I uncomment this line, the promise will be successfully resolved and the 'then' runs 

     return esriLoader.require([ 
       'esri/Map', 
       'esri/widgets/Search', 
       'esri/widgets/Search/SearchViewModel' 
      ]).then(function(esriModules){ 
       var Map = esriModules[0]; 
       var Search = esriModules[1]; 
       var SearchViewModel = esriModules[2]; 

       // Create the map 
       var map = new Map({ 
        basemap: 'satellite' 
       }); 

       console.log("resolve map"); // this code is reached 

       return {map: map}; 


      }); 
+0

Спасибо, это отлично работает! Еще один вопрос: прямо сейчас, каждый вызов 'initMap' создает новую карту. Я хотел бы создать его только один раз и каждый дополнительный «MapService.initMap(). Then()' call вернет ссылку на ранее созданную карту. Как бы Вы это сделали? – user66875

-2

Попробуйте так:

angular.module('app') 
.service('MapService', function($q, esriLoader) { 
    var map; 
    this.initMap = function() { 
     // return map instance if it's already initialized 
     if (map) { 
      return $q.resolve(map); 
     } 

     var defered = $q.defer(); 

     esriLoader.require([ 
      'esri/Map', 
      'esri/widgets/Search', 
      'esri/widgets/Search/SearchViewModel' 
     ]).then(function(esriModules){ 
      var Map = esriModules[0]; 
      var Search = esriModules[1]; 
      var SearchViewModel = esriModules[2]; 

      // Create the map 
      var map_ = new Map({ 
       basemap: 'satellite' 
      }); 

      map = map_; 
      defered.resolve(map_); 
     }); 

     return defered.promise; 
    } 

}); 

Просто используйте initMap, когда вам нужно отобразить экземпляр :)

MapService.initMap().then(function (map) { 
    // use map here 
}); 
+0

Спасибо, но, к сожалению, он все еще не работает. – user66875

+1

http: // stackoverflow.com/questions/23803743/what-is-the-explicit-prom-construction-antipattern-and-how-do-i-avoid-it –

+0

@BenjaminGruenbaum Я не знаю, какое обещание «esriLoader.require» возвращает , Что, если он вернет обещание es6? Будет ли он работать с '$ q'? – karaxuna

Смежные вопросы