AngularJS developers often make 10 mistakes: angularjs developers

Source: Internet
Author: User

AngularJS developers often make 10 mistakes: angularjs developers
Mark Meyer is a full stack software engineer with more than one year of experience in angular. js development. Mark has development experience in multiple languages, from C-based server applications, Rails-based web applications, to IOS applications developed using Swift.

Introduction AngularJS is currently one of the most popular Javascript frameworks. One of AngularJS's goals is to simplify the development process, which makes it very good at building small app prototypes, however, it can also be used to develop client applications with comprehensive functions. It is easy to develop and has extensive features and outstanding performance. However, many common traps also come along. The following lists some common AngularJS misoperations, especially during app scale expansion.
1. the MVC directory structure AngularJS is precisely an MVC framework. Its model is not as clear as that of backbone. js, but its architecture still complements each other. When using an MVC framework for development, the common practice is to classify it based on the file type:
Templates/
_Login.html
_Feed.html
App/
App. js
Controllers/
LoginController. js
FeedController. js
Directives/
FeedEntryDirective. js
Services/
LoginService. js
FeedService. js
Filters/
CapatalizeFilter. js
This seems to be an obvious directory structure, especially Rails. However, once the app scale begins to expand, this structure will lead to opening many directories at a time. Whether using Sublime, Visual Studio, or Vim combined with the Nerd Tree, it takes a lot of time to scroll up and down the directory Tree.
Do not organize files by type, but by features:
App/
App. js
Feed/
_Feed.html
FeedController. js
FeedEntryDirective. js
FeedService. js
Login/
_Login.html
LoginController. js
LoginService. js
Shared/
CapatalizeFilter. js
This directory structure makes it easier for us to find files related to a specific feature to speed up development. Putting .html and. js files together may be controversial, but the time saved is more valuable.
2. It is common to put everything under the main module at the beginning of a module (or without a module. For small apps, there was no problem at the beginning, but it soon became difficult to manage.

var app = angular.module('app',[]);app.service('MyService', function(){    //service code});app.controller('MyCtrl', function($scope, MyService){    //controller code});
After that, the common method is to organize code by object type.
var services = angular.module('services',[]);services.service('MyService', function(){    //service code}); var controllers = angular.module('controllers',['services']);controllers.controller('MyCtrl', function($scope, MyService){    //controller code}); var app = angular.module('app',['controllers', 'services']);
This method is similar to the directory structure mentioned in the first part: Not good enough. Similarly, it can be divided by feature, which is easy to expand.
var sharedServicesModule = angular.module('sharedServices',[]);sharedServices.service('NetworkService', function($http){}); var loginModule = angular.module('login',['sharedServices']);loginModule.service('loginService', function(NetworkService){});loginModule.controller('loginCtrl', function($scope, loginService){}); var app = angular.module('app', ['sharedServices', 'login']);
When developing a large application, it is impossible to include everything on a page. Dividing modules by feature makes it easier to reuse modules between applications.
3. Dependency injection dependency injection is one of the best AngularJS models. It makes the test easier and the dependency relationship clearer. AngularJS injection is very flexible. The simplest method is to pass the name of the dependent person into the function of the module:
var app = angular.module('app',[]); app.controller('MainCtrl', function($scope, $timeout){    $timeout(function(){        console.log($scope);    }, 1000);});
Obviously, MainCtrl depends on $ scope and $ timeout.
Everything works before you deploy it to the production environment and compress the code. However, if UglifyJS is used, the previous example will become as follows:
Var app = angular. module ("app", []);
App. controller ("MainCtrl", function (e, t) {t (function () {console. log (e)}, 1e3 )})
How does AngularJS know who MainCtrl depends on? AngularJS provides a very simple solution, that is, to pass in dependencies as a string array. The last function of the array contains all dependencies as its parameters.
app.controller('MainCtrl', ['$scope', '$timeout', function($scope, $timeout){    $timeout(function(){        console.log($scope);    }, 1000);}]);
In this way, AngularJS will be able to clearly understand how to interpret these dependencies:
app.controller("MainCtrl",["$scope","$timeout",function(e,t){t(function(){console.log(e)},1e3)}])
3.1 When compiling AngularJS applications, global dependencies often bind a depended object to the global scope. This means that this dependency is available in any AngularJS code, but it destroys the dependency injection model and causes some problems, especially during testing.
AngularJS can easily encapsulate these global objects into modules so that they can be injected like standard AngularJS modules.
Underscrore. js is a great library that simplifies Javascript code in a functional style. You can convert it into a module in the following ways:
var underscore = angular.module('underscore', []);underscore.factory('_', function() {  return window._; //Underscore must already be loaded on the page});var app = angular.module('app', ['underscore']); app.controller('MainCtrl', ['$scope', '_', function($scope, _) {    init = function() {          _.keys($scope);      }       init();}]);
This allows the application to continue development in AngularJS dependency injection style, while replacing underscore during the test phase.
This may seem trivial and unnecessary, but if your code is using use strict (and should be used !), That is necessary.
4. Controller expansion Controller is the most basic part of AngularJS. When you accidentally put too much logic into it, especially at the beginning. The Controller should never operate the DOM or hold the DOM selector, which is the use of directive and ng-model. Similarly, the business logic should exist in the service, rather than the controller.
Data should also be stored in the service unless they have been bound to $ scope. The Service itself is a singleton and exists in the entire life cycle of the application. However, the controller is transient between various States of the application. If the data is stored in the controller, it needs to be retrieved from somewhere again when it is instantiated again. Even if data is stored in localStorage, the retrieval speed is an order of magnitude slower than that from Javascript variables.
AngularJS runs well in compliance with the single responsibility principle (SRP. If the controller is the coordinator between views and models, it should contain as few logic as possible. This also makes the test easier.
5. Service vs Factory these two terms make almost every AngularJS developer confused at the beginning. This is really not the case, because they are just the syntactic sugar of (almost) the same thing!
Their definitions in AngularJS Source Code are as follows:
function factory(name, factoryFn) {     return provider(name, { $get: factoryFn }); } function service(name, constructor) {    return factory(name, ['$injector', function($injector) {      return $injector.instantiate(constructor);    }]);}
From the source code, you can see that the service only calls the factory function, and the factory calls the provider function. In fact, AngularJS also provides some additional provider encapsulation, such as value, constant, and decorator. However, this does not cause confusion to a similar extent, and their documents are clearly stated in the application scenarios.
Since the service only calls the factory function, what is the difference between the two? The clue is in $ injector. instantiate; in this function, $ injector creates a new instance in the service constructor.
The following is an example of how a service and a factory accomplish the same thing:
var app = angular.module('app',[]); app.service('helloWorldService', function(){    this.hello = function() {        return "Hello World";    };}); app.factory('helloWorldFactory', function(){    return {        hello: function() {            return "Hello World";        }    }});
When helloWorldService or helloWorldFactory is injected into the controller, they all have a hello method and return "hello world ". Service constructor is instantiated once during declaration, while the factory object is passed once every injection, but there is still only one factory instance ..

Since we can do the same thing, why do we need two different styles? Compared with the service, factory provides more flexibility because it can return functions, which can be new later. This follows the factory mode in object-oriented programming, and the factory is an object that can create other objects.

app.factory('helloFactory', function() {    return function(name) {        this.name = name;         this.hello = function() {            return "Hello " + this.name;        };    };});

Here is an example of controller using service and two factories. HelloFactory returns a function. When new is used, the value of name is set.
app.controller('helloCtrl', function($scope, helloWorldService, helloWorldFactory, helloFactory) {    init = function() {      helloWorldService.hello(); //'Hello World'      helloWorldFactory.hello(); //'Hello World'      new helloFactory('Readers').hello() //'Hello Readers'    }     init();});
At the beginning, it is best to use only service.
Factory is also useful when designing a class that contains many private methods:
app.factory('privateFactory', function(){    var privateFunc = function(name) {        return name.split("").reverse().join(""); //reverses the name    };     return {        hello: function(name){          return "Hello " + privateFunc(name);        }    };});
In this example, the public API of privateFactory cannot directly access privateFunc. This mode can be implemented in service, but it is more intuitive in factory.
6. Not using BatarangBatarang is an outstanding Chrome plug-in for developing and debugging AngularJS applications.
Batarang provides the ability to browse the model, so that you can observe how AngularJS determines the model bound to the scope. This is useful when observing the binding values of directive and isolate scopes.
Batarang also provides a dependency graph. If an untested code library is used, this dependency graph can be used to determine which services should be focused.
Finally, Batarang provides performance analysis. AngularJs has good performance. However, it is sometimes not smooth enough for more and more custom direve VE and complex logic applications. Using the Batarang performance tool, you can easily see which function has the longest running time in a digest cycle. This tool can also display a complete watch tree, which is useful in many watcher scenarios.
7. As mentioned above, AngularJS has good performance. Because dirty data check is required in a digest cycle, once the number of watcher instances increases to about 2000, this cycle produces significant performance problems. (The value 2000 does not necessarily result in a sharp drop in performance, but it is a good empirical value. In AngularJS 1.3 release, there have been some changes that allow strict control of the digest cycle. Aaron Gray has a good article on this issue .)
The following "function expression for immediate execution (IIFE)" will print the number of all watcher instances on the current page. You can simply paste them into the console and observe the results. This IIFE comes from Jared's answer on StackOverflow:
(function () {     var root = $(document.getElementsByTagName('body'));    var watchers = [];     var f = function (element) {        if (element.data().hasOwnProperty('$scope')) {            angular.forEach(element.data().$scope.$$watchers, function (watcher) {                watchers.push(watcher);            });        }         angular.forEach(element.children(), function (childElement) {            f($(childElement));        });    };     f(root);     console.log(watchers.length);})();
In this way, we can get the number of watcher instances. Combined with the watch tree of the Batarang performance part, we should be able to find out where duplicate code exists or which unchanged data has watch.
If you want to use AngularJS to template unchanged data, you can use bindonce. Bindonce is a simple command that allows you to use templates in AngularJS. However, it does not increase the number of watches, avoiding the increase in the number of watches.
8. determine the scope of $ scope Javascript prototype-based inheritance is slightly different from class-based inheritance in object-oriented systems. This is usually not a problem, but it is displayed when $ scope is used. In AngularJS, each $ scope inherits the parent $ scope, and the top level is $ rootScope. ($ Scope is somewhat different when used in directive. isolate scopes only inherits explicitly declared attributes .)
Because of prototype inheritance, it is not important to share data between parent classes and child classes. However, if you are not careful enough, it is easy to overwrite the attributes of the parent $ scope.
For example, we need to display a user name in the navigation bar, which is entered in the login form. The following attempts should work:
<div ng-controller="navCtrl">   <span>{{user}}</span>   <div ng-controller="loginCtrl">        <span>{{user}}</span>        <input ng-model="user"></input>   </div></div>
Q: The ng-model of the user is set in text input. Which template will be updated when the user inputs the content? NavCtrl or loginCtrl?
If you select loginCtrl, you may have understood how prototype inheritance works.
The prototype chain does not work when you retrieve the literal value. If navCtrl is also updated, the retrieval prototype chain is required. However, if the value is an object, this will happen. (Remember, in Javascript, functions, arrays, and objects are all objects)
Therefore, to obtain the expected behavior, you need to create an object in navCtrl, which can be referenced by loginCtrl.
<div ng-controller="navCtrl">   <span>{{user.name}}</span>   <div ng-controller="loginCtrl">        <span>{{user.name}}</span>        <input ng-model="user.name"></input>   </div></div>
Now, because the user is an object, the prototype chain will take effect, and the navCtrl template and $ scope will be updated together with loginCtrl.
This example is a bit stubborn, but when you use directive to create a sub-$ scope, such as ngRepeat, this problem will easily occur.
9. Manual testing because TDD may not be a preferred development method for every developer, when the developer checks whether the code works or whether it affects other things, they perform manual testing.
It makes no sense not to test AngularJS applications. AngularJS is designed to make it completely measurable. The dependency injection and ngMock modules are evidence. AngularJS's core team has developed a number of tools that can bring tests to the next level.
9.1 The unit test of Protractor is the foundation of the test suite, but given the increasingly complex app, integration testing is forced to be more realistic. Fortunately, AngularJS's core team has provided necessary tools.
We have created a Protractor, an end-to-end Tester Used to simulate user interaction, which can help you verify the health status of your AngularJS program.
Protractor uses the Jasmine testing framework to define a test. Protractor has a very robust API for different page interactions.
There are other end-to-end testing tools, but the advantage of Protractor is that it can understand how to work with AngularJS Code, especially in the $ digest cycle.
9.2 Karma once we use Protractor to complete the compilation of the integration test, the next step is to execute the test. Waiting for testing, especially integration testing, is a pain for every developer. AngularJS's core team felt the same, so Karma was developed.
Karma is a Javascript test execution tool that helps with closed-loop operations. Karma can do this because it runs the test when the specified file is changed. Karma can also perform tests concurrently on multiple browsers. Different devices can also point to the Karma server to better cover real application scenarios.
10. Use jQuery
JQuery is a magic library that standardizes cross-platform development and has almost become a necessity for modern Web development. However, despite the many excellent features of JQuery, its philosophy is different from that of AngularJS.
AngularJS is a framework used to build applications, while JQuery is a library that simplifies "HTML document traversal and operations, event processing, animation, and Ajax. This is the most basic difference between the two. AngularJS is committed to the application architecture and has nothing to do with HTML pages.
To better understand how to build an AngularJS program, please Stop using jQuery. JQuery allows developers to think about issues based on existing HTML standards, but as stated in the document, "AngularJS allows you to expand the HTML vocabulary for your applications ".
DOM operations should only be completed in directive, but this does not mean they can only be encapsulated with jQuery. Before using JQuery, you should first consider whether AngularJS has provided this function. It works quite well when directives are combined to create powerful tools.
This day may come, and a great JQuery is required, but it is a common mistake to introduce it at the beginning.

Conclusion AngularJS is a great framework that is constantly evolving in the community. AngularJS is still a concept of continuous development, but we hope that by following the conventions mentioned above, we can avoid some big traps when developing large-scale AngularJS applications.



Link: https://www.airpair.com/angularjs/posts/top-10-mistakes-angularjs-developers-make

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.