Data binding and monitoring
In the process of business development, we may use a lot of DOM operations, this process is cumbersome, but with ANGULARJS, basically can be freed, the key to do this is data binding. So what is data binding and how do you bind it? This section will choose from a variety of perspectives to illustrate the various scenarios in the business development process.
Interface synchronization based on a single model
Sometimes we have this requirement that there is an input box on the interface, and then there's another place to show the text as it is, and if there's no data binding, this code could be a hassle, for example, we'll listen to the various events of the input box, keyboard keys, copy and paste, and so on, and then write the value to the corresponding position. But if there is data binding, this thing is very simple.
<input type= "text" ng-model= "a"/>
<div>{{a}}</div>
Such a small piece of code, it achieved the function we want, is not very cute? What's the key here, the variable a, where variable a acts as the role of the data model, and the input box's data changes are synchronized to the model and then distributed to other UI elements that are bound to the model.
Note that arbitrary binding to the input element of the data model, its data changes will cause the model changes, for example, we have another requirement, two input boxes, we want to enter in any one of the time, the other value is always kept in sync with it. If you need to add an event to the two input boxes in the traditional way, but with data binding, it's simple:
<input type= "text" ng-model= "B"/>
<input type= "text" ng-model= "B"/>
So the code is OK, the core element is the data Model B.
So far, the two examples are simple, but some people may have questions to ask, because we do not write any JS, this A and b where, why can play a role? Let me make an analogy about this problem.
For example, you write JS, you know that variables can not be declared on the use of:
A = 1;
At this point A is assigned to where, to the global Window object, which is actually equivalent to:
WINDOW.A = 1;
In Angularjs, variables and expressions are attached to something called scope (scope), and can declare new scopes themselves, or do not declare them. Each angular application defaults to a root scope ($rootScope), which is created on top of anything that is not declared beforehand.
The relevant concept of scope, we will explain in the next chapter. Here, we just need to know that if an undefined variable is bound in the interface, it is automatically created to the corresponding scope when it is assigned a value.
The symbol, which we mentioned in the example {{}}, is called an interpolation expression, where the content is dynamically parsed or not bound in this way, and angular another ng-bind directive is used for this kind of thing:
<input ng-model= "a"/>
<div>{{a}}</div>
<div ng-bind= "a" ></div>
Two calculations of the model
Well, sometimes it's not so simple, for example, that we might need to do some processing on the data, for example, to add a unit after each number that represents the price:
<input type= "number" ng-model= "Price"/>
<span>{{price + "(yuan)"}}</span>
Of course, our example is not good because, in fact, you can put irrelevant data outside the binding expression, like this:
<input type= "number" ng-model= "Price"/>
<span>{{price}} (Yuan) </span>
Well, consider a slightly more complicated one. We often encounter the presence of gender in the interface, but the database contains 0 or 1, so always convert it. Some of the more corny way to do this is to add extra fields to the model for display:
This is the raw data:
var Tom = {
Name: "Tom",
Gender:1
};
After being transformed by him, it became this way:
var Tom = {
Name: "Tom",
Gender:1,
Gendertext: "Male"
};
The conversion function reads as follows:
if (person.gender = 0)
Person.gendertext = "female";
if (Person.gender = 1)
Person.gendertext = "male";
Although this approach can achieve results, but undermines the structure of the model, we can make some changes:
<div>{{formatgender (Tom.gender)}}</div>
$scope. Formatgender = function (gender) {
if (gender = 0)
return "female";
if (gender = 1)
return "male";
}
};
So that we can achieve the goal. This example lets us see that the original, in the binding expression, can use the function. The formatting functions we have here, in fact, only exist in the view layer, so it doesn't affect the real data model.
Note: Here are two points of attention.
First, in a binding expression, you can use only custom functions, and you cannot use native functions. As an example:
<div>{{math.abs ( -1)}}</div>
That's a problem. Because the interpolation expression mechanism of angular determines that it cannot use such a function, it is to parse the string directly with its own interpreter, if you do need to invoke the native function, you can use a custom function as a wrapper, you can use a variety of native objects in the custom function. Just like this:
<div>{{abs ( -1)}}</div>
$scope. ABS = function (number) {
return Math.Abs (number);
};
Secondly, we have just shown that this example is intended to be used, but it does not mean that this is the best solution. Angular provides a scenario called filter for this type of requirement, which can be used to format data in an interpolation expression using a pipe operator, which we'll look at later.
The binding of an array to an object structure
Sometimes our data is not always that simple, for example, it is possible to display an array of data, which can be handled using angular's ng-repeat instructions, which is equivalent to a loop, as we look at this example:
$scope. arr1 = [1, 2, 3];
$scope. Add = function () {
$scope. Arr1.push ($scope. arr1.length + 1);
};
<button ng-click= "Add ()" >add item</button>
<ul>
<li ng-repeat= "item in ARR1" >{{item}}</li>
</ul>
This allows the contents of the array to be displayed on the interface. When the data in the array changes, it can also be updated to the interface in real time.
Sometimes we encounter a situation where there are duplicate elements in the array, and the Ng-repeat code does not work because angular the default needs to use a unique index in the array, so what if our data does? You can specify that it is indexed by ordinal, just like this:
$scope. arr2 = [1, 1, 3];
<ul>
<li ng-repeat= "item in ARR2 track by $index" >{{item}}</li>
</ul>
You can also iterate over multidimensional arrays in a multilayered way:
$scope. ARR3 = [
[11, 12, 13],
[21, 22, 23],
[31, 32, 33]
];
<ul>
<li ng-repeat= "Childarr in Arr3 Track by $index" >
{{$index}}}
<ul>
<li ng-repeat= "item in Childarr track by $index" >{{item}}</li>
</ul>
</li>
</ul>
If the element in the array is an object structure, it is not difficult, we use a table to show the array:
$scope. arr4 = [{
name: "Tom",
age:5
}, {
name : "Jerry",
age:2
}];
<table class= "Table table-bordered"
<thead>
<tr
<th>name</th>
<th>age</th>
</tr>
</thead>
<tbody>
<tr ng-repeat= "child in Arr4"
<td>{{child.name}}</td>
< Td>{{child.age}}</td>
</tr>
</tbody>
</ Table>
Sometimes we want to traverse the properties of an object, or we can use the Ng-repeat directive:
$scope. obj = {
A:1,
B:2,
C:3
};
<ul>
<li ng-repeat= "(key, value) in obj" >{{key}}: {{value}}</li>
</ul>
Note that in the ng-repeat expression, we use a (key, value) to describe the key-value relationship, if you want only the value, you can not write it, just follow the array. The object value has the repetition, does not need to resemble the array so troublesome needs to specify the $index to do the index, because it is the object key does the index, this does not duplicate.
Data monitoring
Sometimes we do not bind data directly to the interface, but we have to assign it to other variables, or to make some logical processing of the data changes, and we need to use monitoring at this time.
The most basic monitoring is simple:
$scope. A = 1;
$scope. $watch ("A", function (NewValue, oldValue) {
Alert (OldValue + "->" + newvalue);
});
$scope. Changea = function () {
$scope. a++;
};
After you have added a monitor to a variable on a scope, you can be notified when you change it. If the new assignment variable is the same as the original, the monitor will not be executed. For example, just continue to assign a value of 1, not into the monitoring function.
The above method can monitor the most direct assignment, including the various basic types, as well as the complex type of reference assignment, for example, the following array is being assigned a value and can be monitored:
$scope. arr = [0];
$scope. $watch ("Arr", function (NewValue) {
Alert ("Change:" + newvalue.join (","));
});
$scope. Changearr = function () {
$scope. arr = [7, 8];
};
But this kind of monitoring method can only handle the judgment of reference equality, for some more complex monitoring, need more detailed processing. For example, we might need to monitor an array, but not monitor its overall assignment, but monitor its element changes:
$scope. $watch ("Arr", function (NewValue) {
Alert ("Deep:" + newvalue.join (","));
}, True);
$scope. AddItem = function () {
$scope. Arr.push ($scope. arr.length);
};
Note that here we have added a third parameter to the $watch function, which is used to indicate deep monitoring of the data, including the child elements of the array and the attributes of the object, and so on.
Data binding for styles
The examples we mentioned just now are all related to data synchronization and data display, but the data binding is very powerful and its application scenario depends on our imagination.
I do not know if you have encountered such a scene, there is a list of data, one of the points, this changes the style to highlight, if in the traditional way, you may want to add some events, and then do some processing, but using data binding, can greatly simplify the code:
function Listctrl ($scope) {
$scope. Items = [];
for (var i=0; i<10; i++) {
$scope. Items.push ({
Title:i
});
}
$scope. SelectedItem = $scope. Items[0];
$scope. select = function (item) {
$scope. SelectedItem = Item;
};
}
<ul class= "List-group" ng-controller= "Listctrl" >
<li ng-repeat= "Item in Items" Ng-class= "{true: ' List-group-item active ', false: ' List-group-item '}[item== SelectedItem] "ng-click=" SELECT (item) >
{{Item.title}}}
</li>
</ul>
In this case, we use a loop to iterate over the elements in the group, and use a variable SelectedItem to identify the selected item, and then the key point is the ng-class expression, which can make a judgment based on whether the current item is selected, and generate the corresponding style name. This is a typical application of bindings that, based on it, can be used in a particularly simple way to make some of the functionality that depends on some of the controls previously needed.
In addition to using Ng-class, you can use Ng-style to control the style more carefully, such as:
<input type= "Number" ng-model= "x" ng-init= "x=12"/>
<div ng-style= "{' font-size ': x+ ' pt '}" >
Test font Size
</div>
State control
Sometimes, in addition to controlling the normal style, it is possible to control the display concealment of an element of an interface. We use Ng-class or Ng-style of course are able to control the display of elements hidden, but angular gives us a shortcut, that is ng-show and ng-hide, they are the opposite, in fact, as long as one can, provide two is to write the expression of convenience.
With data binding, we can easily implement some of the existing display hiding features. For example, when a list item is selected, some buttons appear, and when nothing is selected, these buttons do not appear.
The main part of the code is to borrow the list above and just add something related to it:
<button ng-show= "SelectedItem" > have selected items can point me </button>
<button ng-hide= "SelectedItem" > when there is no selected item, you can point me </button>
Put this code next to just the list, under the same controller, click on the list elements, you can see the binding state.
Sometimes, we also want to control the clickable state of the button, such as the example just now, the two buttons directly show hidden, too abrupt, we have to change them to enable and disable.
<button ng-disabled= "!selecteditem" > have selected items can point me </button>
<button ng-disabled= "SelectedItem" > when there is no selected item, you can point me </button>
Similarly, if you are an input box, you can use Ng-readonly to control its read-only status in the same way.
Process Control
In addition to using Ng-show and ng-hide to control the display of elements, you can also use ng-if, but the meaning is very different from the implementation mechanism. The so-called show and hide means that the DOM element already exists, only controls whether it is displayed, and if it acts as a process control, only the qualified DOM elements are created or not created.
For example, the following examples:
function Ifctrl ($scope) {
$scope. condition = 1;
$scope. Change = function () {
$scope. condition = 2;
};
}
<div ng-controller= "Ifctrl" >
<ul>
<li ng-if= "Condition==1" >if 1</li>
<li ng-if= "condition==2" >if 2</li>
<li ng-show= "Condition==1" >show 1</li>
<li ng-show= "condition==2" >show 2</li>
</ul>
<button ng-click= "Change ()" >change</button>
</div>
This example was initially created with three Li, one of which was hidden (show 2), when the click button, condition turned 2, was still three Li, of which, if 1 was not there, if 2 was created, shows 1 was hidden, showing 2 was shown.
So, what we're seeing here is that the nodes of if are dynamically created. Similarly, we can also use the Ng-switch directive:
function Switchctrl ($scope) {
$scope. Condition = "";
$scope. A = function () {
$scope. Condition = "A";
};
$scope. B = function () {
$scope. Condition = "B";
};
$scope. C = function () {
$scope. Condition = "C";
};
}
<div ng-controller= "Switchctrl" >
<div ng-switch= "Condition" >
<div ng-switch-when= "A" >A</div>
<div ng-switch-when= "B" >B</div>
<div ng-switch-default>default</div>
</div>
<button ng-click= "A ()" >A</button>
<button ng-click= "B ()" >B</button>
<button ng-click= "C ()" >C</button>
</div>
This example is basically a meaning with if, but the syntax is more natural.
Data linkage
In the process of doing the actual business, it is easy to encounter data linkage scene, the most typical example is the provincial and municipal three-level linkage. A lot of front-end tutorials or basic questions take this as an example to comprehensively examine the knowledge points applied in them.
If you are using angular to do development, it is likely that this will not be a test center, because it is very easy to achieve.
We have just implemented a single level list, you can borrow this code, do two lists, the first data changes, the second data generation filter.
function Regionctrl ($scope) {
$scope. Provincearr = ["Jiangsu", "Yunnan"];
$scope. Cityarr = [];
$scope. $watch ("Selectedprovince", function (province) {
Really useful code here, in the actual scenario, this can be the associated data that calls back-end service queries
Switch (province) {
Case "Jiangsu": {
$scope. Cityarr = ["Nanjing", "Suzhou"];
Break
}
Case "Yunnan": {
$scope. Cityarr = ["Kunming", "Lijiang"];
Break
}
}
});
$scope. selectprovince = function (province) {
$scope. selectedprovince = Province;
};
$scope. selectcity = function (city) {
$scope. selectedcity = City;
};
}
<div ng-controller= "Regionctrl" >
<ul class= "List-group" >
<li ng-repeat= "province in Provincearr" ng-class= "{true: ' List-group-item active ', false: ' List-group-item '}[ Province==selectedprovince] "ng-click=" selectprovince (province) >
{{Province}}}
</li>
</ul>
<ul class= "List-group" >
<li ng-repeat= "city in Cityarr" ng-class= "{true: ' List-group-item active ', false: ' List-group-item '}[city== Selectedcity] "ng-click=" selectcity (city) >
{City}}
</li>
</ul>
</div>
This code looks a little bit more complicated than that, in fact, the value of the code on that $watch inside the thing. What do you mean by that? It means that the monitor selectedprovince this variable, as long as it changes, to query it can cause the update data, and then the rest of the things we do not have to control.
If you are binding to a Drop-down box, the code is simpler, because ANGULARJS specifically makes this kind of consideration, ng-options is the setting:
<select class= "Form-control col-md-6" ng-model= "Selectedprovince" ng-options= "for province in province" ></select>
<select class= "Form-control col-md-6" ng-model= "selectedcity" ng-options= "City for City in Cityarr" ></select >
From this example, we see that the way to manually update the DOM compared to the traditional front-end development way of manual listener events is simply too easy to use data binding for data linkage. If you want to change this example to create a three-level linkage, just to selectedcity also do a monitoring on the line.
A comprehensive example
With these details in hand, we can combine them to make a more practical and comprehensive example. Let's say we're creating an employee's admin interface for a small store that contains an employee table and a form that you can use to add or edit employees.
The employee includes the following fields: Name, age, sex, place of birth, nationality. Among them, the name through the input box input string, age through the input box input integer, sex through the Point Menu selection button to choose, born with two dropdown box to select provinces and cities, ethnic groups can choose Han and minority, if selected minorities, you can manually enter the national name.
This example just happens to be able to use all of the bindings we're talking about. Let's take a look at the binding relationships:
The Employee table can select a row that highlights the line style
If a row is selected, its detailed data is synchronized to the form
If you click on the new or modified button, the current interface is in edit, the form can be entered, otherwise the form is read alone
Modify and delete the clickable state of the button, depending on whether there are selected rows in the table
The place of birth of the provinces and cities in the Drop-down box linkage relationship
The national name of the input box, whose visibility depends on the selection of the Han or Minority radio button
New modification deletes, OK cancellation, these two sets of buttons are mutually exclusive, never appear at the same time, and its visibility depends on whether you are currently editing.
Determines the clickable state of the button, depending on whether the current form data is legitimate
If you want to be fine, there are more places to use bindings, but these are enough for us to use all of our knowledge.
The code for this example is not pasted and can be viewed on its own.
Development and application of data binding
Now we have learned the data binding, can use this kind of characteristic, completes some very chic function. For example, if you want to use div to simulate a sine wave on the page, just generate the waveform data, and then a binding can be done.
$scope. Staticitems = [];
for (var i=0; i<720; i++) {
$scope. Staticitems.push (Math.ceil (1 + math.sin (i * math.pi/180)));
}
If we want this waveform to move, it is also easy to combine a timer, the dynamic generation of this waveform data can be. In order to form the rolling effect, when the number of wave mining points exceeds a certain value, you can take off the original point, to maintain the total length of the array.
$scope. Dynamicitems = [];
var counter = 0;
function AddItem () {
var newitem = Math.ceil (1 + math.sin ((counter++) * math.pi/180));
if ($scope. Dynamicitems.length > 500) {
$scope. Dynamicitems.splice (0, 1);
}
$scope. Dynamicitems.push (NewItem);
$timeout (function () {
AddItem ();
}, 10);
}
AddItem ();
This example corresponds to the following HTML code:
<div ng-controller= "Wavectrl" >
<style>
. wave-item {
Float:left;
width:1px;
Background-color: #ffab51;
}
</style>
<div>
<div ng-repeat= "item in Staticitems track by $index" class= "Wave-item" ng-style= "{' Height ': item+ ' px '}" ></div >
</div>
<div style= "Clear:left" >
<div ng-repeat= "item in Dynamicitems track by $index" class= "Wave-item" ng-style= "{' Height ': item+ ' px '}" ></div >
</div>
</div>
Sometimes we often see some algorithm visualization projects, such as the sort algorithm in a visual way, if the use of ANGULARJS data binding, this effect is easy to achieve:
<div ng-controller= "Sortctrl"
<style>
Data-item {
float:left;
width:20px;
Background-color: #c0c0c0;
border:1px solid #080808;
}
</style>
<button ng-click= "sort ()" >Sort</button>
<div>
<div ng-repeat= "item in ARR Track by $index "class=" Data-item "ng-style=" {' Height ': item*5+ ' px '} ' ></div>
</div
</div>
$scope. arr = [2, 4, 5, N, 4, 5,, 2, 4, n];
$scope. sort = function () {
if (!sort ($scope. arr)) {
$timeout (function () {
$scope. Sort ();
}, 500);
}
};
function sort (array) {
Meow, writing this to find out how good yield is.
for (var i = 0; i < Array.Length; i++) {
for (var j = Array.Length J > 0; j--) {
if (Array[j] < array[j-1]) {
var temp = array[j-1];
ARRAY[J-1] = Array[j];
ARRAY[J] = temp;
return false;
}
}
}
return true;
}
Look, it's as simple as this, the visualization process for a bubble sort algorithm is written.
Even, Angularjs also allows us to use data binding in SVG, use it, do some small games is also very easy, such as I wrote a double game chess, there are demo address, can see the source code, is not very simple?
Summary
Just now we have seen the various usage scenarios for data binding, what is the greatest benefit that this thing brings us? We review the previous web interface, part of the time to write HTML and CSS, part of the time to write pure logic of JavaScript, there is a lot of time to combine the two, such as the various create or select the DOM, set properties, add, etc., these things are very mechanical and cumbersome, Data binding simplifies the process and the code is clear.
Data binding is a way of thinking, and the core of everything is data. Changes in the data cause the interface to update, if we want to update the interface, just change the data.