Example of Angular bidirectional data binding

Source: Internet
Author: User
Tags bind

Angular is a well-known front-end Framework. Many of its features are cool, such as bidirectional data binding, dependency injection, commands, MVC (or MVVM), template (a bit like handlebar ). However, two-way data binding is the most discussed. The core idea of this article is the observer mode (or publish and subscribe mode). The focus of this article is to discuss how to implement the observer mode, then we will discuss how to implement simple two-way data binding.

First, let's take a look at the Observer Mode:


Observer Mode

JavaScript is an event-driven language, and the observer mode can be seen everywhere. For example, some commonly used onclick, attachEvent, and addEventListener are specific applications of the observer mode.

We can directly use the implemented DOM event operations, but for self-implemented objects, we need to implement the publishing/subscription model by ourselves. Here is a simple example (for more information, refer to the JavaScript design pattern-Observer pattern ).

Function PubSub (){
Var pubSub = {
Callbacks :{},
On: function (msg, callback ){
This. callbacks [msg] = this. callbacks [msg] | [];
This. callbacks [msg]. push (callback );
},
Publish: function (msg ){
This. callbacks [msg] = this. callbacks [msg] | [];
For (var I = 0, len = this. callbacks [msg]. length; I <len; I ++ ){
This. callbacks [msg] [I]. apply (this, arguments );
};
        }
      }
Return pubSub;
}

Var writer = new PubSub ();
Var reader = {
Read: function () {alert ("I read this new book ")}
};
Writer. on ("newbook", function () {reader. read ()});
Writer. publish ("newbook ");

In this way, we have completed a simple example. After the author releases a new book, the user can read the book.

Based on the above, we will further discuss two-way data binding:

Bidirectional data binding
Two-way data binding is to bind the object property changes to the UI, or vice versa. In other words, if we have a user object with the name attribute, the UI will display the new name when we give the user. name a new value. Similarly, if the UI contains an input field used to enter the user name, entering a new value will change the attributes in the user object. The diagram of bidirectional data binding is shown in the following figure:

Two way data binding

Many popular client JavaScript frameworks such as Ember. js, AngularJS, and KnockoutJS all use bidirectional data binding as their top feature. However, this does not mean that it is very difficult to implement two-way data binding from scratch. Similarly, when we need two-way data binding, we can not only select one of these frameworks. The underlying idea of two-way data binding is very basic. It can be compressed into three steps:

We need a method to identify which UI element is bound with the corresponding attribute.
We need to monitor the changes in attributes and UI elements.
We need to spread all the changes to the bound objects and elements.
Although there are many implementation methods, the simplest and most effective way is to use the publisher-subscriber mode. The idea is simple: you can use custom data attributes to specify bindings in HTML code. All bound JavaScript objects and DOM elements will "subscribe" to a publisher object. If a JavaScript object or an HTML input field is detected to be changed at any time, we send the proxy event to the publisher-subscriber mode, this in turn broadcasts the changes and broadcasts them to all bound objects and elements.

Here, many people naturally think of using jQuery to listen for UI changes using DOM Event Operations. Then, they will modify the corresponding data fields and then use on to customize event listening data field changes, broadcast changes to all bound objects and elements. This article mainly discusses how to use Javascript to implement bidirectional data binding. If you are interested in jQuery implementation, you can refer to-JavaScript to implement simple bidirectional data binding.

First, let's look at the effect:


Here we only slightly modify the example of the previous observer mode, and add the event listening to the DOM element:

Function DataBinder (object_id ){
// Create a simple pubSub object
Var pubSub = {
Callbacks :{},
On: function (msg, callback ){
This. callbacks [msg] = this. callbacks [msg] | [];
This. callbacks [msg]. push (callback );
},
Publish: function (msg ){
This. callbacks [msg] = this. callbacks [msg] | [];
For (var I = 0, len = this. callbacks [msg]. length; I <len; I ++ ){
This. callbacks [msg] [I]. apply (this, arguments );
};
            }
},

Data_attr = "data-bind-" + object_id,
Message = object_id + ": change ",

ChangeHandler = function (event ){
Var target = event.tar get | event. srcElement, // IE8 compatible
Prop_name = target. getAttribute (data_attr );

If (prop_name & prop_name! = ""){
PubSub. publish (message, prop_name, target. value );
            }
};

// Listen for event changes and proxy to pubSub
If (document. addEventListener ){
Document. addEventListener ("keyup", changeHandler, false );
} Else {
// IE8 uses attachEvent instead of addEventListenter
Document. attachEvent ("onkeyup", changeHandler );
};

// PubSub transmits changes to all bound elements
PubSub. on (message, function (event, prop_name, new_val ){
Var elements = document. querySelectorAll ("[" + data_attr + "=" + prop_name + "]"),
Tag_name;
For (var I = 0, len = elements. length; I <len; I ++ ){
Tag_name = elements [I]. tagName. toLowerCase ();

If (tag_name = "input" | tag_name = "textarea" | tag_name = "select "){
Elements [I]. value = new_val;
} Else {
Elements [I]. innerHTML = new_val;
};
};
})

Return pubSub;
}

Then define the model:

Function User (uid ){
Var binder = new DataBinder (uid ),
User = {
Attribute :{},

// The property setter uses the data binder pubSub for publishing.
Set: function (attr_name, val ){
This. attribute [attr_name] = val;
Binder. publish (uid + ": change", attr_name, val, this );
},

Get: function (attr_name ){
Return this. attribute [attr_name];
},

_ Binder: binder
};

Binder. on (uid + ": change", function (event, attr_name, new_val, initiator ){
If (initiator! = User ){
User. set (attr_name, new_val );
        }
});

Return user;
  }

It is very easy to use. You only need to create a model and set fields through the model.

Var user = new user( 123 );
User. set ("name", "lwl ");

In this way, we have completed simple two-way data binding. In the above codepen instance, we use an input and p, and the input value will change the corresponding data field, changes to data fields will be broadcast to all UI elements at the same time, so that we can see the values we entered in the input on p. Please try again.

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.