There are 6 main traps when using scope in Angularjs. If you understand the concept behind Angularjs, these 6 points are actually very simple. But let's talk about two other concepts before we go into these 6 traps.
Concept 1: Bidirectional data binding
Bidirectional data binding is a very important part of ANGULARJS. The general bindings are very familiar to us. Even if you have not heard of bidirectional data binding, you must have used it.
Common bindings are typically used for data data, which is actually a basic concept of the template engine:
Hello {{username}}
If the variable username is set to John Doe, the above example will be rendered as:
Hello John Doe!
This is the first direction of two-way data binding. You can view the details of the ng-bind in the documentation.
This feature is sufficient in the template because the template is used to output the content. However, you can still use bidirectional data binding to handle user input when building the user interface using HTML. Here is an example:
<input ng-model=‘username‘><p>Hello {{username}}</p>
Only if the framework itself supports reverse binding, the above example can run normally without any additional magic (network onkeyup or Onchang events!). )。
This is the second direction of two-way binding. You can view the details of the Ng-model in the documentation.
If you use two directions together, you've already used two-way data binding in Angularjs, which will be able to consolidate data from the view to the model.
And the source of the data in the binding, we call scope (scope).
Unlike other data-binding frameworks, Angularjs does not wrap objects in accessors, which is why you do not need to define an object that contains a specific getter and setter. Out of some of these features (like $broadcast, $apply, $digest, $emit, and $watch) and references (like $parentscope), the scope is basically a generic object that contains some properties and values. You can access data in scope as you would a normal object, and the changes that occur in the scope are not recognized by the scope itself. Any change requires the use of the $apply method to invoke a digest loop. However, you do not need to pay attention to this matter unless you specifically specify it.
Sometimes it is not appropriate to call a digest loop every time a change occurs because it is bound to affect the performance of the application. A chat client, for example, will add some specific information to the scope every second. To keep your app from getting slow, you'd better limit the number of digest loops. In short, using the $scope. $apply () method to implicitly invoke the digest loop in Angularjs will run all the expressions and monitors in the template.
Concept 2: Declarative UI
In Angularjs, one of the rules you need to follow is "create a reusable component directive to extend your HTML" because it keeps the reusability of your code.
Because you're probably a jquery developer, you're probably already familiar with the "jquery" style of development, such as how to add CSS styles (the addclass () function) and the hidden Elements (hide () function). Such a method is called imperative:
You explicitly tell the computer that you want to run the code in a specific environment, such as wrapping the code in an if statement.
The method used by Angularjs is declarative:
You need to declare in the view how to display a specific environment.
Suppose you now have a navigation list that contains some items. If an item is selected, the project should add a class called Active.
In the following example, the first item is marked as active:
<ul class="Navigation"><li class= "item Item1 active" >item 1< Span class= "token operator" ></li> <li Class=" item item2 ">item 2< /li> <li Class= "item Item3" >item 3</li ><ul>
jquery programmatically removes all active classes first and adds the active class on one of the items. But on what project should we add the active class? You have to provide an additional binding in JavaScript to decide which item to add the class to, possibly an extra class or some data-property.
Let's see what Angularjs should do:
<ul class= "navigation" > <li ng< Span class= "token operator" >-repeat= "item in items" class< Span class= "token operator" >=-class=" {' active ': item.id = = Activeitem} ">< Span class= "token punctuation" >{{item.title}}</li></ Ul>
For the code to work, we need to add the following to the scope:
$scope. Activeitem=' Item1 '; $scope. Items=[{ID: ' item1 ' : ' Item 1 ' } {id ' item2 ' ' Item 2 ' }{id: ' item3 ' Title: ' Item 3 ' } ]
First, this example uses the Ng-repeat directive, which iterates through all items in items and creates HTML elements in the same order. In this example, three elements are created <li> .
The Ng-class directive declares when the active class should be used. This class is only added when the Item.id==activeitem result is true. Since we have two-way data binding, the label changes automatically when you change $scope.activeitem to item2. You don't need to write any code to modify your business logic. In Angularjs, the behavior should be described in the template.
This means that you can easily create tab bars, slide buttons, auto-scroll areas, drag-and-drop windows, or a contextual menu using declarative methods.
After discussing the two-way data binding in Angularjs and the declarative UI, let's look at the problems you'll encounter when using these technologies.
Traps 1:scope digester and expressions
When using an expression in a view or monitor, you should always remember that the expression is always called whenever Angularjs deems it necessary. Therefore, you may not be able to get the performance of the function, and you may even miss some change events.
This means that:
- An expression with a ng-repeat will invoke each item separately. In addition, ANGULARJS will use the Repeat directive to determine the data changes.
- An expression may be valued multiple times in a digest loop (evaluation). This happens when you use more than one instruction or if you have an extra action on the monitor.
- Even if the scope does not change, it is still valued.
- If the expression contains a function, the expression is not valued when the return value of the function changes. However, when the definition of a function changes, it is valued.
For example, we have an expression: stat = = = GetUserState (). There are several possible scenarios:
- The function simply returns scope.currentuserstate: At this point we can discard the function and use the data directly. This type of expression will be gradually optimized in the future.
- This function will perform some business logic calculations: Each time the expression is valued, the logic will run. A better approach is to calculate and write the current user state in the scope. This method can decouple the logic from the user state and view. In general, data is scope, and scope is data.
- The function gets the data from outside the scope: This method is very, very bad. Scope/angularjs are not notified when changes occur. Remember that only when Angularjs thinks the scope has changed does it invoke a digest loop and all expressions are affected.
Sometimes, the second and third situations occur simultaneously.
If you use external data (or data changes) – for example, an external jquery plugin will change the state – you must provide this data for the scope. Given a directive, you might have a callback function that can access the current scope. You may notice that any changes on the scope will not update any UI, because Angularjs will not notice that the scope has changed.
However, you can call the $scope. $apply () function in Angularjs, which will call all digest loops, monitors, and related data estimates.
Still, you should try to avoid using $apply () or its brother $digest (). In addition to real external events (jquery callbacks, browser event callbacks, and so on), you might implement the wrong code schema.
Note that if you call a digest/apply in a running Digest loop, you may encounter errors such as "Digest already in progress". This is also why the function should be avoided in an expression.
The following code is a common error-using function method:
<ul> <li Ng-repeat= "item in LoadItems ()" >{{item.title}}< /li></ul>
The problem here is that a loaditems () function is called. This expression will not be correctly valued: the instruction itself adds some raw data to the model to determine which items in the list should be added, removed, or simply moved. The recommended practice is to use arrays in ng-repeat. Tell yourself: Call LoadItems is imperative, we should declare the given data.
Best Practices:
- Do not use a function in an expression.
- Do not use data outside the scope of an expression.
- Use $scope. $apply () When applying external data changes.
Using these best practices will enable you to get efficient code without missing events.
Trap 2: Referencing a DOM element
The use of DOM elements in directives is correct. They can be stored in a variable. But never store DOM elements in the scope again.
Dom elements are part of a huge DOM tree, and the nature of the DOM tree is that it knows its own parent elements, child elements, and sibling elements. If you are intent on storing a DOM element in the scope, the scope Digest loop will look for itself and its parent element and parent element. This means that digest will check the entire DOM tree to find the parts that are changing. If you think it's not crazy enough, there's something scarier: Because each DOM element has an extra reference, the digest loop will traverse the entire DOM tree more than once.
You don't do it like this, because it's crazy.
Best Practices:
- Do not store DOM elements in the scope, which causes a memory leak.
Trap 3: Use DOM elements outside the instruction
Do not use DOM elements outside the directive. Many services can easily produce a DOM tree because they are usually single, global, and stateless instances, like an instance of a rest API.
A DOM reference in a controller will box a missed instruction or some missed behavior.
The real case is that extracting a DOM reference from a controller into one instruction is very resource-intensive. But if you understand the problem and its impact, but still want to do so, it doesn't matter. But you're going to meet soon. The fact is that the controller binds to a specific template, and DOM changes caused by the controller will not be reflected in the scope and view of the Angularjs.
Best Practices:
- Do not get DOM elements outside the directive because the instructions can decouple the controller, the service, and the DOM. So we get more flexibility and the code is easier to test and use.
Trap 4: Do not use the built-in method
I mentioned earlier the use of $apply () and $digest () and their effects. If many external events require additional $apply () calls, it will cause a lot of trouble. So I suggest you go deep into the Angularjs document and use some built-in instructions, such as using $timeout () instead of window.timeout (), which implicitly calls $rootscope. $apply ().
You should use the built-in $http method instead of the external XHR wrapper, which will return a $q promise. Any callback function that executes this promise will call $rootscope. $apply (). Some modules that return $Q promise will implicitly call $rootscope. $apply ().
Best Practices:
- Use built-in directives because they allow you to write simple and friendly code.
Trap 5: Confusing "current scope"
The hierarchical hierarchy of scopes is very clever, but if you don't understand it deeply, you'll be miserable. In your root scope you can define some global global variables that will be available in all the self-scopes (except for the isolation scope) – The prototype inheritance will "find" these properties. In the DOM you can also define scopes in a common controller to share the data.
But here's a block: it can only run on a unilateral. But that's good, because you don't want to expose data from a local scope to another scope.
<span>outside Controller: Your name is:{{username}}</span><div ng-controller="Signupcontroller"><span>inside Controller: Your name is{{username< Span class= "token punctuation" >}}</span> <fieldset Legend=> <input Ng-model= "username" > </fieldset></div>
Attempts to change the value in input, which can run normally but only for internal bindings. The value of the binding outside the controller will not change. Why is this? The answer exists in "What is my current scope?" In
For example, we have two scopes: the overall rootscope scope and a scope implicitly created by the controller (here is Signupcontroller).
When you enter a new value in the input field. The current scope is assigned a new property called username. Because the scope of the controller that contains the input field is exactly the current scope, this property is also assigned to the scope. Just like the prototype inheritance in JavaScript, this means that this property is not available in the parent scope. Because we know this thing, all this is very well understood.
You might think: I've defined an initial value! You can try it, but it still doesn't work because the data is still stuck in the current scope just like a string. If you assign $rootscope.username to "", you will end up with two properties called username, one in the root scope and the other in the controller we write.
To solve this problem, you should use a well-packaged model. In other words, you should use '. ' In the model.
Make some changes to the example above: Use User.Name instead of username.
<span>outside Controller: Your name is:{{User. Name}}</span><div ng-controller="Signupcontroller"><span>inside Controller: Your name is:{{user.name< Span class= "token punctuation" >}}</span> <fieldset Legend=> <input Ng-model= "User.Name" > </fieldset></div>
Data binding is now assigned to the User.Name. Because if the user object is not found under the current scope, the $rootScope. User is implicitly read, so this problem is resolved. It can also help you to structure your model. This is really a win and a winning approach.
But you'll still find it easy to make mistakes because there are many built-in ANGULARJS instructions-or instructions you create yourself-that create your own sub-scopes. For example, the following commands:
- Ng-controller: A controller has its own scope (because it assigns behavior in scope).
- Ng-form: A special form controller will be used, resulting in a new scope. Note:
<form> an instance of Ng-form is created.
- Ng-repeat: Each project has its own sub-scope (because ' item ' is the content of the loop).
- Ng-switch: Changed the DOM so it has its own scope.
- Ng-view: More or less irrelevant, because you always specify a controller under Ng-view.
Best Practices:
- To avoid problems with unstructured content and the scope context of the error and implicitly generated scopes using directives, do not bind an unbound data to an unpackaged object.
Trap 6: jquery is not used correctly
ANGULARJS implements a subset of jquery jqlite. Its basic operation is very similar to jquery, however, it is not a complete jquery. If you need to use the full jquery implementation, you need to load jquery before Angularjs is loaded. Only in this way can angularjs skip jqlite and use jquery. Otherwise both will be loaded in, Angularjs use Jqlite, and other parts use jquery.
Best Practices:
- Load jquery before Angularjs.
Summarize
This article provides 6 pitfalls that are often encountered by Angularjs's primary developers. If you have previously used jquery, you should remember that you should use declarative methods rather than imperative methods in Angularjs. If you try to follow the path of jquery, you are doomed to fail in Angularjs.
Try to understand the scope as the place to get the data, and if you try to get data from somewhere else, there will eventually be a problem.
Use the best practices mentioned above and make sure you explore the API documentation as you write your ANGULARJS application. Correct use of the features therein.
Make sure you have the right decoupling for your application: using commands, controllers, services, and templates. Obviously you don't need to spread the code across many components and use the framework to suit your needs.
If you have followed these rules, you will be able to enjoy programming in ANGULARJS.
This article is translated from angularjs:6 Common pitfalls Using Scopes, the original address http://thenittygritty.co/angularjs-pitfalls-using-scopes
Go AngularJS: 6 Traps when using scope