简体   繁体   English

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

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

So far studying existing stackoverflow answers always helped me along, and I could always find an answer, but now I'm really stuck. 到目前为止,研究现有的stackoverflow答案总是帮助我,我总能找到答案,但现在我真的被卡住了。

I'm building an app, which uses a directive to create calender month type boxes. 我正在构建一个应用程序,它使用一个指令来创建日历月类型框。

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

the directive code therefore isolates the scope and utilizes a templateUrl file to draw the calendar month 因此,指令代码隔离范围并利用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 ) ;
        }) ;


});

At the moment i use an $injector to inject a factory which runs a $http-request to read a json-file with data such as holidays or other static information specific to the chosen year and month(s). 目前,我使用$ 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 ;
    }
}

}); });

The effect of it is, that the same call to $http is run 12 times for a full year page load. 它的作用是,对于全年页面加载,对$ http的同一调用运行12次。

My concern is to refactor the file, so that I could preferably load the json data into the main-controller and the directive scope could inherit from the parent scope. 我关心的是重构文件,以便我可以优选地将json数据加载到主控制器中,并且指令范围可以从父作用域继承。

By its nature the call returns a promise. 从本质上讲,呼叫会返回一个承诺。 The directive would need means to wait for that promise to resolve before it should proceed, but right now I'm stuck on how to go about it. 该指令需要等待该承诺在其继续进行之前解决的手段,但现在我仍然坚持如何去做。 Thanks in advance for any pointers! 提前感谢任何指针!

First $http is already returning a promise you can do : 第一个$ http已经返回了你可以做的承诺:

return $http.get(...)

PS : you can chain promise so if you have some preprocessing to do you can do PS:你可以链接承诺,所以如果你有一些预处理,你可以做

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

Second : Usually you bind data to your directive (ng-model for instance), and call services in controller (the view controller i mean). 第二:通常你将数据绑定到你的指令(例如ng-model),并在控制器中调用服务(我认为是视图控制器)。 In order to handle the asynchronous loading of data you use the scope.$watch or attrs.$observe on the model to refresh your directive with the data loaded. 为了处理数据的异步加载,你使用范围。$ watch或attrs。$观察模型,用加载的数据刷新你的指令。

This enforces not to bind the directive with how your data loaded making them reusable, whatever the way you load your data or change it on your application. 这强制不会将指令绑定到您的数据加载方式,使其可重用,无论您加载数据或在应用程序上更改数据。

Note what I put in bold, you musn't forget that or the next call to then won't have your processed data. 请注意我粗体显示的内容,您不会忘记,或者下一次调用将不会有您处理的数据。

Finally : usually the link function provided by directive API you can just have : 最后:通常由指令API提供的链接功能你可以拥有:

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

'myVariable' meanning in the call of your directive you have an attr my-variable : 'myVariable'在你的指令调用中意味着你有一个attr my-variable:

and "myData" is loaded in the view controllerlike this : 并且“myData”在视图控制器中加载如下:

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

If you want to go further I suggest you to build a service for your holidays service so you load the data only at startup of your application : 如果您想要更进一步,我建议您为假期服务构建服务,以便仅在应用程序启动时加载数据:

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;
        });
    }
}]);

So now you can use in your main controller : scope.data = MyService.data; 所以现在你可以在你的主控制器中使用:scope.data = MyService.data; or even use it in your directive, or use some getter if you want, this is usually better but not always revelant. 或者甚至在你的指令中使用它,或者如果你想要使用一些吸气剂,这通常会更好,但并不总是令人骄傲。

If i forget anything tell me. 如果我忘了什么告诉我。

I think this could help. 我认为这可能会有所帮助。

  • First add the async call into a parent controller (directive's parent controller). 首先将异步调用添加到父控制器(指令的父控制器)中。
  • Then isolate your directive's scope. 然后隔离指令的范围。 And add a model to it. 并为其添加模型。

 scope: { data: '=', } 

  • On your controller add a variable like: $scope.directiveData = {} 在您的控制器上添加一个变量,如: $scope.directiveData = {}
  • Assign the value of that variable with the result of the async call. 使用异步调用的结果分配该变量的值。
  • Obviously pass it to your directive: <mydirective data="directiveData"></mydirective> 显然将它传递给你的指令: <mydirective data="directiveData"></mydirective>
  • Use this variable on your template with the data name, or scope.data on link. 在模板上使用此变量, scope.data在链接上使用data名称或scope.data

Probably you will need mocked data for directiveData, or just add an ng-if to prevent crashing (when trying to show data the first time, and the directiveData is empty object). 可能你需要为directiveData模拟数据,或者只是添加一个ng-if来防止崩溃(当第一次尝试显示数据时,并且directiveData是空对象)。

Have your factory save the httpPromise and create it only once. 让您的工厂保存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
             };
});

Notice that I removed the $q.defer and instead used the .then and .catch methods. 请注意,我删除了$q.defer和代替.then.catch方法。 The .success and .error methods have been deprecated; .success.error方法已被弃用; see the AngularJS $http Service API Reference -- deprecation notice . 请参阅AngularJS $ http服务API参考 - 弃用通知

You can then simplify your directive: 然后,您可以简化您的指令:

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 ) ;
            });
        })
    }
});

Implemented this way, the jsonsrc factory executes the XHR GET only once, but each instantiation of the app2directive can retrieve the data for its own isolate scope. 以这种方式实现, jsonsrc工厂只执行一次XHR GET,但app2directive每个实例化app2directive可以检索其自己的隔离范围的数据。

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

相关问题 在Chrome扩展程序中,如何使用chrome-promise确保先前的承诺在下一个承诺之前得到解决? - In a Chrome extension, how to ensure previous promise resolves before the next one using chrome-promise? 承诺2在承诺1之前解决 - Promise 2 resolves before the Promise 1 resolve() 执行但 promise 未按预期解析 - resolve() executes but promise not resolves as expected .then()在promise解决之前触发 - .then() fires before promise resolves .then()在内部承诺解决之前先解决自己 - .then() resolves itself before internal promise resolves 对于异步测试和挂钩,如何解决超时超出错误,请确保调用了“ done()”; 如果返回承诺,请确保其解决 - How to fix Timeout exceeded error for async tests and hooks, ensure “done()” is called; if returning a Promise, ensure it resolves 承诺链在最后一个承诺解决之前就解决了 - promise chain resolves before its last promise resolves 导航器 - getCurrentPosition() 承诺在找到位置之前解决 - Navigator - getCurrentPosition() promise resolves before location is found rxjs最终在promise解决之前执行 - rxjs finally executed before promise resolves 承诺在forEach循环完成之前解决 - Promise resolves before forEach loop completes
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM