5

From my littleexperience in Flex, I learned about Bindable variables, so that the content of a text element changed with th value of a variable, for example.

I'm wondering if it's possible to do such a thing in JavaScript. For instance, suppose I have an <h1 id="big_title"> that I want to contain the document's title. That can easily be done with document.getElementById('big_title').innerHTML = document.title;, but what if document.title changes? I'd have to manually update big_title as well.

Another way of putting it, is there a way to create a custom onchange-like event handler on a variable rather than a DOM element? This handler could update the title as needed.

EDIT: I know I could use a setInterval to check for variable "bindings" (defined in an array) and update as needed, but this would be somewhat hack-ish and would require a compromise between responsiveness and impact on performance.

Niet the Dark Absol
  • 301,028
  • 70
  • 427
  • 540

3 Answers3

3

You can "watch" objects in most major browsers. Here is a shim. The idea essentially is to have a setter (in that example it's the function called handler) that will be executed when the value changes. I'm not sure what the extent of browser support is.

Although to be honest it sounds like a much easier solution to have your own setter method. Either make it into an object (you can easily extend this example to use a generic handler insetad of always changing the title):

function Watchable(val) { // non-prototypal modelling to ensure privacy
   this.set = function(v){
      document.title=val=v;
   };
   this.get = function(){return val;};
   this.set(val);
}

var title = new Watchable("original title");

title.get(); // "original title"
title.set("second title"); // "second title"
title.get(); // "second title"

Or if it isn't something you need to instantiate multiple times, a simple function + convention will do:

function changeVal(newVal) {
   variableToWatch = newVal;
   // change some DOM content
}
Community
  • 1
  • 1
davin
  • 41,227
  • 7
  • 73
  • 77
0

The best way:

 (function (win) {
   function bindCtrl(id, varName) {
     var c = win.document.getElementById(id);
     if (!varName) varName = id;
     if (c) {
       Object.defineProperty(win, varName, {
         get: function () { return c.innerHTML; },
         set: function (v) { c.innerHTML = v; }
       });
     }

     return c;
   }

   win.bindCtrl = bindCtrl;
})(this);

// Bind control "test" to "x" variable
bindCtrl('test', 'x');

// Change value
x = 'Bar (prev: ' + x + ')';
<h1 id="test">Foo</h1>
Eduardo Cuomo
  • 13,985
  • 3
  • 93
  • 80
0

A simple method is to concentrate the related elements under one Javascript variable. This variable has a setter method and is bound to a user specified handler function that is called when the setter is invoked.

function Binder(handler) {
    this._value = 0; // will be set 
    this._handler = handler;
}
Binder.prototype.set = function(val) {
    this._value = val;
    this._handler(this);
};
Binder.prototype.get = function() {
    return this._value;
};

The Binder is used as follows:

<h1 id="h1">Title 0</h1>
<h2 id="h2">Title 0</h2>
<script type="text/javascript">
function titleHandler(variable) {
    var val = variable.get();
    document.getElementById("h1").innerHTML = val;
    document.getElementById("h2").innerHTML = "Sub" + val;
    document.title = val;
}
var title = new Binder(titleHandler);
title.set("Title 2");
</script>
Jiri Kriz
  • 8,866
  • 3
  • 26
  • 35