在Directive运行之前,AngularJS通过AJAX检索数据

jac*_*cob 16 javascript html5 angularjs angular-ui

我正在使用AngularUI的uiMap指令来实例化谷歌地图.uiMap指令适用于硬编码数据({mapOptions}[myMarkers]); 但是当我通过$http.get()(在AJAX调用完成之前指令触发)检索此数据时遇到了麻烦.

最初我在我的GoogleMaps控制器中执行GET ,但是当我意识到事情发生的时候,我把GET转移到了uiMap指令中.我有两个问题:

  1. 我认为这不是正确的方法.
  2. GET还检索数据 [myMarkers]
    • 创建标记的函数/指令无处不在,因为它负责创建所有叠加层

所以我的问题是,是否在应用程序的其他地方我可以在指令运行之前检索数据(并将其应用于范围)?

我读了$ q,这听起来像我想要的,但我不确定我是否可以在我的控制器中而不是在指令中做到(也不确定$q.defer.resolve()有什么不同$http.success()).

编辑我使用的大部分代码都是从AngularUI的doc中复制/粘贴,但这里有一个插件:http://plnkr.co/edit/t2Nq57

根据Andy的回答,我使用了uiMap和uiIf的组合:

<!-- index.html -->
<div
  id="map_container"
  ng-controller="GoogleMaps">

  <div ui-if="mapReady">

    <div
      ng-repeat="marker in markers"
      ui-map-marker="markers[$index]"
      ui-event="{'map-click':'openMarkerInfo(marker)'}"
    ></div>

    <div
      ui-map-info-window="myInfoWindow"
      ng-include="'infobox.html'"
    ></div>

    <div
      id="map_canvas"
      ui-map="myMap"
      ui-options="mapOptions"
    ></div>

  </div>

</div>
Run Code Online (Sandbox Code Playgroud)

警告1 uiIf不能在指定控制器提供其条件的同一元素中(uiIf具有比ngController更高的优先级,因此在uiIf执行之前它的控制器不会被设置).

警告2请务必使用最新版本的uiIf(最新标签v0.3.2中提供的版本已过期).在某些情况下,旧的错误导致TypeError.

必须在AngularJS之前包含警告3 jQuery(在index.html中); 否则你会收到一个TypeError声明Object [object Object] has no method 'trigger'(或Object [object HTMLDivElement] has no method 'trigger'在Windows上).Chrome将允许您进入触发器功能,因为Chrome知道它,但Angular没有(并且Angular会抛出错误).

function GoogleMaps( $scope , $http )
{

  var mapDefaults = {
    center:    new google.maps.LatLng(25,-90),//centres on Gulf of Mexico
    zoom:      4,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };

  $scope.mapOptions = {};
  $scope.mapReady = false;
  $scope.markers = [];

  $http.get('map.json').then(function mapData(response) {

    var map_data = response.data,
      user_defaults = map_data.user.defaults; //{center: [lat,lng], zoom: 15}

    $scope.mapOptions = {
      "center":    (typeof user_defaults.center !== 'undefined') ?
        new google.maps.LatLng(user_defaults.center[0],user_defaults.center[1])
        : mapDefaults.center,
      "zoom":      (typeof user_defaults.zoom !== 'undefined') ?
        parseInt(user_defaults.zoom,10)
        : mapDefaults.zoom,
      "mapTypeId": mapDefaults.mapTypeId
    };

    //working on code to populate markers object

    $scope.mapReady = true;

  });

  // straight from sample on http://angular-ui.github.com/#directives-map
  $scope.addMarker = function($event) { … };
  $scope.openMarkerInfo = function(marker) { … };
  $scope.setMarkerPosition = function(marker, lat, lng) { … };

}//GoogleMaps{}
Run Code Online (Sandbox Code Playgroud)

缺点 uiMap目前不支持渲染制作者.我正在研究这个GitHub问题/评论中建议的替代版本的uiMapMarker .
解决此问题的方法: https : //stackoverflow.com/a/14617167/758177
工作示例: http: //plnkr.co/edit/0CMdW3?p = preview

And*_*lin 31

您可以延迟执行ui-map直到加载数据.

HTML:

<div ui-if="loadingIsDone">
  <div ui-map="myMap" ui-options="myOpts"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

JS:

$http.get('/mapdata').then(function(response) {
  $scope.myOpts = response.data;
  $scope.loadingIsDone = true;
});
Run Code Online (Sandbox Code Playgroud)

  • `ui-if`现在是Angular核心的一部分,作为`ngIf`. (4认同)

Ben*_*esh 6

通常,您可以做的是设置您的指令,启动负载并完成成功.我假设您要为指令的所有实例加载一个数据.所以这里有一些伪代码,你可能想要攻击它:

app.directive('myDelayedDirective', ['$http', '$q', function($http, $q) {

  //store the data so you don't load it twice.
  var directiveData,
      //declare a variable for you promise.
      dataPromise;

  //set up a promise that will be used to load the data
  function loadData(){ 

     //if we already have a promise, just return that 
     //so it doesn't run twice.
     if(dataPromise) {
       return dataPromise;
     }

     var deferred = $q.defer();
     dataPromise = deferred.promise;

     if(directiveData) {
        //if we already have data, return that.
        deferred.resolve(directiveData);
     }else{    
        $http.get('/Load/Some/Data'))
          .success(function(data) {
              directiveData = data;
              deferred.resolve(directiveData);
          })
          .error(function() {
              deferred.reject('Failed to load data');
          });
     }
     return dataPromise;
  }

  return {
     restrict: 'E',
     template: '<div>' + 
          '<span ng-hide="data">Loading...</span>' +
          '<div ng-show="data">{{data}}</div>' + 
        '</div>',
     link: function(scope, elem, attr) {
         //load the data, or check if it's loaded and apply it.
         loadData().then(function(data) {
             //success! set your scope values and 
             // do whatever dom/plugin stuff you need to do here.
             // an $apply() may be necessary in some cases.
             scope.data = data;
         }, function() {
             //failure! update something to show failure.
             // again, $apply() may be necessary.
             scope.data = 'ERROR: failed to load data.';
         })
     }
  }
}]);
Run Code Online (Sandbox Code Playgroud)

无论如何,我希望有所帮助.

  • 我宁愿不在指令中执行GET(我不认为它属于那里?),但这样做也是一个问题,因为范围与该指令隔离,而markers指令需要一些检索到的数据.初始GET. (2认同)
  • 您可以轻松地将GET分解为服务,这将是同样的事情.为了简单起见,我没有在我的例子中这样做...如果你有另一个需要相同数据的指令,那么你将把所有逻辑与GET及其承诺放在一个服务中,然后同时使用指令调用该服务上的loadData. (2认同)