0

I have been playing with the javascript Object.defineProperty to create data binding. I did get it to work. My question is has to do with something else.

I have a for html query to look for elements with the attribute 'data-bind' and loop through them in a for-loop. From withing the for-loop I call a function to bind them through the setter property:

var cbinder = function(obj, elem, prop) {
      Object.defineProperty(obj, prop, {
        set: function(val) {
          elem.innerHTML = val;
        }
      });
    };

// called from

 var elem = document.querySelectorAll("[data-bind]"); 
 for (var i = 0; i < elem.length; i++) {
            var prop = elem[i].getAttribute("data-bind");
            cbinder(obj, elem[i], prop);
        }

 var obj = {};
 var cbinder = function(obj, elem, prop) {

   Object.defineProperty(obj, prop, {
     set: function(val) {
       elem.innerHTML = val;
     }
   });
 };

 window.onload = function() {
   var elem = document.querySelectorAll("[data-bind]");

   for (var i = 0; i < elem.length; i++) {
     var prop = elem[i].getAttribute("data-bind");
     cbinder(obj, elem[i], prop);
   }


   var btn = document.querySelector("#chnbtn");
   btn.addEventListener("click", function(event) {
     obj.fname = "John";
     obj.lname = "Doe";

   }, false);


 };
<p>
  <span data-bind="fname">my name</span>  <span data-bind="lname">my name</span>
</p>
<p>
  <button id="chnbtn">Change Values</button>
</p>

Since I call this function within the for-loop I figured I might as well integrate it there, but here is where my issue rises. It does not work correctly and only assigns the last value when setting the object. Why is the first example working fine and the second fails, while they are in my opinion similar calls. Can someone clench my curiosity?

   var elem = document.querySelectorAll("[data-bind]");
   for (var i = 0; i < elem.length; i++) {
        var prop = elem[i].getAttribute("data-bind");
        var el = elem[i]
        Object.defineProperty(obj, prop, {
            set: function (val) {
                el.innerHTML = val;
            }
        });
    }

    var obj = {};
    window.onload = function() {
      var elem = document.querySelectorAll("[data-bind]");

      for (var i = 0; i < elem.length; i++) {
        var prop = elem[i].getAttribute("data-bind");
        var el = elem[i]
        Object.defineProperty(obj, prop, {
          set: function(val) {
            el.innerHTML = val;
          }
        });
      }


      var btn = document.querySelector("#chnbtn");
      btn.addEventListener("click", function(event) {
        obj.fname = "John";
        obj.lname = "Doe";

      }, false);


    };
<p>
  <span data-bind="fname">my name</span>  <span data-bind="lname">my name</span>

</p>
<p>
  <button id="chnbtn">Change Values</button>
</p>
Daniel
  • 4,816
  • 3
  • 27
  • 31
  • possible duplicate of [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Qantas 94 Heavy Feb 25 '15 at 06:50
  • @Qantas94Heavy - Thanks for pointing that one out to me. I would have not thought to link that to my question. – Daniel Feb 25 '15 at 16:57

1 Answers1

1

The setter function you're assigning to your property has an enduring reference to the el variable, not a copy of it as of when the function was created. So when the function is called, it's trying to use the last value el had in the loop.

Your original code, putting that off in a function, was the way to go.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    Thanks ... Your answer definitely was the first big pointer for me. After reading some more into the link above I now understand what is going on here. First time I run into this tricky trap ;-) – Daniel Feb 25 '15 at 17:10