Recently, I just finished getting all mustache tests to pass with a new "Scope" property lookup module. Here's the branch: https://github.com/bitovi/canjs/tree/mustache-scope-manipulation. This is the first step, and possibly the most difficult, step in supporting two-way binding and can.component type features.
Before going further, I'd like to talk about "Scope" and get suggestions for naming it, it's API, etc. Here's Scope:
And it's test: https://github.com/bitovi/canjs/blob/mustache-scope-manipulation/view/mustache/scope_test.js
"Scope" is a terrible name. It's more similar to how JavaScript's DOT operator walks up the proto-chain to find property values on "parent" objects or JavaScript's closure walks up call-objects/closures to find variable names. Here's an example:
- var me = {name: {first: "Justin", last: "Meyer"}, age: 30}
- meScoped = new Scope(me)
- nameScoped = me.add(me.name);
- nameScoped.attr('first') //-> "Justin"
- nameScoped.attr('age') //-> 30
Notice how nameScoped.attr('age') will
- look for properties on me.name, not find it
- go to it's parent scope (meScoped)
- return meScoped's age property
Basically, scopes walk up to parent scopes looking for a property value.
Scopes will have the same API as can.Observe. You will be able to use .attr, .bind, etc.
Scopes will be a big part of can.component as they will be the View-Model. For example, a template like:
<combo value="{{person.name}}" values="{{people}}"/>
Rendered with:
- var person = new Person(),
- people = new Person.List({})
- template({
- person: person,
- people: people
- })
Will create a scope object like:
- templateScope =new Scope({
- person: person,
- people: people
- })
And the scope object created for the Combo can.component will look like:
- comboScope = templateScope.add({
- value: person.compute('name')
- values: people
- })
A few random thoughts / questions for people who are following along:
- What should "Scope" be called? It's a horrible name.
- Should can.component inherit from "Scope"? This would allow you to change value like: this.attr('value', "John"). Or would it be better to do something like this.viewModel.attr("value","John").