How is the 'Two way data binding' process with pure JS?

7

Nowadays javaScript frameworks are popular, such as React, Vue and Angular.

They work with Two-Way Data Binding which is a hand in the wheel for the developer.

How is this process done? Is there any simple way to do this?

I would like something didactic if possible.

    
asked by anonymous 10.05.2018 / 13:58

2 answers

4

Understand, making a Two-Way Data Binding of nothing is a lot more complicated than it sounds, after all you have to predict all the scenarios, so I strongly advise you not to try it, and use a tool like VueJS or React .

In the example below, Two-Way Data Binding involves only two diretivas , in the case data-html and data-value , where we are assuming that they will be span and input[type='text'] . In a real scenario, you would have to treat the behavior of these directives in different HTMLElement types, such as select or input[type='radio']

The second point is that we have to change the object that will serve as a template, by overwriting its get and set .

Below is a functional example, but keep in mind, it is far from mature enough to be adopted as a Blibioteca.

// definindo um modelo
var model = {
  teste1: 'Hello World',
  teste2: 'Olá Mundo'
};

(function () {
  // buscando todos os HTMLElement com a diretiva data-value
  var values = document.querySelectorAll("[data-value]")
  // buscando todos os HTMLElement com a diretiva data-html
  var htmls = document.querySelectorAll("[data-html]")
  // criando um indice para os HTMLElements com a diretiva data-value
  values = [].reduce.call(values, function (values, value) {
    if (!values[value.dataset.value])
      values[value.dataset.value] = [];
    values[value.dataset.value].push(value)
    return values
  }, {})
  // criando um indice para os HTMLElements com a diretiva data-html
  htmls = [].reduce.call(htmls, function (htmls, html) {
    if (!htmls[html.dataset.html])
      htmls[html.dataset.html] = [];
    htmls[html.dataset.html].push(html)
    return htmls
  }, {})  
  
  // criando um evento para os HTMLElements com a diretiva data-value
  // quando o mesmo for atualizado pelo Usuario, deverá refletir no modelo
  // ao refletir no modelo, este deverá ser propagado para o restante da pagina.
  var onValueInput = function (evt) {
    model[this.key] = this.input.value
  }
  Object.keys(values).forEach(function (key) {
    var inputs = values[key]
    inputs.forEach(function (input) {
      input.addEventListener("input", onValueInput.bind({ key, input }))
    })
  })
  // modificando as propriedades de acesso do modelo
  Object.keys(model).forEach(function (key) {
    var _value = model[key]
    Object.defineProperty(model, key, {
      // get: retorna o valor para de uma determinada propriedade do modelo
      get: function () {
        return _value;
      },
      // set: ao setar algum valor no modelo, deve se propagar o mesmo para os HTMLElements
      // com diretivas associadas a esta propriedade
      set: function (value) {
        _value = value
        if (values[key]) {
          var inputs = values[key]
          inputs.forEach(function (input) {
            input.value = _value
          })
        }
        if (htmls[key]) {
          var spans = htmls[key]
          spans.forEach(function (span) {
            span.textContent = _value
          })
        }
      }
    })
    // atualizando a pagina com os valores iniciais
    model[key] = _value
  })
})();

// atualizando os valores do modelo após 5 segundos (apenas para demonstrar o 2-way data binding)
window.setTimeout(function () {
  model.teste1 += " - deprecated"
  model.teste2 += " - descontinuado"
}, 5000)
<input type="text" data-value="teste1" />
<br />
<span data-html="teste1"></span>
<br />
<input type="text" data-value="teste2" />
<br />
<span data-html="teste2"></span>
<br />
<br />
Recaptulando, Os textos são <span data-html="teste1"></span> e <span data-html="teste2"></span>
    
10.05.2018 / 17:02
4

Two-way binding means only that:

  • When the properties in the template are updated, so does the user interface.
  • When UI elements are updated, changes are propagated back to the template.

Simple Bidirectional Data Binding Example with Pure JavaScript:

twoWay = function(event) {
  var elem = document.getElementsByClassName(event.currentTarget.className);
  for(var key in elem){
    elem[key].value = event.currentTarget.value;
  }
}
<title>Exemplo Two Way data binding</title>
<body style="background: whitesmoke;">

  Nome : <input type="text" class="username" onkeyup="twoWay(event);" >
  <input type="text" class="username" onkeyup="twoWay(event);"> <br>
  
  Idade : <input type="text" class="idade" onkeyup="twoWay(event);" >
  <input type="text" class="idade" onkeyup="twoWay(event);">
  <input type="text" class="idade" onkeyup="twoWay(event);">
</body>

Another example (code only):

References:

10.05.2018 / 15:36