如何将资源调用与指令集成?

时间:2014-10-03 12:25:18

标签: angularjs angular-directive

基本上,我有两个指令:

angular.module("maineMap")
.directive("ngMap", ["APPCONFIG", "Map", function(config, Map){
       //D3 map drawing functionality based on data from $resource call
       return {
        restrict : "E",
        transclude : true,
        scope : {
            mapData : '='
        },
        link : function(scope, el, attrs){
                   }
        };
    }])
    .directive("donutChart", function(){
    return {
        restrict : "E",
        link : function(scope, el, attrs){
                    }
            }
    });

和控制器

angular.module("maineMap")
.controller('MapCtrl', ['$scope','Map', function($scope, Map{
    $scope.mapData = Map.mapData()  
                        .query();

    $scope.mapData.$promise.then(function(results){
        $scope.mapData = results;
        console.log($scope.mapData);
    });

}]);

其中Map是获取JSON文件的$resource实现。

我的问题是指令功能在控制器调用之前执行。也就是说,我在指令中调用mapData的几个属性,并且它们都在控制台中返回未定义的相应错误消息。但是,在错误打印输出后不久,执行$resource实现的数据提取并打印到控制台。

请注意,如果我替换$promise并完全依赖

$scope.mapData = Map.mapData()  
                        .query();

然后我在$scope.mapData指令中看到了<donut-chart>,但没有<ng-map>

鉴于这种结构,如何在控制器加载数据之前延迟指令功能?

2 个答案:

答案 0 :(得分:0)

执行顺序:

<div ng-controller="controller">
    <outer>
      <inner></inner>
      <inner></inner>
    </outer>
</div>

将是:

  1. 编译(内部)
  2. 编译(内部)
  3. 编译(外部)
  4. 控制器
  5. controller(外部)
  6. controller(内部)
  7. link(inner)
  8. controller(内部)
  9. link(inner)
  10. link(外部)
  11. 因此,控制器在指令链接发生之​​前明确设置范围。当然,除非在异步函数中设置范围。但是你的指令应该能够处理undefined范围值,因为指令不会(可能不应该)关心它在哪个控制器下操作,除非requires它。

答案 1 :(得分:0)

我使用joakimbi's解决方案来解决这个问题。具体来说,我添加了ngRoute依赖项并使用resolve属性来确保所包含的promise将在显示视图之前执行数据提取。

更新服务:

angular.module("maineMap")
.factory("MapService", ["$http", "$log", "$q", "appConfig", function($http, $log, $q, appConfig){
    var mapPaths, mapPromise, 
        cityPositions, cityPromise;

    return {
        getMapPaths : function(){

            mapPromise = $http.get(appConfig.maineData)
                                .success(function(data){
                                    mapPaths = data;
                                });

            return {
                getData : function(){
                    return mapPaths;
                },
                setData : function(data){
                    mapPaths = data;
                },
                promise : mapPromise
            };
        },
        getCityPositions : function() { ... }
   };
}]);

修改了应用程序初始值设定项,用于定义resolve属性中的promise:

angular.module("maineMap", ["ngResource", "ngRoute", "configuration"])
.config(["$routeProvider", function($routeProvider){
    $routeProvider.when("/", {
        templateUrl : "views/main.html",
        controller : "MapCtrl",
        resolve : {
            "MapData" : function(MapService){
                return MapService.getMapPaths().promise;
            },
            "CityData" : function(MapService){
                return MapService.getCityPositions().promise;
            }
        }
    });
}]);

修改后的控制器,其中数据提取在视图之前加载:

angular.module("maineMap")
.controller('MapCtrl', ['$scope','MapService', function($scope, MapService){
    $scope.mapData = MapService.getMapPaths().getData();
    $scope.cityData = MapService.getCityPositions().getData();
    $scope.currentCounty = {};
    console.log("MapData: " + $scope.mapData);
}]);

这样做的结果是,在视图模板中处理指令的标记之前,数据提取会执行并将结果保存在范围内,使其可用于指令。

Martin Atkins提出的另一个选项会将数据加载到angular.constant()变量中。由于我计划针对多个视图扩展此应用程序,因此ngRoute结合resolve承诺是合适的解决方案。