Easy javascript data bidirectional binding _ javascript skills

Source: Internet
Author: User
This article teaches you how to easily bind javascript data in two-way Bidirectional data bindingIt means that the corresponding UI can be changed simultaneously when the object property changes, and vice versa. In other words, if we have a user object and this object has a name attribute, the UI will also display this new value whenever you set a new value for user. name. Similarly, if the UI contains an input box for data username, inputting a new value will also change the name attribute of the user object accordingly.

Many popular javascript frameworks, such as Ember. js, Angular. js, or KnockoutJS, use two-way data binding as their main features for publicity. This does not mean that it is difficult to implement it from the beginning, nor does it mean that when we need such a function, using these frameworks is our only choice. The internal potential thinking is actually quite basic. The implementation can be summarized into the following three points:

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

Although there are many ways to achieve this, a simple and efficient method is implemented through the publish subscriber mode. The method is simple: you can use custom data attributes as the attributes to be bound in HTML code. All bound Javascript objects and DOM elements will subscribe to this publish subscription object. At any time, we detect changes in Javascript objects or HTML input elements. We send event proxies to publish and subscribe objects, then, it transmits and broadcasts all changes to the bound objects and elements.

A simple example of jQuery implementation

Using jQuery to implement the things we discussed above is quite simple and clear, because as a popular library, it makes it easy for us to subscribe to and publish DOM events. At the same time, we can also 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-
 
  ="
  
   "  var data_attr="bind-"+object_id,    message=object_id+":change";  // Listen to chagne events on elements with data-binding attribute and proxy  // then to the PubSub, so that the change is "broadcasted" to all connected objects  jQuery(document).on("change","[data-]"+data_attr+"]",function(eve){    var $input=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, the following is an example of the minimal user data model implementation:

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 property to the UI, we only need to set the appropriate data property on the corresponding HTML element.

// javascript var user=new User(123);user.set("name","Wolfgang");// html

The value changes in the input box are automatically mapped to the name attribute of the user, and vice versa. Success!

JQuery implementation is not required

Most of the current projects are generally used by jQuery, so the above example is completely acceptable. But if we need to completely depend on jQuery, how can we implement it? Well, in fact, it is not difficult to do this (especially when we only provide Internet Explorer 8 or more support for Internet Explorer ). Finally, we only need to observe DOM events through the publish subscriber mode.

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

The data model can remain unchanged. Apart from calling the trigger method in jQuery in setter, we can replace it with the publish method 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` method     binder.publish( uid + ":change", attr_name, val, this );  } } // ...}

I explained through examples, and once again completed what we wanted through pure javascript, which is less than one hundred lines, and can be maintained. I hope it will be helpful for you to implement two-way binding of javascript data.

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.