intercellular / cell

A self-driving web app framework
https://www.celljs.org
MIT License
1.51k stars 94 forks source link

Define a variable's attribute using another attribute of itself #153

Open gliechtenstein opened 7 years ago

gliechtenstein commented 7 years ago

It would be nice to be able to use _variables not just from functions but from attributes. For example in the following code I have to create 2 separate variables (template and c), and refer to template from c's _add() function:

var template = function(index) {
  return {
    class: "page hidden",
    $text: index,
    style: {
      zIndex: index,
      color: "white",
      background: '#'+Math.floor(Math.random()*16777215).toString(16)
    },
    $init: function() {
      this.class = "page";
    },
    onclick: function(e) {
      this._add();
    }
  }
};
var c = {
  $cell: true,
  _add: function() {
    this.$components.push(template(++this._index))
  },
  _index: 0,
  $components: [template(0)]
}

It would be nice if this could be somehow expressed as :

var c = {
  $cell: true,
  _add: function() {
    this.$components.push(this._template(++this._index))
  },
  template:  function(index) {
    return {
      class: "page hidden",
      $text: index,
      style: {
        zIndex: index,
        color: "white",
        background: '#'+Math.floor(Math.random()*16777215).toString(16)
      },
      $init: function() {
        this.class = "page";
      },
      onclick: function(e) {
        this._add();
      }
    }
  },
  _index: 0,
  $components: [this._template(0)]
}

Currently this is not possible because that's how JavaScript works--you can't refer to an object's attribute from its own definition. (In above case the this in this._template will be bound to the window object.

Even though this is not natively possible with JS maybe there's a clever way around it.

Caffeinix commented 6 years ago

What if $components accepted either an array or a function returning an array? Then we could have:

var c = {
  $cell: true,
  _add: function() {
    this.$components.push(this._template(++this._index))
  },
  template:  function(index) {
    return {
      class: "page hidden",
      $text: index,
      style: {
        zIndex: index,
        color: "white",
        background: '#'+Math.floor(Math.random()*16777215).toString(16)
      },
      $init: function() {
        this.class = "page";
      },
      onclick: function(e) {
        this._add();
      }
    }
  },
  _index: 0,
  $components: function() { return [this._template(0)]; }
}

The function would be invoked whenever $components would otherwise be read (so not at $init time or $update time).