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>