14

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.

fat
  • 5,098
  • 4
  • 28
  • 31
  • ist $ referring to jQuery ? So it's not plain JS huh – daslicht Sep 02 '14 at 15:56
  • Possible duplicate of [How to Implement DOM Data Binding in JavaScript](http://stackoverflow.com/questions/16483560/how-to-implement-dom-data-binding-in-javascript) – Beginner Dec 29 '15 at 14:50

3 Answers3

5

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>
metadings
  • 3,798
  • 2
  • 28
  • 37
3

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.

Pointy
  • 405,095
  • 59
  • 585
  • 614
0

I have enhanced it for multi-watchers.

http://jsfiddle.net/liyuankui/54vE4/

//The dom element changes values when the propertyName is setted
this._watch = function(DOMelement, propertyName) {
    //__watch triggers when the property changes
    if(watchList.indexOf(DOMelement)<0){
        watchList.push(DOMelement);
    }
    this.__watch(propertyName, function(property, value) {
        for(var i=0;i<watchList.length;i++){
            var watch=watchList[i];
            $(watch).val(value);
            $(watch).html(value);
        }
    });
};