So basically I am using resolve in $routeProvider in order to get my current user's information before I instantiate the controller.
This is how I do it:
userMan.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/userManagement', {
templateUrl: 'userManagement/userManagement.html',
controller: 'userManCtrl',
resolve: {
myUser:function($http){
console.log("I am about to make the call");
$http.get("/irods-cloud-backend/searchByMetadata/getCurrentUser").then( function( result ) {
console.log(result.data);
return result.data;
},
function( result ) {
alert("Unable to find any users! Please try again...");
})
}
}
});
}]);
My controller also looks something like this:
userMan.controller('userManCtrl', ['$scope', '$log', '$http', '$location', 'myUser',
function($scope, $log, $http, $location, myUser){
var currUser = myUser;
Basically my error is that currUser is undefined. This prevents me to check the user's permissions and such.
I have also used:
$scope.$on('$routeChangeSuccess',function(event, current){
alert("loaded!!");
});
To see when this promise is resolved, but I see the alert message as soon as I load into the tab.
I then tried to use a dummy return object simply like
return { someAttr: 'val'};
This functions just fine.. I know its not a promise but did that for sanity purposes..
Any clues for the error?
You don't return from the myUser method, so there's nothing to wait for but undefined. As #JoelCDoyle commented:
Your resolve method must return a promise. $http method returns a promise.
resolve: {
myUser:function($http){
// return here!
return $http.get("/irods-cloud-backend/searchByMetadata/getCurrentUser").then( function( result ) {
console.log(result.data);
return result.data;
}
After feedback from #JoelCDoyle and #baao, I used a different approach.
I simply created a service that handled the GET request and used that in my resolve.
More on this can be viewed here
Related
I have a state as following :
.state('core.recover', {
url: '/recover',
controller: 'RecoverPasswordCtrl',
templateUrl: 'views/tmpl/recoverAccount/recover-password.html'
})
I want when I enter to this state to check something before loading the template, in this case I want to call an api that checks for something if the promise is successful it will continue and display the template, otherwise it will redirect the user to another state.
I tried to do this on the top of the controller but I always see the template for a moment then it redirects me, so I tried to use resolve as in this post :
AngularJS | handle routing before they load
As following :
.state('core.recover', {
url: '/recover',
controller: 'RecoverPasswordCtrl',
resolve: function(recoverAccountService, $location, $state, $q) {
var deferred = $q.defer();
deferred.resolve();
recoverAccountService.get({email:$location.search().email, verificationKey:$location.search().verificationKey})
.$promise.then(function (result) {}).catch(function (err) {
$state.go("candidature.pre");
});
return deferred.promise;
},
templateUrl: 'views/tmpl/recoverAccount/recover-password.html'
})
but it didn't work and I'm getting this error in the browser's console :
Error: 'invocables' must be an object
How can I solve this ?
You're not using the correct syntax, uiRouter is expecting as entry for resolve an object, which keys it will try to evaluate.
Lets abbreviate your resolving function as aimadResolver, such that
var aimadResolver = function(recoverAccountService, $location, $state, $q) {
var deferred = $q.defer();
deferred.resolve();
recoverAccountService.get({ email: $location.search().email, verificationKey: $location.search().verificationKey })
.$promise.then(function(result) {}).catch(function(err) {
$state.go("candidature.pre");
});
return deferred.promise;
}
Of course, this is not mandatory, but I'm doing it for the sake of readability. Then, your state definition should be as follows:
state('core.recover', {
url: '/recover',
controller: 'RecoverPasswordCtrl',
resolve: {'yourResolverName': aimaidResolver}
},
templateUrl: 'views/tmpl/recoverAccount/recover-password.html'
})
Don't forget to inject yourResolverName in RecoverPasswordCtrl, or else your controller will be instantiated without waiting anyway. Source: look for the resolve examples
On the side
I'd like to point out that your use of deferred objects doesn't make sense. You're immediately resolving your deferred object on the second line within your function, which means that recoverAccountservice.get() could still be pending while RecoverPasswordCtrl is already being instantiated. Assuming that recoverAccountservice.get() returns a promise (and if it doesn't, you should change it such that it does), you can more efficiently write:
var aimadResolver = function(recoverAccountService, $location, $state, $q) {
return recoverAccountService.get({... })
.then(function(result) {
// do nothing? Apparently you only want to $state.go on a rejection of the promise
})
.catch(function(err) {
$state.go("candidature.pre");
return $q.when()
})
}
More on the use of $q.when() versus deferred can be found here.
Im trying to make a AngularJS factory that provides my app with a list of businesses. But i cant seem to get the variable the first time this is run. But after interval is run, i get the variable.
I get this on the first run on the controller in the page:
angular.js:12783 Error: [$injector:undef] Provider 'businessList' must return a value from $get factory method
But I think my solution is faulty, any how? Can anyone point me in the right direction here? For example is using rootScope here a good idea?
What I want is a globally accessible list of businesses in my app, that is collected on start of visit, and updates itself with a timer. So i dont have to all the time call for induvidial requests from the laravel backend, when i can just find it in that list.. is my idea.
Factory:
myApp.factory('businessList', ['$interval', '$http', '$rootScope',
function($interval, $http, $rootScope) {
function bedriftliste() {
$http.get('get/allebedrifter')
.then(function(result) {
bedrifter = result.data;
$rootScope.bedrifter = bedrifter;
});
return $rootScope.bedrifter;
}
var bedrifter = bedriftliste();
// start periodic checking
$interval(bedriftliste, 5000);
return bedrifter;
}
]);
Controller
myApp.controller('bsC', ['$rootScope', '$scope', 'businessList',
function($rootScope, $scope, businessList) {
$scope.allebedrifter = businessList;
}]);`
I solved this by just doing a http.get if object was null.
if (!$rootScope.allebedrifter) {
$http.get('get/bedrift/' + $scope.tslug)
.then(function(result) {
bedriften = result.data;
$scope.bedriften = bedriften;
});
Seems to work fine like this
Although I am late in pointing out but that doesn't seem to be a proper solution to this problem. You need to make these changes in factory:
myApp.factory('businessList', ['$interval', '$http', '$rootScope',
function($interval, $http, $rootScope) {
function bedriftliste() {
return $http.get('get/allebedrifter');
}
}
]);
and in the controller you'll do something like this:
myApp.controller('bsC', ['$rootScope', '$scope', 'businessList', function($rootScope, $scope, businessList) {
function TestFunction(){
businessList.bedriftliste().then(function successCallback(response) {
$scope.allebedrifter = response.data;
//it will invoke 5 seconds after you receive the response from your factory method, I didn't test it but it will solve your problem
$interval(TestFunction, 5000);
}, function errorCallback(response) {
});
}
}]);
I have a factory using $resource but cant use object generated as undefined
I've seen so many reponses regarding that problem that i am more and more confusing
here is my factory
angular.module('contrats')
.factory('Contrats', ['$resource',
function($resource) {
return $resource('contrats/:contratId', { contratId: '#_id'}, {
update: {method: 'PUT'},
});
}
]);
here is my controler
// Contrats controller
var app = angular.module('contrats')
.controller ('ContratsController',
['$scope' , '$stateParams', '$location', 'Authentication', 'Contrats', function($scope, $stateParams, $location, Authentication, Contrats)
{
$scope.contrats = Contrats.query();
$scope.nbctrt = $scope.contrats.length;
})];
$scope.contrats.length = > generate error can't get property of undefined
I'stuck for days with that and dont understand Thanks for your advices to a newbie
To clarify my comment.
Add you logs inside the success function, so that the query is complete before logging, something like this
$scope.contrats = Contrats.query(function(success) {
// response from query
console.log(success);
// length of $scope.contrats
console.log('nb contrats',$scope.contrats.length);
// first item in $scope.contrats
console.log('contrats[0]:' , $scope.contrats[0]);
}, function(error){
console.log(error);
});
apothekenService.getApotheke returns a promise. response.data within the promise is a json object which is delivered correctly, I can see that in the first console.log.
How can I get this json object to my variable in the resolve? When I do the same in a controller I just use $scope and bind the variable within the response but in this case I don't have a scope.
angular.module("test", ["ngAnimate", "ngCookies", "ngTouch", "ngSanitize", "ngResource", "ui.router", "ui.bootstrap", "ui.bootstrap.showErrors", "myApothekenService"]).config(function($stateProvider, $urlRouterProvider, $uiViewScrollProvider, showErrorsConfigProvider) {
$uiViewScrollProvider.useAnchorScroll;
return $stateProvider.state("root", {
abstract: true,
controller: "RootCtrl",
resolve: {
Apotheke: function(apothekenService) {
this.apo = {};
apothekenService.getApotheke().then(function(response) {
console.log(response.data);
return this.apo = response.data;
});
console.log(this.apo);
return this.apo;
}
}
});
}).controller("RootCtrl", function($scope, $location, $anchorScroll, Apotheke) {
$scope.apotheke = Apotheke;
console.log($scope.apotheke);
});
You know this inside the promise resolve function (then) is different than the this inside the parent resolve function. If you want to use this pattern, the usual convention is to capture this in a local variable self, and use that throughout your resolve function.
But anyways, I will just do as below. This way, the controller code won't execute until the resolve promise is resolved.
Apotheke: function(apothekenService) {
return apothekenService.getApotheke();
}**
I'm wondering what the best way to abstract $http calls into an angularjs service is. I've done a bit of research and this seems to be the most common way:
app.factory('myService', function($http) {
return {
getFoo: function() {
return $http.get('foo.json').then(function(result) {
return result.data;
});
}
}
});
app.controller('MainCtrl', function($scope, myService) {
//the clean and simple way
$scope.foo = myService.getFoo();
}
But the problem with this approach is I can't figure out how to do anything on .error.
I'd prefer to have my .success and .error callbacks inside my controller.
Is there a way to abstract the http call inside the service whilst maintaining .error and .success callbacks inside the controller?
Thank you.
You can still use the on success/error calls.
The method you've highlighted returns a "Promise" object. A good thing about promises is that they are chainable.
So say you wish to respond to a $http request error in your controller:
app.factory('myService', function($http) {
return {
getFoo: function() {
return $http.get('foo.json').then(function(result) {
return result.data;
});
}
}
});
app.controller('MainCtrl', function($scope, myService) {
//the clean and simple way
$scope.foo = myService.getFoo().then(function(){
//Do something with successful response
}, function(){
//Do something with unsuccessful response
});
}
NOTE: This following next section no longer holds true. Promises used in templates are no longer automatically resolved to its values when the promise resolves.
You should also understand why assigning $scope.foo works in your templates. AngularJS has a bit of magic that will resolve any promises to the object you need in a template. So while your template might reference foo.bar and the output will be correct, whats actually happening in the background is that the template is waiting for the promise to be fulfilled before rendering that part of the template.
Also, another gotcha is to remember to return an rejected promise if you're handling the error somewhere up in the chain.
For example:
app.factory('myService', function($http, $q) {
return {
getFoo: function() {
return $http.get('foo.json').then(function(result) {
return result.data;
}, function(result){
//I'm doing something here to handle the error
return $q.reject(result);
});
}
}
});
app.controller('MainCtrl', function($scope, myService) {
//the clean and simple way
$scope.foo = myService.getFoo().then(function(){
//Do something with successful response
}, function(){
//Do something with unsuccessful response
});
}
If we didn't return a rejected promise in the service, the controller's 'success' code path will be run instead of the reject path.