Home Web Front-end JS Tutorial Implement very simple js two-way data binding_javascript skills

Implement very simple js two-way data binding_javascript skills

May 16, 2016 pm 03:33 PM

Two-way data binding refers to the ability to bind changes in object properties to changes in the user interface, and vice versa. In other words, if we have a user object and a name attribute, once we assign a new value to user.name, the new name will be displayed on the UI. Likewise, if the UI contains an input box for the user's name, entering a new value should cause the user object's name property to change accordingly.

Many popular JS framework clients such as Ember.js, Angular.js or KnockoutJS have implemented two-way data binding in their latest features. This does not mean that it is difficult to implement it from scratch, nor does it mean that adopting these frameworks is the only option when these functions are needed. The idea below is actually very basic and can be thought of as a 3-step plan:

We need a way to bind UI elements and attributes to each other
We need to monitor changes in properties and UI elements
We need to make all bound objects and elements aware of changes

There are still many ways to implement the above idea. One simple and effective way is to use the PubSub mode. The idea is simple: we use data attributes to bind HTML code, and all JavaScript objects and DOM elements that are bound together subscribe to a PubSub object. As long as a JavaScript object or an HTML input element listens to data changes, the event bound to the PubSub object will be triggered, and other bound objects and elements will make corresponding changes.

Use jQuery to make a simple implementation

For subscribing and publishing DOM events, it is very simple to implement it with jQuery. Next, we will use Jquery, such as the following:

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 attribute and proxy
 // them to the PubSub, so that the change 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 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("input, textarea, select") ) {
  $bound.val( new_val );
  } else {
  $bound.html( new_val );
  }
 });
 });
 return pubSub;
}
Copy after login

For the above implementation, the following is the simplest implementation method of a User 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 the PubSub
 binder.on( uid + ":change", function( evt, attr_name, new_val, initiator ) {
 if ( initiator !== user ) {
  user.set( attr_name, new_val );
 }
 });
 return user;
}
Copy after login

Now if we want to bind the User model attributes to the UI, we only 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" />
Copy after login

In this way, the input value will be automatically mapped to the name attribute of the user object, and vice versa

Same. This simple implementation is complete!

No need for jQuery implementation

In most projects today, jQuery is probably already used, so the above example is completely acceptable. However, what if we need to try going to the other extreme and also remove the dependency on jQuery? Well, it's not that hard to prove (especially since we restrict support to IE 8 and above). Ultimately, we have to implement a custom PubSub using normal javascript and retain 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, arguments );
   }
  }
  },
  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 change events and proxy to PubSub
 if ( document.addEventListener ) {
 document.addEventListener( "change", changeHandler, 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 elements = 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;
}
Copy after login

The model can remain the same except for calling the jQuery trigger method in the setter. Calling the trigger method will be replaced by calling the publish method of our customized 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` method
  binder.publish( uid + ":change", attr_name, val, this );
 }
 }
 // ...
}
Copy after login

We once again achieved the results we wanted with less than a hundred lines of maintainable pure JavaScript.

The above content is a tutorial on js two-way data binding. I hope it will be helpful to everyone.

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What should I do if I encounter garbled code printing for front-end thermal paper receipts? What should I do if I encounter garbled code printing for front-end thermal paper receipts? Apr 04, 2025 pm 02:42 PM

Frequently Asked Questions and Solutions for Front-end Thermal Paper Ticket Printing In Front-end Development, Ticket Printing is a common requirement. However, many developers are implementing...

Demystifying JavaScript: What It Does and Why It Matters Demystifying JavaScript: What It Does and Why It Matters Apr 09, 2025 am 12:07 AM

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

Who gets paid more Python or JavaScript? Who gets paid more Python or JavaScript? Apr 04, 2025 am 12:09 AM

There is no absolute salary for Python and JavaScript developers, depending on skills and industry needs. 1. Python may be paid more in data science and machine learning. 2. JavaScript has great demand in front-end and full-stack development, and its salary is also considerable. 3. Influencing factors include experience, geographical location, company size and specific skills.

How to merge array elements with the same ID into one object using JavaScript? How to merge array elements with the same ID into one object using JavaScript? Apr 04, 2025 pm 05:09 PM

How to merge array elements with the same ID into one object in JavaScript? When processing data, we often encounter the need to have the same ID...

Is JavaScript hard to learn? Is JavaScript hard to learn? Apr 03, 2025 am 12:20 AM

Learning JavaScript is not difficult, but it is challenging. 1) Understand basic concepts such as variables, data types, functions, etc. 2) Master asynchronous programming and implement it through event loops. 3) Use DOM operations and Promise to handle asynchronous requests. 4) Avoid common mistakes and use debugging techniques. 5) Optimize performance and follow best practices.

How to achieve parallax scrolling and element animation effects, like Shiseido's official website?
or:
How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? How to achieve parallax scrolling and element animation effects, like Shiseido's official website? or: How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? Apr 04, 2025 pm 05:36 PM

Discussion on the realization of parallax scrolling and element animation effects in this article will explore how to achieve similar to Shiseido official website (https://www.shiseido.co.jp/sb/wonderland/)...

The difference in console.log output result: Why are the two calls different? The difference in console.log output result: Why are the two calls different? Apr 04, 2025 pm 05:12 PM

In-depth discussion of the root causes of the difference in console.log output. This article will analyze the differences in the output results of console.log function in a piece of code and explain the reasons behind it. �...

How to implement panel drag and drop adjustment function similar to VSCode in front-end development? How to implement panel drag and drop adjustment function similar to VSCode in front-end development? Apr 04, 2025 pm 02:06 PM

Explore the implementation of panel drag and drop adjustment function similar to VSCode in the front-end. In front-end development, how to implement VSCode similar to VSCode...

See all articles