⬆️ ⬇️

Several useful tricks for beginners in AngularJS

When creating applications on AngularJS, a novice developer has a lot of questions, especially if, until a certain time, he used libraries similar to jQuery or Prototype. In this post I would like to share some tricks that would be useful for novice AngularJS developers.



Application download and state manager



Until the moment the framework is loaded, its dependencies and the processing of all requests in the background, the application can look very depressing. And even ng-cloak will not be able to help in most cases. Usually for such purposes a div is used that has a larger z-index than the main content of the site and overlaps it before loading all the components and states. It might look like this:



<div class="loader" ng-show="loader"><div class="loader-content">Loading...</div></div> 




and his styles are like this:

')

  .loader { position: fixed; width: 100%; height: 100%; z-index: 9; } .loader-content { width: 128px; height: 128px; overflow: auto; margin: auto; position: absolute; z-index: 10; top: 0; left: 0; bottom: 0; right: 0; } 


In AngularJS, we will use the loader variable, which will be in $ rootScope, and depending on its value, our div will be hidden or displayed in the browser window. Constantly changing the value of a variable in $ rootScope is rather inconvenient, while we may have several operations that will be performed at the same time, and at that moment when one of them works, the second one may not finish its work. In this case, the bootloader will disappear.



To avoid such cases, you can create a service that will be responsible for storing all the states, and depending on whether there are any operations in operation, control the value of $ rootScope.loader. In its simplest form, it can be described as follows:



 'use strict'; app.factory('StateManager', function StatemManager($rootScope, $log) { var stateContainer = []; return { add: function (service) { stateContainer.push(service); $rootScope.globalLoader = true; $log.log('Add service: ' + service); }, remove: function (service) { stateContainer = _.without(stateContainer, service); $log.log('Remove service: ' + service); if (stateContainer.length === 0) { $rootScope.globalLoader = false; $log.log('StateContainer is empty.'); } }, getByName: function (service) { return _.include(stateContainer, service) }, clear: function () { stateContainer.length = 0; $log.log('StateContainer clear.'); return true; } } }); 


This example uses the underscore library. Simply put, this service writes the transferred process name to an array and deletes it upon request. If the array is empty, $ rootScope.loader is set to false. And an example of use:



 StateManager.add('Load_json_data'); var request = $http.get('/data.josn'); request.success(function(response) { console.log(response); StateManager.remove('Load_json_data'); }); 




Of course, this is not an ideal option, but to understand how it works, it’s sufficient.



Receive events



There are situations when we need to receive an event or an element from the controller function by, say, ng-click . Of course, for these purposes it is better to use directives, but anything happens. Fortunately, we have $ event at our disposal:



 <ul> <li ng-repeat="name in names" ng-bind="name" ng-click="setActive($event);"></li> </ul> 




 $scope.names = ['John', 'Peter', 'Joe']; $scope.setActive = function (evt) { angular.element(evt.target).addClass('active'); } 


In this case, when you click on an element from the list, it will receive the class active. Essentially, angular.element is jqLite and allows you to use the very methods that jQuery lovers are used to.



AngularJS and PHP



Many newbies to AngularJS are surprised that php cannot process the POST request sent to it. He simply does not see him. Everything is explained very simply. As the developers themselves say, AngularJS is sharpened for Ruby on Rails, so data is serialized in JSON format, incomprehensible to php. There is an excellent article describing how to get rid of this problem. In case you want to make jQuery.ajax work for the $ http service, you will need to include the following code in your AngularJS application:



Javascript code
 angular.module('MyModule', [], function($httpProvider) { // Use x-www-form-urlencoded Content-Type $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'; // Override $http service's default transformRequest $httpProvider.defaults.transformRequest = [function(data) { /** * The workhorse; converts an object to x-www-form-urlencoded serialization. * @param {Object} obj * @return {String} */ var param = function(obj) { var query = ''; var name, value, fullSubName, subName, subValue, innerObj, i; for(name in obj) { value = obj[name]; if(value instanceof Array) { for(i=0; i<value.length; ++i) { subValue = value[i]; fullSubName = name + '[' + i + ']'; innerObj = {}; innerObj[fullSubName] = subValue; query += param(innerObj) + '&'; } } else if(value instanceof Object) { for(subName in value) { subValue = value[subName]; fullSubName = name + '[' + subName + ']'; innerObj = {}; innerObj[fullSubName] = subValue; query += param(innerObj) + '&'; } } else if(value !== undefined && value !== null) { query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&'; } } return query.length ? query.substr(0, query.length - 1) : query; }; return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data; }]; }); 




Caching ($ cacheFactory)



Not even the newbies neglect this service. Suppose you have a controller that, when switching to a specific route, makes a POST request and receives data about the artist's albums:



 var request = $http.get('/albums.json'); request.success(function (response) { $scope.albums = response; }); 


The fact is that if the user clicks on another link, and then comes back, our code will be executed again, and the request for albums will be sent again. Quite often there is no need to use repeated requests to the server after downloading the entire application. There can be many situations. This is what $ cacheFactory is for. Let's try to create a simple cache service:



 app.factory('DataCache', function ($cacheFactory) { return $cacheFactory('dataCache', {}); }); 


and use it in our controller:



 app.controller('AlbumsCtrl', function (DataCache) { var $scope.albums = DataCache.get('albums'); if (!$scope.albums) { var request = $http.get('/albums.json'); request.success(function (response) { DataCache.put('albums', response); $scope.albums = response; }); } }); 




Now, if there is data in the cache, the album request will not be fulfilled.



Conclusion



These techniques do not claim to truth in the first instance. I would be glad to see in the comments your ways other than those proposed by me.

Source: https://habr.com/ru/post/197762/



All Articles