0

I'm trying to make an angular-like scope object that responds to changes in its properties. This is the intended behavior:

x = new Scope('a', 'b');

x.data = {
  name: 'Jim',
  age : 19
}

x.$init();

x.$digest();

x.data.name = 'Bob';
x.$digest();
// name has been changed from "Jim" to "Bob"

x.data.age = 200;
x.$digest();

// age has been changed from "19" to "200"

The age key works fine at the moment. But the name doesn't. I suspect it's to do with scoping in the following function:

Scope.prototype.$init = function() {
  $$ = this;
  $$.keys = Object.keys($$.data);

  for(var i=0; i<$$.keys.length; i++) {
    var key = $$.keys[i];

    $$.$watch(
      function(scope) { return scope.data[key] },
      function(newValue, oldValue, scope) {
        if(newValue) {
          console.log ('%s has been changed from "%s" to "%s"',key,oldValue, newValue)
        }
      }
    )
  }
}

The problem seems to be passing the var key into this: function(scope) { return scope.data[key] }, Here are the other two functions used:

Scope.prototype.$watch = function(watchFunction, listenerFunction) {
  var watcher = {
    watchFunction: watchFunction,
    listenerFunction: listenerFunction
  }

  this.watchers.unshift(watcher)
}

Scope.prototype.$digest = function() {
  var length = this.watchers.length;
  var watcher, newValue, oldValue

  while(length--) {
    watcher = this.watchers[length];
    newValue = watcher.watchFunction(this);
    oldValue = watcher.last;

    if(newValue !== oldValue) {
      watcher.last = newValue;
      watcher.listenerFunction(newValue, oldValue, this);
    }
  }
}

Has anybody got any ideas how to solve that function? If I initialise the watcher in the console it works perfectly but I want it automated so you don't have to define a watcher everytime you define a new variable.

andy
  • 2,369
  • 2
  • 31
  • 50
  • 1
    possible duplicate of [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – elclanrs Mar 19 '14 at 10:17

1 Answers1

0

Found a solution. The method is to use this:

Scope.prototype.$createWatcher = function(key) {
  return function(scope) { return scope.data[key] }
}

Then in the init function:

$$.$watch(
  $$.$createWatcher(key),
  function(newValue, oldValue, scope) {
    if(newValue) {
      console.log ('has been changed from "%s" to "%s"',oldValue, newValue)
    }
  }
)
andy
  • 2,369
  • 2
  • 31
  • 50