Delve into the super tutorials for scope objects in the ANGULARJS framework _angularjs

Source: Internet
Author: User
Tags object object

First, the problems encountered
The problem occurs when using Angularjs nesting Controller. Because each Controller has its corresponding scope (which corresponds to scope, control range), the nesting of Controller means the nesting of scope. What happens when you have a Model of the same name in two scopes at this time? How do you update the Model in the parent scope from the child scope?

This is a typical question, for example, if the current page is a product list, then you need to define a Productlistcontroller

function Productlistcontroller ($scope, $http) {
  $http. Get ('/api/products.json ')
    . Success (function (data) {
      $scope. productlist = data;
    });
  $scope. selectedproduct = {};
}

You've probably seen it. A selectedproduct model is also defined in Scope, indicating that a product is selected. The product details are obtained, and the page is automatically updated with the $routeProvider in the Angularjs, drawing a new detail page template with a Productdetailcontroller

function Productdetailcontroller ($scope, $http, $routeParams) {
  $http. Get ('/api/products/' +$ Routeparams.productid+ '. Json ')
    . Success (function (data) {
      $scope. selectedproduct = data;}
    );

Interesting thing happened, here also has a selectedproduct, how will it affect the selectedproduct in Productlistcontroller?

The answer is no effect. In Anuglarjs the scope does inherit objects from the parent scope, but when you try a two-way data binding for the base data type (string, number, Boolean), you find strange behavior, and inheritance doesn't work as you think. The property of a child scope hides (Overrides) a property of the same name in the parent scope, and changes to the Sub scope property (form Element) do not update the value of the parent scope property. This behavior is actually not angularjs specific, and JavaScript itself is the prototype chain that works. Developers are often unaware that ng-repeat, Ng-switch, Ng-view, and ng-include all create their new child scopes, so they often have problems with these directive.

Ii. Approaches to settlement
the solution is to not use the basic data type, and in the Model always add a point.

Use

<input type= "text" ng-model= "SOMEOBJ.PROP1" >

To replace

<input type= "text" ng-model= "Prop1" >

Is it a pit dad? The following example is a clear expression of what I want to say about the wonderful phenomenon

App.controller (' Parentcontroller ', function ($scope) {
  $scope. parentprimitive = "Some primitive"
  $ Scope.parentobj = {};
  $scope. Parentobj.parentproperty = "some value";
});
App.controller (' Childcontroller ', function ($scope) {
  $scope. parentprimitive = "This would not modify the parent"
  $scope. Parentobj.parentproperty = "This'll modify the parent";
});

View Demo Demo Online
But I really very, very much need to use the original data types such as string number how to do? 2 Methods-

Use $parent. Parentprimitive in the child Scope. This prevents the child Scope from creating its own properties.
Define a function in the parent scope, let the child scope call, pass the parameters of the original data type to the father, thereby updating the properties in the parent scope. (not always feasible)
third, the prototype chain of JavaScript inheritance
after the slot is over, let's take a closer look at the prototype chain of JavaScript. This is important, especially when you go from server-side development to the front end, you should be familiar with the classic class class inheritance, let's recap.

Suppose the parent class Parentscope has the following member properties astring, Anumber, Anarray, AnObject, and Afunction. The subclass Childscope prototype inherits the parent class Parentscope, so we have:

If the child scope attempts to access the attribute defined in Parentscope, JavaScript looks in the child scope first, and if it does not, finds its inherited Scope to get the property, and if the inherited prototype object Parentscope does not have the attribute, the Continue to look for it in its prototypes, from the prototype chain up until it reaches Rootscope. So, the following expression results are ture:

Childscope.astring = = ' Parent string '
childscope.anarray[1] = =
ChildScope.anObject.property1 = = ' Parent Prop1 '
childscope.afunction () = = ' Parent output '

Let's say we execute the following statement

childscope.astring = ' Child string '

The prototype chain is not queried, but instead adds a new attribute astring to the childscope. This new property hides (Overrides) an attribute of the same name in Parentscope. This concept is important when we discuss ng-repeat and ng-include below.

Let's say we perform this operation:

Childscope.anarray[1] = ' childScope.anObject.property1 '
= ' child Prop1 '

The prototype chain was queried because the objects Anarray and AnObject were not found in Childscope. They were found in the Parentscope and the values were updated. No new attributes were added to the Childscope, and no new objects were created. (Note: In JavaScript, array and function are objects)

Let's say we perform this operation:

Childscope.anarray = [MB, 555]
childscope.anobject = {name: ' Mark ', Country: ' USA '}

The prototype chain has not been queried, and the child Scope has added two new object properties, which hide (overwrite) The object attributes of the same name in Parentscope.

Should be able to summarize

If the Childscope.propertyx is read and the Childscope has attribute Propertyx, then the prototype chain is not queried.
If you set the Childscope.propertyx, the prototype chain will not be queried.
In the last case,

Delete Childscope.anarray
childscope.anarray[1] = = =/True

We removed the attribute from Childscope, then the prototype chain is queried when we access the property again. Deleting an object's properties will bring the attributes from the prototype chain to the surface.

Iv. Scope Inheritance of Angularjs
Create new Scope and prototype inheritance: Ng-repeat, Ng-include, Ng-switch, Ng-view, ng-controller, directive with scope:true, Directive WI Th transclude:true
Creates a new Scope, but does not inherit: directive with Scope: {...}. It will create a separate Scope.
Note: Directive does not create a new Scope by default, that is, the default parameter is Scope:false.

Ng-include

Suppose in our controller,

$scope. myprimitive = m;
$scope. MyObject  = {anumber:11};

HTML is:

<script type= "Text/ng-template" id= "/tpl1.html" >
  <input ng-model= "myprimitive" >
</script >
<div ng-include src= "'/tpl1.html '" ></div> <script type= "text/ng-template" id= "
 
Tpl2.html ">
  <input ng-model=" Myobject.anumber ">
</script>
<div ng-include src=" ' /tpl2.html ' "></div>

Each ng-include generates a child scope, and each child scope inherits the parent scope.

Input (such as "77″") to the first input text box, the child Scope obtains a new myprimitive property that overrides the parent scope's same name. This may not be the same as you expected.

The input (such as "99″") to the second input text box does not create a new attribute in the child Scope, because tpl2.html binds the model to an object attribute (an object), and prototype inheritance plays a role at this time, Ngmodel looking for objects MyObject and found in its parent Scope.

If we don't want to change model from number base type to object, we can rewrite the first template with $parent:

<input ng-model= "$parent. Myprimitive" >

Input (such as "22″") to this text box will not create a new attribute. Model is bound to the property of the parent scope (because $parent is a property of the child scope that points to its parent scope).

For all scope (prototype inherited or not inherited), angular always records the parent-child relationship (that is, the inheritance relationship) through the $parent of the scope, $ $childHead and $ $childTail attributes, which are not drawn in the diagram for simplification.

In the absence of a form element, another method is to define a function in the parent Scope to modify the base data type. Because of the prototype inheritance, the child Scope ensures that the function can be called. For example


$scope. setmyprimitive = function (value) {
  $scope. myprimitive = value in the parent Scope;

View DEMO

Ng-switch
Ng-switch's prototype inheritance is the same as ng-include. So if you need to do a two-way binding on the base type data, use the $parent, or change it to an object object and bind to its properties to prevent the child scope from overwriting the parent scope's properties.
Ng-repeat
Ng-repeat is a bit different. Let's say in our controller:

$scope. myarrayofprimitives = [one to one];
$scope. myarrayofobjects  = [{num:101}, {num:202}]

There is also HTML:

<ul>
  <li ng-repeat= "num in myarrayofprimitives" >
    <input ng-model= "num" >
  </li >
<ul>
<ul>
  <li ng-repeat= "obj in myarrayofobjects" >
    <input ng-model= " Obj.num ">
  </li>
<ul>

For each item,ng-repeat creates a new scope, each scope inherits the parent scope, but the value of the Item is also assigned to the new scope (the name of the new property is the variable name of the loop). The source code of angular ng-repeat is actually this:

Childscope = scope. $new (); The child scope prototype inherits the parent scope ...   
Childscope[valueident] = value; Create a new Childscope property

If item is an underlying data type (just like myarrayofprimitives), its value is essentially copied to a new child scope property. Changing this child scope property value (such as Ng-model, or num) does not change the array referenced by the parent scope. So the NUM attribute obtained in the first ng-repeat of the above is independent of the myarrayofprimitives array:

This ng-repeat is different from what you expected. In angular 1.0.2 and earlier versions, entering a text box would change the value of the gray lattice, which is visible only in the child Scope. After angular 1.0.3+, the input text will not have any effect.
What we want is that the input can change the myarrayofprimitives array, not the properties in the child Scope. For this we must change the model to an array of objects (array of objects).

So if item is an object, then a reference to the original object (not a copy) is assigned to the new Child Scope property. Changing the value of the child scope property (using Ng-model, or obj.num) also changes the object referenced by the parent scope. So the second ng-repeat above can be expressed as:

That's what we want. Entering a text box changes the value of the gray lattice, which is visible both in the parent scope and the child scope.
Ng-controller
Nested using Ng-controller, the result is the normal prototype inheritance as Ng-include and Ng-switch. So the practice is no longer to repeat. However, "Two controller use $scope inheritance to share information is considered a bad practice"
You should use service to share data between controller.

If you really want to share data through inheritance, there is nothing special to do, and the child scope can directly access all the properties of the parent scope.
Directives
This needs to be discussed in a separate context.

The

Default scope:false–directive does not create a new scope, so there is no prototype inheritance. This may seem simple, but it is also dangerous, because you will think that directive creates a new attribute in Scope, and in fact it only uses an existing attribute. This is not good for writing reusable modules and components.
scope:true– then directive creates a new child scope and inherits the parent scope. If you have multiple directive on the same DOM node to create a new scope, only a new scope is created. Because of the normal prototype inheritance, as with Ng-include, ng-switch to note the two-way binding of the underlying type data, the child scope property overrides the parent scope attribute with the same name.
Scope: {...}– then directive creates a separate scope without prototype inheritance. This is a good choice when writing reusable modules and components, because directive does not accidentally read and write to the parent scope. However, sometimes such directives often require access to the properties of the parent scope. Object hashes are used to establish a two-way binding (using ' = ') or one-way binding (using ' @ ') between this independent scope and the parent scope. There is also a ' & ' expression that binds to the parent Scope. These are all derived from the parent scope to create a local scope property. Note that HTML attributes are used to establish bindings, and you cannot refer to the property names of the parent Scope in an object hash, you must use an HTML attribute. For example, <div my-directive> and scope: {localprop: ' @parentProp '} is unable to bind the parent property parentprop to the standalone scope, you must specify this: <div My-direc tive the-parent-prop=parentprop> and scope: {localprop: ' @theParentProp '}. Independent scope __proto__ refers to a scope object (the Orange Object in the following illustration), and the $parent of the independent scope points to the parent scope, so although it is independent and does not inherit from the parent scope prototype, it is still a child scope 。

In the figure below, we have <my-directive interpolated= "{{PARENTPROP1}}" twowaybinding= "ParentProp2" > and scope:

{interpolatedprop: ' @interpolated ', Twowaybindingprop: ' =twowaybinding '}.

At the same time, suppose directive has done Scope.someisolateprop = "I ' m isolated" in its link function

Note: Use the attrs. $observe (' Attr_name ', function (value) {...}) in the link function to get the property value that the independent Scope replaces with the ' @ ' symbol. For example, in the link function there is a attrs. $observe (' interpolated ', the function (value) {...} value will be set to one. (Scope.interpolatedprop in the link function is Undefi Ned, the opposite Scope.twowaybindingprop is defined in the link function because of the ' = ' notation.
transclude:true– then directive creates a new "transcluded" child scope and inherits the parent scope. So if the content in the template fragment (for example, those that will replace Ng-transclude) requires a two-way binding of the base type data for the parent scope, use $parent, or you will model an object's properties to prevent the child scope attribute from overwriting the parent scope property.

Transcluded and independent scope (if any) are brotherhood, and each scope $parent points to the same parent scope. When scope and independent scope exist in the template at the same time, the independent scope property $ $nextSibling will point to scope in the template.
In the following figure, suppose directive is just like the last one, but it's more transclude:true

To view the online DEMO, the example has a showscope () function that can be used to check the independent scope and its associated transcluded scope.
Summary
There are four types of Scope altogether:

Scope--ng-include, Ng-switch, ng-controller, directive with scope:true, common for prototype inheritance
The generic prototype inherits the Scope but copies the assignment--ng-repeat. Each ng-repeat loop creates a new child scope, and the child scope always gets the new attribute.
Independent isolate scope--directive with scope: {...}. It is not a prototype inheritance, but ' = ', ' @ ' and ' & ' provides a mechanism to access the parent Scope property.
Transcluded scope--directive with Transclude:true. It also follows prototype inheritance, but it is also any isolate scope brother.
For all Scope,angular, the parent-child relationship is always recorded through the $parent of Scope, $ $childHead and $ $childTail properties.

The difference between Ps:scope and Rootscope
Scope is the bridge between HTML and a single controller, and data binding depends on him. Rootscope is the bridge of scope in each controller. Values defined with Rootscope can be used in each controller. Here is a detailed description of the example.
1,js Code

Phonecatapp.controller (' Testctrl ', [' $scope ', ' $rootScope ', 
  function ($scope, $rootScope) { 
    $rootScope. Name = ' This is test '; 
  } 
]; 
 
Phonecatapp.controller (' Test111ctrl ', [' $scope ', ' $rootScope ', 
  function ($scope, $rootScope) { 
    $scope. Name = $rootScope. Name; 
  } 
]); 

2,html Code

<div ng-controller= "Testctrl" > 
  I Set the global variable.<strong>{{$root .name}}</strong> 
</div> 
 
<div ng-controller= "Test111ctrl" > 
  1,get global variable. <strong>{{name}} </strong><br> 
  2,get global variable. <strong>{{$root .name}}</strong> 
</div > 

3, Show results

I set the global variable.this is test 
1,get global variable. This is test 
2,get global variable. This is test 

As you can see from the results, $rootScope. Name set variables, in all controller can be directly with the {{$root. Name}} to display, very powerful. That, of course, can also be assigned a value to scope.

Related Article

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.