directly use array length

This commit is contained in:
Evan You 2013-08-22 16:30:51 -04:00
parent 0a45bb813f
commit 77ce1fc355
4 changed files with 77 additions and 15 deletions

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SEED repeated items</title>
<meta charset="utf-8">
</head>
<body>
<div id="app">
<ul>
<li sd-each="item:items" sd-text="item.title"></li>
</ul>
<p>Total items: {{items.length}}</p>
</div>
<script src="../dist/seed.js"></script>
<script>
seed.config({debug: true})
var items = [
{ title: 'hi' },
{ title: 'ha' },
{ title: 'hu' },
{ title: 'ho' },
{ title: 'he' }
]
var test = {
test: [1, 2, 3]
}
var demo = new seed.ViewModel({
el: '#app',
data: {
items: items,
test: test
}
})
</script>
</body>
</html>

View File

@ -73,6 +73,7 @@ function Compiler (vm, options) {
var observables = this.observables = [] var observables = this.observables = []
var computed = this.computed = [] // computed props to parse deps from var computed = this.computed = [] // computed props to parse deps from
var ctxBindings = this.contextBindings = [] // computed props with dynamic context var ctxBindings = this.contextBindings = [] // computed props with dynamic context
var arrays = this.arrays = []
// prototypal inheritance of bindings // prototypal inheritance of bindings
var parent = this.parentCompiler var parent = this.parentCompiler
@ -113,12 +114,18 @@ function Compiler (vm, options) {
binding = observables[i] binding = observables[i]
Observer.observe(binding.value, binding.key, this.observer) Observer.observe(binding.value, binding.key, this.observer)
} }
// emit set events for array lengths
i = arrays.length
while (i--) {
binding = arrays[i]
this.observer.emit('set', binding.key + '.length', binding.value.length)
}
// extract dependencies for computed properties // extract dependencies for computed properties
if (computed.length) DepsParser.parse(computed) if (computed.length) DepsParser.parse(computed)
// extract dependencies for computed properties with dynamic context // extract dependencies for computed properties with dynamic context
if (ctxBindings.length) this.bindContexts(ctxBindings) if (ctxBindings.length) this.bindContexts(ctxBindings)
// unset these no longer needed stuff
this.observables = this.computed = this.contextBindings = null this.observables = this.computed = this.contextBindings = this.arrays = null
} }
var CompilerProto = Compiler.prototype var CompilerProto = Compiler.prototype
@ -141,14 +148,17 @@ CompilerProto.setupObserver = function () {
// add own listeners which trigger binding updates // add own listeners which trigger binding updates
observer observer
.on('get', function (key) { .on('get', function (key) {
if (depsOb.isObserving && bindings[key]) { console.log('get ' + key)
if (bindings[key] && depsOb.isObserving) {
depsOb.emit('get', bindings[key]) depsOb.emit('get', bindings[key])
} }
}) })
.on('set', function (key, val) { .on('set', function (key, val) {
console.log('set ' + key)
if (bindings[key]) bindings[key].update(val) if (bindings[key]) bindings[key].update(val)
}) })
.on('mutate', function (key) { .on('mutate', function (key) {
console.log('mutate ' + key)
if (bindings[key]) bindings[key].pub() if (bindings[key]) bindings[key].pub()
}) })
} }
@ -300,7 +310,9 @@ CompilerProto.bindDirective = function (directive) {
} }
// set initial value // set initial value
directive.update(binding.value) if (binding.value) {
directive.update(binding.value)
}
if (binding.isComputed) { if (binding.isComputed) {
directive.refresh() directive.refresh()
} }
@ -375,13 +387,16 @@ CompilerProto.define = function (key, binding) {
this.computed.push(binding) this.computed.push(binding)
} else { } else {
// observe objects later, becase there might be more keys // observe objects later, becase there might be more keys
// to be added to it // to be added to it. we also want to emit all the set events
// when values are available.
this.observables.push(binding) this.observables.push(binding)
} }
} else if (type === 'Array') { } else if (type === 'Array') {
// observe arrays right now, because they will be needed in // observe arrays right now, because they will be needed in
// sd-each directives. // sd-each directives.
Observer.observe(value, key, compiler.observer) Observer.observe(value, key, compiler.observer)
// we need to later emit set event for the arrays length.
this.arrays.push(binding)
} }
Object.defineProperty(vm, key, { Object.defineProperty(vm, key, {

View File

@ -83,7 +83,7 @@ module.exports = {
ctn.removeChild(this.el) ctn.removeChild(this.el)
this.collection = null this.collection = null
this.vms = null this.vms = null
this.mutationListener = (function (mutation) { this.mutationListener = (function (path, arr, mutation) {
mutationHandlers[mutation.method].call(this, mutation) mutationHandlers[mutation.method].call(this, mutation)
}).bind(this) }).bind(this)
}, },
@ -102,7 +102,6 @@ module.exports = {
this.collection = collection this.collection = collection
this.vms = [] this.vms = []
console.log(collection)
// listen for collection mutation events // listen for collection mutation events
// the collection has been augmented during Binding.set() // the collection has been augmented during Binding.set()
collection.__observer__.on('mutate', this.mutationListener) collection.__observer__.on('mutate', this.mutationListener)
@ -120,16 +119,16 @@ module.exports = {
this.container.insertBefore(node, ref) this.container.insertBefore(node, ref)
ViewModel = ViewModel || require('../viewmodel') ViewModel = ViewModel || require('../viewmodel')
var vmID = node.getAttribute(config.prefix + '-viewmodel'), var vmID = node.getAttribute(config.prefix + '-viewmodel'),
ChildVM = utils.getVM(vmID) || ViewModel ChildVM = utils.getVM(vmID) || ViewModel,
wrappedData = {}
wrappedData[this.arg] = data
var item = new ChildVM({ var item = new ChildVM({
el: node, el: node,
each: true, each: true,
eachPrefix: this.arg, eachPrefix: this.arg,
parentCompiler: this.compiler, parentCompiler: this.compiler,
delegator: this.container, delegator: this.container,
data: { data: wrappedData
todo: data
}
}) })
if (dummy) { if (dummy) {
item.$destroy() item.$destroy()

View File

@ -101,10 +101,10 @@ function emitSet (obj, observer) {
module.exports = { module.exports = {
observe: function (obj, path, observer) { observe: function (obj, rawPath, observer) {
if (isWatchable(obj)) { if (isWatchable(obj)) {
path = path + '.' var path = rawPath + '.',
var ob, alreadyConverted = !!obj.__observer__ ob, alreadyConverted = !!obj.__observer__
if (!alreadyConverted) { if (!alreadyConverted) {
defProtected(obj, '__observer__', new Emitter()) defProtected(obj, '__observer__', new Emitter())
} }
@ -117,7 +117,15 @@ module.exports = {
observer.emit('set', path + key, val) observer.emit('set', path + key, val)
}, },
mutate: function (key, val, mutation) { mutate: function (key, val, mutation) {
observer.emit('mutate', path + key, val, mutation) // if the Array is a root value
// the key will be null
var fixedPath = key ? path + key : rawPath
observer.emit('mutate', fixedPath, val, mutation)
// also emit set for Array's length when it mutates
var m = mutation.method
if (m !== 'sort' && m !== 'reverse') {
observer.emit('set', fixedPath + '.length', val.length)
}
} }
} }
ob ob