Easily implement bidirectional binding _javascript techniques for JavaScript data

Source: Internet
Author: User

bidirectional data binding refers to the ability to change the corresponding UI at the same time as the object's properties change, and vice versa. In other words, if we have a user object, this object has a Name property, and whenever you set a new value for User.Name, the UI will also show the new value. Similarly, if the UI contains an input box for the name of the data user, entering a new value can also cause the user object's Name property to change accordingly.

Many popular JavaScript frameworks, like Ember.js,angular.js or KNOCKOUTJS, use two-way data binding as their main feature. This does not mean that it is difficult to achieve it from scratch, nor does it mean that when we need this functionality, using these frameworks is our only option. The underlying idea inside is actually quite basic, and it can be summed up in the following three points:

    • We need a way to determine which UI element is bound to which attribute.
    • We need to monitor changes in properties and UI
    • We need to propagate the changes of all the bound objects and UI elements.

Although there are many ways to do this, a simple and efficient approach is to implement it by publishing the subscriber pattern. The method is simple: we can use the custom data property as the attribute in the HTML code that needs to be bound. All of the JavaScript objects and DOM elements that are bound together will subscribe to this publication subscription object. Any time we detect changes in both JavaScript objects and HTML input elements, we are passing the event agent to the publication subscription object, and then passing it through and broadcasting all the changes that occur in the bound objects and elements.

A simple example of a jquery implementation

The things we discussed above through jquery are fairly straightforward, because as a popular library, it makes it easy to subscribe and publish DOM events, and we can customize one:

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 Chagne events in elements with data-binding attributes and proxy//then to the PubSub S "broadcasted" to all connected objects jQuery (document). On ("Change", "[data-]" +data_attr+ "]", function (Eve) {var $in

    Put=jquery (this);
  Pubsub.trigger (message,[$input. Data (data_attr), $input. Val ()));

  }); PubSub propagates chagnes to all bound elemetns,setting value of//input tags or HTML content of other tags PubSub . On (Message,function (evt,prop_name,new_val) {jQuery ("[data-" +data_attr+ "=" +prop_name+ "]"). each (function () {var $

      Bound=jquery (this);
      if ($bound. Is (")) {$bound. val (new_val);
   }else{$bound. html (new_val);   }
    });
  });
return pubSub;
 }

As for JavaScript objects, here are examples of implementations of the minimized user data model:

function User (UID) {
  var binder=new databinder (UID),
    
    user={
      attributes:{},
      //The attribute setter 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.attributes[attr_name];
      },
    
      _binder:binder
    };

  Subscribe to PubSub
  Binder.on (uid+ ": Change", function (evt,attr_name,new_val,initiator) {
    if (initiator! ==user) {
      user.set (attr_name,new_val);
    }
  });

  return user;
}

Now, whenever we want to bind an object's properties to the UI, we simply set the appropriate data property on the corresponding HTML element.

JavaScript 
var user=new user (123);
User.set ("name", "Wolfgang");

HTML
<input type= "number" data-bind-123= "name"/>

Changes to the input box are automatically mapped to the user's Name property, and vice versa. Done!

No need for jquery implementations

Most of the projects now in general jquery are already in use, so the above example is perfectly acceptable. But what if we need to be completely independent of jquery? Well, in fact it's not hard to do (especially when we provide IE8 support for IE only). Finally, we just want to look at DOM events by publishing subscriber mode.

function DataBinder (object_id) {//Create a simple PubSub object var PubSub = {callbacks: {}, On:function (ms G, 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 (evt) { var target = Evt.target | |

  Evt.srcelement,//IE8 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 ')
 Changehandler, false); else {//IE8 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 = 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;

 }

The data model can be maintained, in addition to the invocation of the trigger method in jquery in the setter, we can replace it with the Publish method we have customized in PubSub.

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);
  }

 // ...
}

Through the example explained, and once again through 100 lines, but also maintainable pure JavaScript finished the results we want to achieve the JavaScript data two-way binding to help.

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.