Preloading data before navigation ensures that the required data is available before rendering a new route. This improves performance and prevents UI flickering due to missing data. In AngularJS, we can achieve this using resolve
in $routeProvider.
1. Why Use Data Preloading?
✔ Prevents UI flickering – Ensures all required data is loaded before the page is displayed.
✔ Improves User Experience – No need to show a loading spinner every time.
✔ Reduces API Calls – Data is fetched once and used throughout the route lifecycle.
2. Using $routeProvider.resolve
for Preloading Data
AngularJS provides the resolve
property in $routeProvider
, which ensures data is fetched before loading the route.
Step 1: Configure Route with resolve
Modify your app.config
to include a resolve
function:
var app = angular.module("myApp", ["ngRoute"]);
app.config(["$routeProvider", function($routeProvider) {
$routeProvider
.when("/users", {
templateUrl: "users.html",
controller: "UsersController",
resolve: {
userData: function(UserService) {
return UserService.getUsers(); // Fetch users before loading the route
}
}
})
.otherwise({
redirectTo: "/"
});
}]);
How It Works:
- Before navigating to
/users
,UserService.getUsers()
is executed. - The route will load only after the API call is completed.
Step 2: Create a Service for API Calls
Define a UserService
to fetch data from an API:
app.service("UserService", ["$http", function($http) {
this.getUsers = function() {
return $http.get("https://jsonplaceholder.typicode.com/users")
.then(response => response.data)
.catch(error => console.error("Error fetching users:", error));
};
}]);
Why Use a Service?
- Centralizes API calls, making the app more modular.
- Prevents redundant code in controllers.
Step 3: Inject Preloaded Data into the Controller
Since resolve
returns the data to the controller, we inject userData
into UsersController
:
app.controller("UsersController", ["$scope", "userData", function($scope, userData) {
$scope.users = userData; // Preloaded data is assigned to $scope
}]);
How It Works:
- The controller receives
userData
fromresolve
. $scope.users
is populated before rendering the page.
3. Showing a Loading Indicator
If data fetching takes time, display a loading spinner:
Modify the Controller
app.controller("UsersController", ["$scope", "userData", function($scope, userData) {
$scope.isLoading = true;
userData.then(function(data) {
$scope.users = data;
$scope.isLoading = false;
});
}]);
Update the View (users.html
)
<div ng-if="isLoading">Loading users...</div>
<ul ng-if="!isLoading">
<li ng-repeat="user in users">{{ user.name }}</li>
</ul>
Now, users will be displayed only after the data is loaded.
4. Alternative Approach Using $rootScope
Events
Another way to handle preloading is to use $rootScope.$on("$routeChangeStart")
:
app.run(["$rootScope", function($rootScope) {
$rootScope.$on("$routeChangeStart", function(event, next, current) {
console.log("Route change started to:", next.$$route.originalPath);
});
$rootScope.$on("$routeChangeSuccess", function() {
console.log("Route successfully changed.");
});
}]);
Use this method for debugging and tracking route changes.
5. Summary
Approach | Pros | Cons |
---|---|---|
$routeProvider.resolve | Ensures data is available before route loads | Initial load may be slow |
$rootScope.$on("$routeChangeStart") | Can track route changes globally | Does not wait for data to load |