[英]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. 我认为这可能会有所帮助。
scope: { data: '=', }
$scope.directiveData = {}
$scope.directiveData = {}
<mydirective data="directiveData"></mydirective>
<mydirective data="directiveData"></mydirective>
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.