如何确保工厂承诺在指令执行之前解析

时间:2016-01-17 22:09:13

标签: javascript angularjs json

到目前为止,研究现有的stackoverflow答案总能帮助我,我总能找到答案,但现在我真的被卡住了。

我正在构建一个应用程序,它使用指令创建日历月类型框。

<app2directive class="column_50" jahr="2016" mon="November"></app2directive>

指令代码因此隔离范围并利用templateUrl文件绘制日历月

App.directive('app2directive',function( YEARS, MONTHS, DAYS){

return {
    restrict:"ACE",
    scope:{},
    replace:true,
    templateUrl:"templates/cal_directive3.html",
    controller: function ( $scope, $attrs, $injector, $log, YEARS, MONTHS, DAYS) {            var factoryName = "datumFactory" ;
        var factoryTonnen = "jsonsrc" ;
        var factoryInstance = $injector.get( factoryName ) ;
        var tonnenInstance = $injector.get( factoryTonnen ) ;

        var wtf = $scope.jsondata.get().then( function( promise){
            console.log( "jsondata", promise ) ;
            //$scope.tonnen = promise ;
        }, function( error){
            console.log( "error", error ) ;
        }) ;


});

目前我使用$ injector注入一个工厂,该工厂运行$ http-request来读取json文件,其中包含假期或特定于所选年份和月份的其他静态信息等数据。

App.factory( 'jsonsrc', function( $http, $q ){ 
return {
    get: function(){
        var deferred = $q.defer() ;
        $http.get( 'termine_2016.json' )
            .success(function(data, status, headers, config) {
                deferred.resolve( data ) ;
            }).error(function(data, status, headers, config) {
                console.log( "[jsonsrc] request didnot work!" );
                deferred.reject( data ) ;
            }) ;
        return deferred.promise ;
    }
}

});

它的效果是,对于全年页面加载,对$ http的同一调用运行12次。

我关心的是重构文件,以便我可以优选地将json数据加载到主控制器中,并且指令范围可以从父作用域继承。

本质上,呼叫返回一个承诺。该指令需要等待该承诺在其继续进行之前解决的手段,但现在我仍然坚持如何去做。提前感谢任何指针!

3 个答案:

答案 0 :(得分:1)

首先$ http已经返回了你可以做的承诺:

return $http.get(...)

PS:你可以链接承诺,所以如果你有一些预处理可以做

return $http.get(..).then(function(response){
    var data = response.data;
    [..process..]
    **return data;**
}, function(rejection){
    // do some stuff
});

第二:通常你将数据绑定到你的指令(例如ng-model),并在控制器中调用服务(我认为是视图控制器)。为了处理数据的异步加载,你使用范围。$ watch或attrs。$观察模型,用加载的数据刷新你的指令。

这强制不会将指令绑定到您的数据加载方式,使其可重复使用,无论您加载数据的方式如何或在应用程序上更改它。

请注意我以粗体显示的内容,您不会忘记,或者下一次调用将不会处理您的数据。

最后:通常由指令API提供的链接功能你可以拥有:

link  : function(scope, element, attrs){
    attrs.$observe('myVariable', function(){
         // refresh your internal state of the directive here
    });
}

'myVariable'意味着在你的指令调用中你有一个attr my-variable:     

和“myData”在视图控制器中加载如下:

jsonrc.get().then(function(response){
    $scope.myData = response.data;
});

如果您想要更进一步,我建议您为假期服务构建服务,以便仅在应用程序启动时加载数据:

App.service('MyService',['$http', function($http){
    var promise = $http.get([URL]);
    return function(){  // this is your service
        var me = this;
        promise.then(function(response){
            this.data = response.data;
        });
    }
}]);

现在您可以在主控制器中使用:scope.data = MyService.data;或者甚至在你的指令中使用它,或者如果你想要使用一些吸气剂,这通常会更好,但并不总是令人骄傲。

如果我忘了什么告诉我。

答案 1 :(得分:0)

我认为这可能有所帮助。

  • 首先将异步调用添加到父控制器(指令的父级) 控制器)。
  • 然后隔离指令的范围。并为其添加模型。

&#13;
&#13;
scope: {
  data: '=',
}
&#13;
&#13;
&#13;

  • 在您的控制器上添加如下变量:$scope.directiveData = {}
  • 使用异步调用的结果分配该变量的值。
  • 显然将其传递给您的指令:<mydirective data="directiveData"></mydirective>
  • 在模板上使用此变量,并使用data名称或链接上的scope.data

可能你需要为directiveData模拟数据,或者只是添加一个ng-if来防止崩溃(当第一次尝试显示数据时,并且directiveData是空对象)。

答案 2 :(得分:0)

让您的工厂保存httpPromise并仅创建一次。

App.factory( 'jsonsrc', function( $http ){
     var httpPromise;
     function load () {
         httpPromise = $http.get( 'termine_2016.json' )
             .then(function onFullfilled(response) {
                  //return data for chaining
                  return response.data;
             }).catch( function onRejected(response) {
                  console.log( "[jsonsrc] request didnot work!" );
                  //throw to reject promise
                  throw response.status;
             });
          return httpPromise;
      };
      function get () {
          if (httpPromise) return httpPromise;
          //Otherwise
          return load();
      };
      return { load: load,
               get:  get
             };
});

请注意,我删除了$q.defer,而是使用了.then.catch方法。已弃用.success.error方法;请参阅AngularJS $http Service API Reference -- deprecation notice

然后您可以简化您的指令:

App.directive('app2directive',function(){
    return {
        restrict:"ACE",
        scope:{},
        replace:true,
        templateUrl:"templates/cal_directive3.html",
        controller: function ($scope, $attrs, jsonsrc, $log, YEARS, MONTHS, DAYS) { 
            jsonsrc.get().then (function (data) {
                $scope.tonnen = data ;
            }).catch ( function(error){
                console.log( "error", error ) ;
            });
        })
    }
});

以这种方式实现,jsonsrc工厂只执行一次XHR GET,但app2directive的每个实例都可以检索其自己的隔离范围的数据。