Bidirectional data binding refers to the ability of a binding object property to change to the user interface, and vice versa. To put it another way, if we have a user object and a Name property, once we assign a new value to User.Name, the new name will appear on the UI. Similarly, if the UI contains an input box that enters the user's name, entering a new value should cause the user object's Name property to be changed accordingly.
Many of the most popular JS framework clients, such as Ember.js,angular.js or Knockoutjs, have published two-way data binding on the latest features. This does not mean that it is difficult to implement from zero or that these frameworks are the only option when these features are needed. The following idea is actually very basic and can be considered as a 3 step plan:
We need a way to bind UI elements and attributes to each other
We need to monitor changes in attributes and UI elements
We need to get all the bound objects and elements to feel the change.
There are still many ways to achieve the above ideas, there is a simple and effective way is to use the PubSub mode. The idea is simple: we use data attributes to bind HTML code, and all the JavaScript objects and DOM elements that are bound together subscribe to a PubSub object. Whenever a JavaScript object or an HTML INPUT element is monitoring the changes in the data, the events bound to the PubSub object are triggered, so that other bound objects and elements are changed accordingly.
Use jquery to do a simple implementation
For the subscription and publication of DOM events, it is very simple to use jquery, and then we'll use jquery like this:
function DataBinder (object_id) {//Use a JQuery object as simple PubSub var PubSub = JQuery ({});
We expect a ' data ' element specifying the binding//In the form:data-bind-<object_id>= "<property_name>"
var data_attr = "bind-" + object_id, message = object_id + ": Change"; Listen to change events on elements with the data-binding attributes and proxy//them to the PubSub E is ' broadcasted ' to ' all ' connected objects jQuery (document). On ("Change", "[data-" + data_attr + "]", Function (EVT)
{var $input = JQuery (this);
Pubsub.trigger (message, [$input. Data (data_attr), $input. Val ()]);
}); PubSub propagates changes to all bound elements, setting value of//input tags or HTML content of the other tags PubSub. On (Message, function (EVT, prop_name, New_val) {jQuery ("[data-" + data_attr + "=" + Prop_name + "]"). each (
{var $bound = JQuery (this); if ($bound. Is ("Input, textarea, select") {$bound. val (new_vAL);
else {$bound. html (new_val);
}
});
});
return pubSub; }
For the above implementation, here is the simplest implementation of a user model:
function User (UID) {
var binder = new DataBinder (UID),
user = {
attributes: {},
//The attribute Sette R Publish changes using the DataBinder PubSub
set:function (Attr_name, Val) {
this.attributes[attr_name] = val ;
Binder.trigger (UID + ": Change", [Attr_name, Val, this]);
},
get:function (attr_name) {return
this.attr ibutes[attr_name];
},
_binder:binder
};
Subscribe to the PubSub
Binder.on (uid + ": Change", Function (evt, attr_name, New_val, initiator) {
if (INI Tiator!== user) {
user.set (attr_name, new_val);
}
});
return user;
}
Now if we want to bind the user model properties to the UI, we just need to bind the appropriate data attributes to the corresponding HTML elements.
JavaScript
var user = new User (123);
User.set ("name", "Wolfgang");
HTML
<input type= "number" data-bind-123= "name"/>
The input value is automatically mapped to the Name property of the user object, whereas
Versa This simple implementation is done!
No need for jquery implementation
In most of today's projects, jquery may already be used, so the above example is perfectly acceptable. But what if we need to try to do it to the other extreme and also remove the dependency on jquery? Well, verify that it's not difficult to do this (especially if we limit the support of IE 8 and above). Ultimately, we have to implement a custom pubsub with generic JavaScript and preserve DOM events:
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 =, Len = this.callbacks[msg].length i < len; i++) {this.callbacks[msg] [i].apply (this, a
rguments);
}}, Data_attr = "data-bind-" + object_id, message = object_id + ": Change", Changehandler = function (evt) { var target = Evt.target | |
Evt.srcelement,//IE compatibility Prop_name = Target.getattribute (data_attr);
if (prop_name && prop_name!== "") {pubsub.publish (message, Prop_name, target.value);
}
}; Listen to the change events and proxy to PubSub if (Document.addeventlistener) {document.addeventlistener (' change ', C
Hangehandler, false); else {//IE uses attachevent instead of aDdeventlistener document.attachevent ("onchange", Changehandler); }//PubSub propagates changes to all bound elements pubsub.on (message, function (EVT, prop_name, new_val) {var elem
Ents = Document.queryselectorall ("[" + data_attr + "=" + Prop_name + "]"), tag_name;
for (var i =, 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; }
In addition to the trigger method of calling jquery in the setup, the model can remain the same. Invoking the Trigger method replaces the Publish method that invokes our custom pubsub with different characteristics:
In the model ' s setter:
function User (UID) {
//...
user = {
//...
Set:function (Attr_name, Val) {
this.attributes[attr_name] = val;
Use the ' Publish '
to Binder.publish (uid + ": Change", Attr_name, Val, this);
}
// ...
}
Once again, we've done what we want with a 100-line, maintainable, pure JavaScript.
The above content is about the JS two-way data binding of the relevant tutorials, I hope to help you learn.