wip v-repeat: init working

This commit is contained in:
Evan You 2014-08-20 23:00:27 -04:00
parent 13253dbe3d
commit 1af8126e1e
2 changed files with 128 additions and 11 deletions

View File

@ -7,8 +7,7 @@ module.exports = {
var el = this.el
if (!el.__vue__) {
this.ref = document.createComment('v-if')
_.after(this.ref, el)
_.remove(el)
_.replace(el, this.ref)
this.inserted = false
if (el.tagName === 'TEMPLATE') {
this.el = templateParser.parse(el)

View File

@ -1,4 +1,7 @@
var _ = require('../util')
var textParser = require('../parse/text')
var expParser = require('../parse/expression')
var templateParser = require('../parse/template')
var uid = 0
module.exports = {
@ -17,9 +20,16 @@ module.exports = {
if (!this.filters) {
this.filters = []
}
this.filters.unshift('_objectToArray')
// check v-ref
this.filters.unshift({ name: '_objToArray' })
// check other directives that need to be handled
// at v-repeat level
this.checkIf()
this.checkRef()
this.checkComponent()
// check if this is a block repeat
if (this.el.tagName === 'TEMPLATE') {
this.el = templateParser.parse(this.el)
}
// setup ref node
this.ref = document.createComment('v-repeat')
_.replace(this.el, this.ref)
@ -27,6 +37,19 @@ module.exports = {
this.data = this.vms = this.oldData = this.oldVms = null
},
/**
* Warn against v-if usage.
*/
checkIf: function () {
if (_.attr(this.el, 'if') !== null) {
_.warn(
'Don\'t use v-if with v-repeat. ' +
'Use v-show or the "filterBy" filter instead.'
)
}
},
/**
* Check if v-ref is also present. If yes, evaluate it and
* locate the first non-anonymous parent as the owner vm.
@ -46,6 +69,38 @@ module.exports = {
}
},
/**
* Check the component constructor to use for repeated
* instances. If static we resolve it now, otherwise it
* needs to be resolved at build time with actual data.
*/
checkComponent: function () {
var id = _.attr(this.el, 'component')
if (!id) {
this.Ctor = _.Vue // default constructor
} else {
var tokens = textParser.parse(id)
if (!tokens.length) { // static component
this.Ctor = this.vm.$options.components[id]
if (!this.Ctor) {
_.warn('Failed to resolve component: ' + id)
this.Ctor = _.Vue
}
} else if (tokens.length === 1) {
// to be resolved later
this.CtorExp = tokens[0].value
} else {
_.warn(
'Invalid attribute binding: "' +
'component="' + id + '"' +
'\nDon\'t mix binding tags with plain text ' +
'in attribute bindings.'
)
}
}
},
/**
* Update.
* This is called whenever the Array mutates.
@ -61,6 +116,9 @@ module.exports = {
)
return
}
// converted = true means the Array was converted
// from an Object
this.converted = data._converted
this.oldVms = this.vms
this.oldData = this.data
this.data = data || []
@ -79,7 +137,17 @@ module.exports = {
*/
init: function () {
var data = this.data
var i = 0
var l = data.length
var vms = new Array(l)
var vm
for (; i < l; i++) {
vm = this.build(data[i], i)
vms[i] = vm
vm.$before(this.ref)
}
return vms
},
/**
@ -89,20 +157,70 @@ module.exports = {
*/
diff: function () {
// TODO
console.log('diffing...')
},
/**
* Build a new instance and cache it.
*
* @param {Object} data
* @param {Number} index
*/
build: function (data) {
// TODO: resolve constructor dynamically based on
// passed in data. may need to modify vm.$interpolate
// also, vm.$value should always point to the actual
// data in the user Array/Object.
build: function (data, index) {
var original = data
var raw = this.converted
? data.value
: data
var isObject = raw && typeof raw === 'object'
var hasAlias = !isObject || this.arg
// wrap the raw data with alias
data = hasAlias ? {} : raw
// resolve constructor
var Ctor = this.Ctor || this.resolveCtor(data)
var vm = new Ctor({
el: this.el.cloneNode(true),
data: data,
parent: this.vm
})
// define alias
if (hasAlias) {
var alias = this.arg || '$value'
vm.$add(alias, raw)
}
// define key
if (this.converted) {
vm.$add('$key', original.key)
}
// define index
vm.$add('$index', index)
// cache instance
if (isObject) {
this.cacheInstance(raw, vm)
}
return vm
},
/**
* Resolve a contructor to use for an instance.
* The tricky part here is that there could be dynamic
* components depending on instance data.
*
* @param {Object} data
* @return {Function}
*/
resolveCtor: function (data) {
var getter = expParser.parse(this.CtorExp).get
var context = Object.create(this.vm.$scope)
_.extend(context, data)
var id = getter(context)
var Ctor = this.vm.$options.components[id]
if (!Ctor) {
_.warn('Failed to resolve component: ' + id)
}
return Ctor
},
/**