So far studying existing stackoverflow answers always helped me along, and I could always find an answer, but now I'm really stuck.
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
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).
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.
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.
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 :
return $http.get(...)
PS : you can chain promise so if you have some preprocessing to do you can do
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). 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.
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 :
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 :
and "myData" is loaded in the view controllerlike this :
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; 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 = {}
<mydirective data="directiveData"></mydirective>
data
name, or scope.data
on link. 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).
Have your factory save the httpPromise and create it only once.
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. The .success
and .error
methods have been deprecated; see the AngularJS $http Service API Reference -- deprecation notice .
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.