Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plain Javascript bidirectional Data binding

out of curiosity and to increase my knowledge, i wanted to implement some kind of two way data binding between dom elements and javascript variables.

I was lucky enough to find an excellent answer to half of my problem here @ stackoverflow which led me to this gist https://gist.github.com/384583, but i still can't get the thing done at 100%.

Here's an example of my code: http://jsfiddle.net/bpH6Z/

If you try to run the fiddle and click on "view Value" you will get undefined, while i want to get the actual value of the object's attribute.

I am probably doing something wrong due to my lack of experience with javascript, but do you have any idea why i can't properly read the attribute 'secret' after the _bind() and _watch() calls?

DISCLAIMER: as i said, i'm doing this because i want better knowledge of javascript, and i am not going to write my framework. So any "USE FRAMEWORK X" is completely useless, as i could get the job done with angularjs.

like image 280
fat Avatar asked Aug 10 '12 14:08

fat


People also ask

Is JavaScript two-way binding?

Two-way binding is a strategy to simplify the synchronization between a JavaScript reference and the HTML element value and vice versa. That means every change in the self property value reflects in the HTML element value, and every change in the HTML element value propagated back to the self.

What is bidirectional data binding?

Two-way data binding refers to sharing data between a component class and its template. If you change data in one place, it will automatically reflate at the other end. For example, if you change the value of the input box, then it will also update the value of the attached property in a component class.

What is data binding in JavaScript?

Data binding is the process that couples two data sources together and synchronizes them. With data binding, a change to an element in a data set automatically updates in the bound data set.

What directive is used for two-way data binding?

Two-way data binding can be achieved using a ngModel directive in Angular. The below syntax shows the data binding using (ngModel), which is basically the combination of both the square brackets of property binding and parentheses of the event binding.


Video Answer


2 Answers

Please try http://jsfiddle.net/bpH6Z/4/

I've updated your redefined getter/setter in Object.prototype.__watch, also currently your handler needs to return the new value.

Update: Now your handler isn't required to return the newly set value.

Current code:

//Got this great piece of code from https://gist.github.com/384583
Object.defineProperty(Object.prototype, "__watch", {
    enumerable: false,
    configurable: true,
    writable: false,
    value: function(prop, handler) {
        var val = this[prop],
            getter = function() {
                return val;
            },
            setter = function(newval) {
                val = newval;
                handler.call(this, prop, newval);
                return newval;
            };

        if (delete this[prop]) { // can't watch constants
            Object.defineProperty(this, prop, {
                get: getter,
                set: setter,
                enumerable: true,
                configurable: true
            });
        }
    }
});

var Controller = function () {
    //The property is changed whenever the dom element changes value
    //TODO add a callback ?
    this._bind = function (DOMelement, propertyName) {
        //The next line is commented because priority is given to the model
        //this[propertyName] = $(DOMelement).val();
        var _ctrl = this;
        $(DOMelement).on("change input propertyChange", function(e) {
            e.preventDefault();
            _ctrl[propertyName] = DOMelement.val();
        });

    };

    //The dom element changes values when the propertyName is setted
    this._watch = function(DOMelement, propertyName) {
        //__watch triggers when the property changes
        this.__watch(propertyName, function(property, value) {
            $(DOMelement).val(value);
        });
    };
};

var ctrl = new Controller();
ctrl.secret = 'null';
ctrl._bind($('#text1'), 'secret'); // I want the model to reflect changes in #text1
ctrl._watch($('#text2'), 'secret'); // I want the dom element #text2 to reflect changes in the model
$('#button1').click(function() {
    $('#output').html('Secret is : ' + ctrl.secret); //This gives problems
});

Current HTML:

<html>
<head></head>
<body>
    value: <input type="text" id="text1" /><br />
    copy: <input type="text" id="text2" /><br />
    <input type="button" id="button1" value="View value"><br />
    <span id="output"></span>
</body>
</html>
like image 127
metadings Avatar answered Oct 13 '22 05:10

metadings


The handler you pass to your __watch function is missing a return statement.

this._watch = function(DOMelement, propertyName) {
    //__watch triggers when the property changes
    this.__watch(propertyName, function(property, value) {
        $(DOMelement).val(value);
        return value;
    })

}

Because newval is set to what's returned from the handler, it'll be undefined without that.

like image 3
Pointy Avatar answered Oct 13 '22 03:10

Pointy