Skip to content

Commit 22d2bdf

Browse files
committed
directives on a component written in its parent template should be compiled in the parent scope
1 parent 6d7e9f6 commit 22d2bdf

File tree

3 files changed

+57
-6
lines changed

3 files changed

+57
-6
lines changed

src/compile/compile.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,16 @@ function checkTerminalDirectives (el, options) {
415415
function makeTeriminalLinkFn (el, dirName, value, options) {
416416
var descriptor = dirParser.parse(value)[0]
417417
var def = options.directives[dirName]
418+
// special case: we need to collect directives found
419+
// on a component root node, but defined in the parent
420+
// template. These directives need to be compiled in
421+
// the parent scope.
422+
if (dirName === 'component') {
423+
var dirs = collectDirectives(el, options, true)
424+
el._parentLinker = dirs.length
425+
? makeDirectivesLinkFn(dirs)
426+
: null
427+
}
418428
var terminalLinkFn = function (vm, el) {
419429
vm._bindDir(dirName, el, descriptor, def)
420430
}
@@ -427,10 +437,11 @@ function makeTeriminalLinkFn (el, dirName, value, options) {
427437
*
428438
* @param {Element} el
429439
* @param {Object} options
440+
* @param {Boolean} asParent
430441
* @return {Array}
431442
*/
432443

433-
function collectDirectives (el, options) {
444+
function collectDirectives (el, options, asParent) {
434445
var attrs = _.toArray(el.attributes)
435446
var i = attrs.length
436447
var dirs = []
@@ -440,6 +451,12 @@ function collectDirectives (el, options) {
440451
attrName = attr.name
441452
if (attrName.indexOf(config.prefix) === 0) {
442453
dirName = attrName.slice(config.prefix.length)
454+
if (
455+
asParent &&
456+
(dirName === 'with' || dirName === 'ref')
457+
) {
458+
continue
459+
}
443460
dirDef = options.directives[dirName]
444461
_.assertAsset(dirDef, 'directive', dirName)
445462
if (dirDef) {

src/directives/component.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ module.exports = {
2222
_.replace(this.el, this.ref)
2323
// check keep-alive options
2424
this.checkKeepAlive()
25+
// check parent directives
26+
this.parentLinker = this.el._parentLinker
2527
// if static, build right now.
2628
if (!this._isDynamicLiteral) {
2729
this.resolveCtor(this.expression)
@@ -71,17 +73,26 @@ module.exports = {
7173

7274
build: function () {
7375
if (this.keepAlive) {
74-
var vm = this.cache[this.ctorId]
75-
if (vm) {
76-
this.childVM = vm
77-
vm.$before(this.ref)
76+
var cached = this.cache[this.ctorId]
77+
if (cached) {
78+
this.childVM = cached
79+
cached.$before(this.ref)
7880
return
7981
}
8082
}
83+
var vm = this.vm
8184
if (this.Ctor && !this.childVM) {
82-
this.childVM = this.vm.$addChild({
85+
this.childVM = vm.$addChild({
8386
el: templateParser.clone(this.el)
8487
}, this.Ctor)
88+
if (this.parentLinker) {
89+
var dirCount = vm._directives.length
90+
var targetVM = this.childVM.$options.inherit
91+
? this.childVM
92+
: vm
93+
this.parentLinker(targetVM, this.childVM.$el)
94+
this.parentDirs = vm._directives.slice(dirCount)
95+
}
8596
if (this.keepAlive) {
8697
this.cache[this.ctorId] = this.childVM
8798
}
@@ -106,6 +117,12 @@ module.exports = {
106117
}
107118
} else {
108119
this.childVM.$destroy(remove)
120+
if (this.parentDirs) {
121+
var i = this.parentDirs.length
122+
while (i--) {
123+
this.parentDirs[i]._teardown()
124+
}
125+
}
109126
}
110127
this.childVM = null
111128
},

test/unit/specs/directives/component_spec.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,23 @@ if (_.inBrowser) {
134134
})
135135
})
136136

137+
it('should compile parent template directives in parent scope', function (done) {
138+
var vm = new Vue({
139+
el: el,
140+
data: { ok: false },
141+
template: '<div v-component="test" v-show="ok"></div>',
142+
components: {
143+
test: {}
144+
}
145+
})
146+
expect(el.firstChild.style.display).toBe('none')
147+
vm.ok = true
148+
_.nextTick(function () {
149+
expect(el.firstChild.style.display).toBe('')
150+
done()
151+
})
152+
})
153+
137154
it('teardown', function () {
138155
var vm = new Vue({
139156
el: el,

0 commit comments

Comments
 (0)