Skip to content

Commit

Permalink
Change scope resolution to use prototype like approach instead of cop…
Browse files Browse the repository at this point in the history
…ying properties to children scopes.

Use $index instead of index for iteration index property name
  • Loading branch information
blikblum committed Aug 7, 2016
1 parent 9e70c2b commit 7203c10
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 39 deletions.
23 changes: 22 additions & 1 deletion lib/sightglass.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
function Observer(obj, keypath, callback, options) {
this.options = options || {}
this.options.adapters = this.options.adapters || {}
this.obj = obj
this.keypath = keypath
this.callback = callback
this.objectPath = []
this.update = this.update.bind(this)
this.parse()
this.obj = this.getRootObject(obj)

if (isObject(this.target = this.realize())) {
this.set(true, this.key, this.target, this.callback)
Expand Down Expand Up @@ -191,6 +191,27 @@
this.set(false, this.key, this.target, this.callback)
}
}
// traverse the scope chain to find the scope which has the root property
// if the property is not found in chain, returns the root scope
Observer.prototype.getRootObject = function (obj) {
var rootProp, current;
if (!obj.$parent) {
return obj;
}

if (this.tokens.length) {
rootProp = this.tokens[0].path
} else {
rootProp = this.key.path
}

current = obj;
while (current.$parent && (current[rootProp] === undefined)) {
current = current.$parent
}

return current;
}

// Check if a value is an object than can be observed.
function isObject(obj) {
Expand Down
14 changes: 12 additions & 2 deletions spec/rivets/binders.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ describe("Rivets.binders", function() {
};
});

it.skip("lets you access index from current and parent scope", function() {
nestedEl.textContent = '{%item%}-{%nested%}';
it("lets you access index from current and parent scope", function() {
nestedEl.textContent = '{$parent.$index}-{$index}';
var view = rivets.bind(el, model);

Should(fragment.childNodes[1].childNodes[1].textContent).be.exactly('0-0');
Expand All @@ -151,6 +151,16 @@ describe("Rivets.binders", function() {
Should(fragment.childNodes[1].childNodes[2].textContent).be.exactly('New!Level 1 - 0');
Should(fragment.childNodes[2].childNodes[2].textContent).be.exactly('New!Level 1 - 1');
});

it("reflects changes when an undefined property is set in root scope", function() {
nestedEl.textContent = '{unset}';
var view = rivets.bind(el, model);
model.unset = 'NotUndefined';
Should(fragment.childNodes[1].childNodes[1].textContent).be.exactly('NotUndefined');
Should(fragment.childNodes[1].childNodes[2].textContent).be.exactly('NotUndefined');
Should(fragment.childNodes[2].childNodes[2].textContent).be.exactly('NotUndefined');
});

});

describe("if", function() {
Expand Down
19 changes: 4 additions & 15 deletions spec/rivets/functional.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,28 +232,17 @@ describe('Functional', function() {
el.getElementsByTagName('li')[3].textContent.should.equal('last')
});

it.skip('should allow binding to the iterated element index', function() {
listItem.setAttribute('data-index', 'index');
it('should allow binding to the iterated element index', function() {
listItem.setAttribute('data-index', '$index');
rivets.bind(el, bindData);
el.getElementsByTagName('li')[0].getAttribute('index').should.equal('0');
el.getElementsByTagName('li')[1].getAttribute('index').should.equal('1')
});

it.skip('should allow binding to the iterated element index by using the %item% syntax', function() {
listItem.setAttribute('data-index', '%item%');
rivets.bind(el, bindData);
el.getElementsByTagName('li')[0].getAttribute('index').should.equal('0');
el.getElementsByTagName('li')[1].getAttribute('index').should.equal('1')
});

it.skip('should allow the developer to configure the index attribute available in the iteration', function() {
rivets.configure({
iterationAlias : function(modelName) {
return modelName + 'Index';
}
});

it('should allow the developer to configure the index attribute available in the iteration', function() {
listItem.setAttribute('data-index', 'itemIndex');
listItem.setAttribute('index-property', 'itemIndex');
rivets.bind(el, bindData);
el.getElementsByTagName('li')[0].getAttribute('index').should.equal('0');
el.getElementsByTagName('li')[1].getAttribute('index').should.equal('1')
Expand Down
36 changes: 15 additions & 21 deletions src/binders.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ const binders = {
priority: 4000,

bind: function(el) {
if (!defined(this.marker)) {
if (!this.marker) {
let attr = [this.view.prefix, this.type].join('-').replace('--', '-')
let declaration = el.getAttribute(attr)

Expand All @@ -157,7 +157,7 @@ const binders = {
},

unbind: function() {
if (defined(this.nested)) {
if (this.nested) {
this.nested.unbind()
this.bound = false
}
Expand All @@ -166,16 +166,11 @@ const binders = {
routine: function(el, value) {
if (!!value === !this.bound) {
if (value) {
let models = {}

This comment has been minimized.

Copy link
@Namek

Namek May 23, 2017

do you maybe know if this object was shallow-cloned on purpose? Or did you just remove it from here without thinking about that?

This comment has been minimized.

Copy link
@blikblum

blikblum May 23, 2017

Author Owner

I think about that. It fixes the issues of nested scope binding. The related issues are linked in the readme of svelte branch


Object.keys(this.view.models).forEach(key => {
models[key] = this.view.models[key]
})

if (defined(this.nested)) {
if (this.nested) {
this.nested.bind()
} else {
this.nested = rivets.bind(el, models, this.view.options())
this.nested = rivets.bind(el, this.view.models, this.view.options())
}

this.marker.parentNode.insertBefore(el, this.marker.nextSibling)
Expand All @@ -189,7 +184,7 @@ const binders = {
},

update: function(models) {
if (defined(this.nested)) {
if (this.nested) {
this.nested.update(models)
}
}
Expand Down Expand Up @@ -224,13 +219,13 @@ const binders = {
priority: 1000,

unbind: function(el) {
if (defined(this.handler)) {
if (this.handler) {
unbindEvent(el, this.args[0], this.handler)
}
},

routine: function(el, value) {
if (defined(this.handler)) {
if (this.handler) {
unbindEvent(el, this.args[0], this.handler)
}

Expand All @@ -245,7 +240,7 @@ const binders = {
priority: 4000,

bind: function(el) {
if (!defined(this.marker)) {
if (!this.marker) {
let attr = [this.view.prefix, this.type].join('-').replace('--', '-')
this.marker = document.createComment(` rivets: ${this.type} `)
this.iterated = []
Expand All @@ -261,7 +256,7 @@ const binders = {
},

unbind: function(el) {
if (defined(this.iterated)) {
if (this.iterated) {
this.iterated.forEach(view => {
view.unbind()
})
Expand All @@ -271,6 +266,7 @@ const binders = {
routine: function(el, collection) {
let modelName = this.args[0]
let collection = collection || []
let indexProp = el.getAttribute('index-property') || '$index'

if (this.iterated.length > collection.length) {
times(this.iterated.length - collection.length, () => {
Expand All @@ -281,15 +277,11 @@ const binders = {
}

collection.forEach((model, index) => {
let data = {index: index, $parent: this.model}
let data = {$parent: this.view.models}
data[indexProp] = index
data[modelName] = model

if (!defined(this.iterated[index])) {
Object.keys(this.view.models).forEach(key => {
if (!defined(data[key])) {
data[key] = this.view.models[key]
}
})
if (!this.iterated[index]) {

let previous = this.marker

Expand Down Expand Up @@ -321,6 +313,8 @@ const binders = {
update: function(models) {
let data = {}

//todo: add test and fix if necessary

Object.keys(models).forEach(key => {
if (key !== this.args[0]) {
data[key] = models[key]
Expand Down

0 comments on commit 7203c10

Please sign in to comment.