How to use routing resolves on ajax calls - angularjs

I am new to angular and there is virtually no documentation on routing resolves .
1.How Do we use resolves?
2.I need to run an ajax call before the page load. How do I do that if the ajax calls are in the service.js?
3. Can I redirect to another page if the ajax call fails or if I do not get favourable objects in the success of the ajax call?

To use a resolve-block with a route you can do
var dataResolve = ['someDependency', function(someDependency) {
return someDependency.someThingAsync();
}];
Sets up the resolve-objekt and injects stuff into it.
when('/my/url', {
templateUrl: 'templates/myTemplate.html',
controller: 'MyCtrl',
resolve: {
data: dataResolve
}
})
Sets up the resolve for the route. The controller can then take data into its constructor function.
As for cancelling the route, I am not sure.

Related

What is the best way to resolve data before loading view and controller in Angular JS?

I've a page with Navbar and Sidebar that remains common across most of the pages and hence I load all data related to LoggedInUser in NavbarController.
This data ($scope.loggedInUser) is used in other Controllers (child controller) as well. Since call to get User data is async, many times, child controller tries to access data before it is returned from the server.
What is the best way to ensure, all promises of parent controller are resolved before child controller starts it's work?
You should use resolve from $stateProvider. This function ensures that all the promises are resolved before loading a new state.
A resolve is a property you can attach to a route in both ngRoute and the more robust UI router. A resolve contains one or more promises that must resolve successfully before the route will change. This means you can wait for data to become available before showing a view, and simplify the initialization of the model inside a controller because the initial data is given to the controller instead of the controller needing to go out and fetch the data.
$routeProvider
.when("/news", {
templateUrl: "newsView.html",
controller: "newsController",
resolve: {
message: function(messageService){
return messageService.getMessage();
}
}
})
in controller
app.controller("newsController", function (message) {
$scope.message = message;
});
Hope this will help you

Sequential Angular stateProvider resolves

I need to perform router resolves in order. Meaning first run ProfileLoaded http call, when that finishes, run Access resolve. How can I do this?
$stateProvider.
state('sign-up', {
url : '/sign-up',
templateUrl: '/html/pages/registration.html',
controller: 'signupCtrl',
resolve : {
// Load profile first, then check if they are subscribed
ProfileLoaded : ['$rootScope', function ($rootScope) {
return $rootScope.loadProfile();
}],
// Then check Access
access: ['Access', function (Access) {
return Access.isSubscribed();
}]
}
})
Where $rootScope.loadProfile(); is an AJAX $http request and, where Access.isSubscribed relies on the loaded profile to perform auth'ed routing.
The logical choice would be to put access as a callback in loadProfile, but don't want it to get messy.
Assuming $rootScope.loadProfile returns a promise, simply add the required resolve property as a dependency, eg
access: ['Access', 'ProfileLoaded', function(Access, ProfileLoaded) {
return Access.isSubscribed();
}]
See http://angular-ui.github.io/ui-router/site/#/api/ui.router.util.$resolve#methods_resolve
Dependencies of invocables are resolved (in this order of precedence)
from the specified locals
from another invocable that is part of this $resolve call
from an invocable that is inherited from a parent call to $resolve (or recursively from any ancestor $resolve of that parent).
and
Invocables are invoked eagerly as soon as all dependencies are available.

Resolve must contain all promises even from controller?

Probably it's just as easy as I think it is, but I cannot really find an answer to my question on the internet, so I hope you guys know the answer just by looking at a small piece of my code.
Problem: I'm using the UI router in Angular and it loads the template before all the data is loaded. So all input fields receive the correct values AFTER the template is already loaded. So the input fields are empty for a second or two....
I think my resolve is not as it should be:
So my ui-router code looks something like this (check the resolve object):
$stateProvider.state('teststate', {
url: '/test/',
templateUrl: 'app/page/template.html',
controller: 'testCtrl',
resolve: {
access: ["Access", function(Access) { return Access.isAuthenticated(); }],
UserProfile: 'UserProfile'
}
});
Now the controller contains the promise to get some data from an API url:
function TestCtrl($scope, $state, $stateParams, TestService) {
TestService.get($stateParams.id).then(function(response) {
$scope.data = response;
});
}
Now the service (which connects to the API) should return the promise to the Controller:
TestService.factory('TestService', ['Restangular', function(Restangular) {
var factory = {};
factory.get = function(id) {
return Restangular.one('api/test', id).get();
}
return factory;
}]);
Now, could the problem be, that because the TestService.get() (which connects to the API) within the Controller, gets executed NOT before the template is loaded, because it's not inside the resolve object? So the UI router doesn't resolve the call to the API? I'm just curious or I should move all methods which make API calls, to the resolve object of each stat inside the $stateProvider.
I could run a lot of tests, but if someone just directly knows the answer by just looking at this question, it helps me a lot.
Your assumptions are all correct.
If you resolve the TestService.get in routing config the data would be readily available to controller as an injectable resource
If you don't want your controller to run and your template to show before all your API calls are finished, you have to put all of them inside ui-routers resolve.
However, if API requests can take a little while it seems better UX to transition to the new page immediately and show some kind of loading indicator (e.g. block-ui) while your API call is running.

How to update data on entering state in AngularJS UI-Router?

I'm using UI-Router for AngularJS and here is the question - at the moment when I'm clicking a link which sends me to specific state (using ui-sref) I want to send AJAX request to back end, get data, and render them in the template related to this new state. To which event should I listen for making AJAX request? Could you please give me a code example for this listener? I understand that the question seems to be simple, but I'm new in AngularJS world.
Thank you.
Have a look at the resolve property on your state configuration. See ui-router wiki
Then inject the resolved property as a dependency of the controller.
Example:
$stateProvider.state('about', {
templateUrl: 'about.html',
controller: 'AboutController',
resolve: {
something: function ($http) {
// make ajax request
return $http.get(...).then(function (response) {
return response.data;
});
}
}
})
In the controller, we inject the data that will be resolved, i.e. something :
app.controller('AboutController', function (..., something, ...) {
// The data resolved by ui-router is ready when the controller is instantiated
}

Waiting for XHR to finish in AngularJS before rendering template

When switching Views in AngularJS (from #1 to #2), I am sending two XHR requests to the server. One of them is finished quicker and as soon as it is, the template gets rendered. However, in the template I'm referring to data that comes back from the second request, which at that time is not finished yet.
Is there a way that I can wait for all requests to finish before rendering the template?
Currently I'm simply defining methods in the controller and then at its bottom, executing the XHR requests and assigning the response to $scope variables.
If you're using the $compile directive to render your HTML-Templates dynamically, you could add
ng-show="showCtrl"
And in your controller preset
$scope.showCtrl = false;
If you have the standard route provider, wrap your HTML-Template with a DIV e.g.
<div style="display:none" or ng-show="showCtrl">
If your XHR Request is finished, just take the DIV-Element with attribute and say
display:block or
showCtrl = true; $scope.$apply();
Greetings
You should be using the promise service
Please refer to
https://docs.angularjs.org/api/ng/service/$q
I'd say the best way to handler this is to use a resolve on your router.
If you are using the default Angular router, see the docs here: https://docs.angularjs.org/api/ngRoute/provider/$routeProvider, specifically the resolve property of the route definition. It allows you to specify any async calls that will be completed before the route changes and the next view is loaded.
If you use angular-ui-router, there is the exact same concept there.
Here is an example of using resolve from the angular docs:
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/Book/:bookId', {
templateUrl: 'book.html',
controller: 'BookController',
resolve: {
// I will cause a 1 second delay
delay: function($q, $timeout) {
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise;
}
}
});
});
Obviously they have a fake async call here with a timeout, but as long as your XHR call returns a promise (which will be the case if you use the $http service), then your controller can just be injected with delay in this case, and use the resolved data straight away.

Resources