繁体   English   中英

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

[英]How to ensure factory promise resolves before directive executes

到目前为止,研究现有的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数据加载到主控制器中,并且指令范围可以从父作用域继承。

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

第一个$ 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; 或者甚至在你的指令中使用它,或者如果你想要使用一些吸气剂,这通常会更好,但并不总是令人骄傲。

如果我忘了什么告诉我。

我认为这可能会有所帮助。

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

 scope: { data: '=', } 

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

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

让您的工厂保存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服务API参考 - 弃用通知

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

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每个实例化app2directive可以检索其自己的隔离范围的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM