Skip to content

Commit

Permalink
feat: allow to pass props to child components (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
ktsn committed Apr 24, 2018
1 parent dc43f42 commit 3989f24
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 10 deletions.
6 changes: 6 additions & 0 deletions src/view/components/ContainerVueComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
:data="document.data"
:child-components="document.childComponents"
:styles="document.styleCode"
:props-data="propsData"
/>
</template>

Expand All @@ -26,6 +27,11 @@ export default Vue.extend({
uri: {
type: String,
required: true
},
propsData: {
type: Object as () => Record<string, any>,
required: true
}
},
Expand Down
6 changes: 5 additions & 1 deletion src/view/components/Node.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,12 @@ export default Vue.extend({
}
}
// If there is matched nodeUri, the vnode will be ContainerVueComponent
if (this.nodeUri) {
data.props = { uri: this.nodeUri }
data.props = {
uri: this.nodeUri,
propsData: data.attrs
}
}
return data
Expand Down
20 changes: 12 additions & 8 deletions src/view/components/VueComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import Vue, { VNode } from 'vue'
import Child from './Child.vue'
import { Template } from '@/parser/template/types'
import { DefaultValue, Prop, Data, ChildComponent } from '@/parser/script/types'
import { Prop, Data, ChildComponent } from '@/parser/script/types'
import { resolveControlDirectives, ResolvedChild } from '../rendering'
export default Vue.extend({
Expand All @@ -29,18 +29,22 @@ export default Vue.extend({
childComponents: {
type: Array as { (): ChildComponent[] },
required: true
},
propsData: {
type: Object as { (): Record<string, any> },
default: () => ({})
}
},
computed: {
scope(): Record<string, DefaultValue> {
const scope: Record<string, DefaultValue> = {}
const data: { name: string; default?: DefaultValue }[] = [
...this.props,
...this.data
]
scope(): Record<string, any> {
const scope: Record<string, any> = {}
this.props.forEach(({ name, default: value }) => {
scope[name] = name in this.propsData ? this.propsData[name] : value
})
data.forEach(({ name, default: value }) => {
this.data.forEach(({ name, default: value }) => {
scope[name] = value
})
Expand Down
112 changes: 111 additions & 1 deletion test/view/VueComponent/child-component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createTemplate, h, render, exp, a } from '../../helpers/template'
import { createTemplate, h, render, exp, a, d } from '../../helpers/template'

describe('VueComponent child components', () => {
it('should render child components in the store', () => {
Expand Down Expand Up @@ -91,4 +91,114 @@ describe('VueComponent child components', () => {
// should resolved as child component value
expect(wrapper.find('#second').text()).toBe('should render child value')
})

it('passes attribute values as props to a child component', () => {
// prettier-ignore
const template = createTemplate([
h('div', [], [
h('Foo', [a('message', 'hello from parent')], [])
])
])

const components = {
'file:///Foo.vue': {
// prettier-ignore
template: createTemplate([
h('h1', [], [exp('message')])
]),
props: [
{
name: 'message',
type: 'String'
}
]
}
}
const wrapper = render(
template,
[],
[],
[
{
name: 'Foo',
uri: 'file:///Foo.vue'
}
],
components
)
expect(wrapper.find('h1').text()).toBe('hello from parent')
})

it('passes v-bind values as props to a child component', () => {
// prettier-ignore
const template = createTemplate([
h('div', [], [
h('Foo', [d('bind', { argument: 'childMessage' }, 'message')], [])
])
])

const components = {
'file:///Foo.vue': {
// prettier-ignore
template: createTemplate([
h('h1', [], [exp('childMessage')])
]),
props: [
{
name: 'childMessage',
type: 'String'
}
]
}
}
const wrapper = render(
template,
[],
[
{
name: 'message',
default: 'hello from parent v-bind'
}
],
[
{
name: 'Foo',
uri: 'file:///Foo.vue'
}
],
components
)
expect(wrapper.find('h1').text()).toBe('hello from parent v-bind')
})

it('does not pass props if child component does not declare it', () => {
// prettier-ignore
const template = createTemplate([
h('div', [], [
h('Foo', [a('message', 'hello from parent')], [])
])
])

const components = {
'file:///Foo.vue': {
// prettier-ignore
template: createTemplate([
h('h1', [], [exp('message')])
])
}
}
const wrapper = render(
template,
[],
[],
[
{
name: 'Foo',
uri: 'file:///Foo.vue'
}
],
components
)
expect(wrapper.find('h1').text()).toBe('{{ message }}') // not resolved
})
})

0 comments on commit 3989f24

Please sign in to comment.