Databinding entire objects between child Vue components and the root Vue instance
up vote
1
down vote
favorite
I have a form in which I am collecting data from two applicants. In order to minimize HTML duplication I built an applicant Vue component that generates each applicant from a template.
Each applicant has an applicant data object. My question is regarding the best practice for data binding these applicant objects inside the component back to the root Vue instance. Here is my working code:
Vue Root Instance
var app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
})
Template
<script type="x-template" id="applicant-container">
<div class="row">
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
Component
The applicant prop gives me access to the applicant objects in the root Vue instance
Vue.component('applicant', {
template: '#applicant-container',
props: ['applicant'],
})
Component Instance
I pass each applicant object to the component instance through the applicant prop.
<applicant :applicant="form.borrower"></applicant>
<applicant :applicant="form.coborrower"></applicant>
This code works perfectly. Any changes that are made using the inputs generated from the components is reflected when I output the applicant objects e.g
{{ form.borrower }}
{{ form.coborrower }}
The thing that I'm unsure about is this approach best practice? The Vue's docs state
...the parent may need to pass data down to the child, and the child may need to inform the parent of something that happened in the child. However, it is also very important to keep the parent and the child as decoupled as possible via a clearly-defined interface
Every component instance has its own isolated scope. This means you cannot (and should not) directly reference parent data in a child component’s template1
Since I'm passing the parent applicant object to the component and am modifying it directly through that passed in reference using the v-model directive am I not directly modifying the parent object so therefore keeping the data coupled as the docs recommended against.
1https://vuejs.org/v2/guide/components.html#Composing-Components
javascript vue.js databinding
add a comment |
up vote
1
down vote
favorite
I have a form in which I am collecting data from two applicants. In order to minimize HTML duplication I built an applicant Vue component that generates each applicant from a template.
Each applicant has an applicant data object. My question is regarding the best practice for data binding these applicant objects inside the component back to the root Vue instance. Here is my working code:
Vue Root Instance
var app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
})
Template
<script type="x-template" id="applicant-container">
<div class="row">
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
Component
The applicant prop gives me access to the applicant objects in the root Vue instance
Vue.component('applicant', {
template: '#applicant-container',
props: ['applicant'],
})
Component Instance
I pass each applicant object to the component instance through the applicant prop.
<applicant :applicant="form.borrower"></applicant>
<applicant :applicant="form.coborrower"></applicant>
This code works perfectly. Any changes that are made using the inputs generated from the components is reflected when I output the applicant objects e.g
{{ form.borrower }}
{{ form.coborrower }}
The thing that I'm unsure about is this approach best practice? The Vue's docs state
...the parent may need to pass data down to the child, and the child may need to inform the parent of something that happened in the child. However, it is also very important to keep the parent and the child as decoupled as possible via a clearly-defined interface
Every component instance has its own isolated scope. This means you cannot (and should not) directly reference parent data in a child component’s template1
Since I'm passing the parent applicant object to the component and am modifying it directly through that passed in reference using the v-model directive am I not directly modifying the parent object so therefore keeping the data coupled as the docs recommended against.
1https://vuejs.org/v2/guide/components.html#Composing-Components
javascript vue.js databinding
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I have a form in which I am collecting data from two applicants. In order to minimize HTML duplication I built an applicant Vue component that generates each applicant from a template.
Each applicant has an applicant data object. My question is regarding the best practice for data binding these applicant objects inside the component back to the root Vue instance. Here is my working code:
Vue Root Instance
var app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
})
Template
<script type="x-template" id="applicant-container">
<div class="row">
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
Component
The applicant prop gives me access to the applicant objects in the root Vue instance
Vue.component('applicant', {
template: '#applicant-container',
props: ['applicant'],
})
Component Instance
I pass each applicant object to the component instance through the applicant prop.
<applicant :applicant="form.borrower"></applicant>
<applicant :applicant="form.coborrower"></applicant>
This code works perfectly. Any changes that are made using the inputs generated from the components is reflected when I output the applicant objects e.g
{{ form.borrower }}
{{ form.coborrower }}
The thing that I'm unsure about is this approach best practice? The Vue's docs state
...the parent may need to pass data down to the child, and the child may need to inform the parent of something that happened in the child. However, it is also very important to keep the parent and the child as decoupled as possible via a clearly-defined interface
Every component instance has its own isolated scope. This means you cannot (and should not) directly reference parent data in a child component’s template1
Since I'm passing the parent applicant object to the component and am modifying it directly through that passed in reference using the v-model directive am I not directly modifying the parent object so therefore keeping the data coupled as the docs recommended against.
1https://vuejs.org/v2/guide/components.html#Composing-Components
javascript vue.js databinding
I have a form in which I am collecting data from two applicants. In order to minimize HTML duplication I built an applicant Vue component that generates each applicant from a template.
Each applicant has an applicant data object. My question is regarding the best practice for data binding these applicant objects inside the component back to the root Vue instance. Here is my working code:
Vue Root Instance
var app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
})
Template
<script type="x-template" id="applicant-container">
<div class="row">
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
Component
The applicant prop gives me access to the applicant objects in the root Vue instance
Vue.component('applicant', {
template: '#applicant-container',
props: ['applicant'],
})
Component Instance
I pass each applicant object to the component instance through the applicant prop.
<applicant :applicant="form.borrower"></applicant>
<applicant :applicant="form.coborrower"></applicant>
This code works perfectly. Any changes that are made using the inputs generated from the components is reflected when I output the applicant objects e.g
{{ form.borrower }}
{{ form.coborrower }}
The thing that I'm unsure about is this approach best practice? The Vue's docs state
...the parent may need to pass data down to the child, and the child may need to inform the parent of something that happened in the child. However, it is also very important to keep the parent and the child as decoupled as possible via a clearly-defined interface
Every component instance has its own isolated scope. This means you cannot (and should not) directly reference parent data in a child component’s template1
Since I'm passing the parent applicant object to the component and am modifying it directly through that passed in reference using the v-model directive am I not directly modifying the parent object so therefore keeping the data coupled as the docs recommended against.
1https://vuejs.org/v2/guide/components.html#Composing-Components
javascript vue.js databinding
javascript vue.js databinding
edited Jan 8 at 6:08
Sᴀᴍ Onᴇᴌᴀ
8,13861752
8,13861752
asked Nov 27 '17 at 5:35
CodeMonkey
63
63
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
General feedback
The use of the <script>
tag as a template is nice and I have aimed to use that more frequently in my own projects when not using a larger template library.
Doesn’t it seem a bit redundant to have a compnent called applicant
, which has a property called applicant
? Perhaps a more generic name for those properties would be more appropriate - e.g. attributes
. However, the advice below, which responds to your question, suggests binding the applicant to the model
attribute instead of a property.
Main question
Since I'm passing the parent applicant object to the component and am modifying it directly through that passed in reference using the v-model directive am I not directly modifying the parent object so therefore keeping the data coupled as the docs recommended against.
Your question appears nearly identical to this SO question, though in your case you have working code and are passing an object instead of a single value. To follow the guidelines in the documentation, perhaps altering the code as described in the answer by asemahle would be an optimal route.
Change the property from
applicant
tovalue
.
props: ['value'],
And in the markup, use
v-model
instead of the property for applicant:
<applicant v-model="form.borrower"></applicant>
<applicant v-model="form.coborrower"></applicant>
Add
applicant
via the the local data properties:
data: function() {
return {
applicant: {}
}
},
When the component is created, set the
applicant
to thevalue
property:
created: function() {
this.applicant = this.value;
}
Watch for changes on the local data property
applicant
and emit an event in response to that change
watch: {
'applicant': function() {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
}
Below is a demonstration:
Vue.component('applicant', {
template: '#applicant-container',
props: ['value'],
watch: {
'applicant': function(valueChanged) {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
},
data: function() {
return {
applicant: {}
}
},
created: function() {
this.applicant = this.value;
}
})
// Root Vue instance
const app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
});
.row {
border: 2px solid #5CD7FF;
margin: 2px;
padding: 4px;
}
.label {
font-style: italic;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
<h3>Borrower:</h3> in parent:{{ form.borrower }}
<applicant v-model="form.borrower"></applicant>
<h3>Co-borrower:</h3> in parent:{{ form.coborrower }}
<applicant v-model="form.coborrower"></applicant>
</div>
<script type="x-template" id="applicant-container">
<div class="row"><span class="label">Applicant Template:</span>
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f181375%2fdatabinding-entire-objects-between-child-vue-components-and-the-root-vue-instanc%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
General feedback
The use of the <script>
tag as a template is nice and I have aimed to use that more frequently in my own projects when not using a larger template library.
Doesn’t it seem a bit redundant to have a compnent called applicant
, which has a property called applicant
? Perhaps a more generic name for those properties would be more appropriate - e.g. attributes
. However, the advice below, which responds to your question, suggests binding the applicant to the model
attribute instead of a property.
Main question
Since I'm passing the parent applicant object to the component and am modifying it directly through that passed in reference using the v-model directive am I not directly modifying the parent object so therefore keeping the data coupled as the docs recommended against.
Your question appears nearly identical to this SO question, though in your case you have working code and are passing an object instead of a single value. To follow the guidelines in the documentation, perhaps altering the code as described in the answer by asemahle would be an optimal route.
Change the property from
applicant
tovalue
.
props: ['value'],
And in the markup, use
v-model
instead of the property for applicant:
<applicant v-model="form.borrower"></applicant>
<applicant v-model="form.coborrower"></applicant>
Add
applicant
via the the local data properties:
data: function() {
return {
applicant: {}
}
},
When the component is created, set the
applicant
to thevalue
property:
created: function() {
this.applicant = this.value;
}
Watch for changes on the local data property
applicant
and emit an event in response to that change
watch: {
'applicant': function() {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
}
Below is a demonstration:
Vue.component('applicant', {
template: '#applicant-container',
props: ['value'],
watch: {
'applicant': function(valueChanged) {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
},
data: function() {
return {
applicant: {}
}
},
created: function() {
this.applicant = this.value;
}
})
// Root Vue instance
const app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
});
.row {
border: 2px solid #5CD7FF;
margin: 2px;
padding: 4px;
}
.label {
font-style: italic;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
<h3>Borrower:</h3> in parent:{{ form.borrower }}
<applicant v-model="form.borrower"></applicant>
<h3>Co-borrower:</h3> in parent:{{ form.coborrower }}
<applicant v-model="form.coborrower"></applicant>
</div>
<script type="x-template" id="applicant-container">
<div class="row"><span class="label">Applicant Template:</span>
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
add a comment |
up vote
0
down vote
General feedback
The use of the <script>
tag as a template is nice and I have aimed to use that more frequently in my own projects when not using a larger template library.
Doesn’t it seem a bit redundant to have a compnent called applicant
, which has a property called applicant
? Perhaps a more generic name for those properties would be more appropriate - e.g. attributes
. However, the advice below, which responds to your question, suggests binding the applicant to the model
attribute instead of a property.
Main question
Since I'm passing the parent applicant object to the component and am modifying it directly through that passed in reference using the v-model directive am I not directly modifying the parent object so therefore keeping the data coupled as the docs recommended against.
Your question appears nearly identical to this SO question, though in your case you have working code and are passing an object instead of a single value. To follow the guidelines in the documentation, perhaps altering the code as described in the answer by asemahle would be an optimal route.
Change the property from
applicant
tovalue
.
props: ['value'],
And in the markup, use
v-model
instead of the property for applicant:
<applicant v-model="form.borrower"></applicant>
<applicant v-model="form.coborrower"></applicant>
Add
applicant
via the the local data properties:
data: function() {
return {
applicant: {}
}
},
When the component is created, set the
applicant
to thevalue
property:
created: function() {
this.applicant = this.value;
}
Watch for changes on the local data property
applicant
and emit an event in response to that change
watch: {
'applicant': function() {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
}
Below is a demonstration:
Vue.component('applicant', {
template: '#applicant-container',
props: ['value'],
watch: {
'applicant': function(valueChanged) {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
},
data: function() {
return {
applicant: {}
}
},
created: function() {
this.applicant = this.value;
}
})
// Root Vue instance
const app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
});
.row {
border: 2px solid #5CD7FF;
margin: 2px;
padding: 4px;
}
.label {
font-style: italic;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
<h3>Borrower:</h3> in parent:{{ form.borrower }}
<applicant v-model="form.borrower"></applicant>
<h3>Co-borrower:</h3> in parent:{{ form.coborrower }}
<applicant v-model="form.coborrower"></applicant>
</div>
<script type="x-template" id="applicant-container">
<div class="row"><span class="label">Applicant Template:</span>
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
add a comment |
up vote
0
down vote
up vote
0
down vote
General feedback
The use of the <script>
tag as a template is nice and I have aimed to use that more frequently in my own projects when not using a larger template library.
Doesn’t it seem a bit redundant to have a compnent called applicant
, which has a property called applicant
? Perhaps a more generic name for those properties would be more appropriate - e.g. attributes
. However, the advice below, which responds to your question, suggests binding the applicant to the model
attribute instead of a property.
Main question
Since I'm passing the parent applicant object to the component and am modifying it directly through that passed in reference using the v-model directive am I not directly modifying the parent object so therefore keeping the data coupled as the docs recommended against.
Your question appears nearly identical to this SO question, though in your case you have working code and are passing an object instead of a single value. To follow the guidelines in the documentation, perhaps altering the code as described in the answer by asemahle would be an optimal route.
Change the property from
applicant
tovalue
.
props: ['value'],
And in the markup, use
v-model
instead of the property for applicant:
<applicant v-model="form.borrower"></applicant>
<applicant v-model="form.coborrower"></applicant>
Add
applicant
via the the local data properties:
data: function() {
return {
applicant: {}
}
},
When the component is created, set the
applicant
to thevalue
property:
created: function() {
this.applicant = this.value;
}
Watch for changes on the local data property
applicant
and emit an event in response to that change
watch: {
'applicant': function() {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
}
Below is a demonstration:
Vue.component('applicant', {
template: '#applicant-container',
props: ['value'],
watch: {
'applicant': function(valueChanged) {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
},
data: function() {
return {
applicant: {}
}
},
created: function() {
this.applicant = this.value;
}
})
// Root Vue instance
const app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
});
.row {
border: 2px solid #5CD7FF;
margin: 2px;
padding: 4px;
}
.label {
font-style: italic;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
<h3>Borrower:</h3> in parent:{{ form.borrower }}
<applicant v-model="form.borrower"></applicant>
<h3>Co-borrower:</h3> in parent:{{ form.coborrower }}
<applicant v-model="form.coborrower"></applicant>
</div>
<script type="x-template" id="applicant-container">
<div class="row"><span class="label">Applicant Template:</span>
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
General feedback
The use of the <script>
tag as a template is nice and I have aimed to use that more frequently in my own projects when not using a larger template library.
Doesn’t it seem a bit redundant to have a compnent called applicant
, which has a property called applicant
? Perhaps a more generic name for those properties would be more appropriate - e.g. attributes
. However, the advice below, which responds to your question, suggests binding the applicant to the model
attribute instead of a property.
Main question
Since I'm passing the parent applicant object to the component and am modifying it directly through that passed in reference using the v-model directive am I not directly modifying the parent object so therefore keeping the data coupled as the docs recommended against.
Your question appears nearly identical to this SO question, though in your case you have working code and are passing an object instead of a single value. To follow the guidelines in the documentation, perhaps altering the code as described in the answer by asemahle would be an optimal route.
Change the property from
applicant
tovalue
.
props: ['value'],
And in the markup, use
v-model
instead of the property for applicant:
<applicant v-model="form.borrower"></applicant>
<applicant v-model="form.coborrower"></applicant>
Add
applicant
via the the local data properties:
data: function() {
return {
applicant: {}
}
},
When the component is created, set the
applicant
to thevalue
property:
created: function() {
this.applicant = this.value;
}
Watch for changes on the local data property
applicant
and emit an event in response to that change
watch: {
'applicant': function() {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
}
Below is a demonstration:
Vue.component('applicant', {
template: '#applicant-container',
props: ['value'],
watch: {
'applicant': function(valueChanged) {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
},
data: function() {
return {
applicant: {}
}
},
created: function() {
this.applicant = this.value;
}
})
// Root Vue instance
const app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
});
.row {
border: 2px solid #5CD7FF;
margin: 2px;
padding: 4px;
}
.label {
font-style: italic;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
<h3>Borrower:</h3> in parent:{{ form.borrower }}
<applicant v-model="form.borrower"></applicant>
<h3>Co-borrower:</h3> in parent:{{ form.coborrower }}
<applicant v-model="form.coborrower"></applicant>
</div>
<script type="x-template" id="applicant-container">
<div class="row"><span class="label">Applicant Template:</span>
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
Vue.component('applicant', {
template: '#applicant-container',
props: ['value'],
watch: {
'applicant': function(valueChanged) {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
},
data: function() {
return {
applicant: {}
}
},
created: function() {
this.applicant = this.value;
}
})
// Root Vue instance
const app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
});
.row {
border: 2px solid #5CD7FF;
margin: 2px;
padding: 4px;
}
.label {
font-style: italic;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
<h3>Borrower:</h3> in parent:{{ form.borrower }}
<applicant v-model="form.borrower"></applicant>
<h3>Co-borrower:</h3> in parent:{{ form.coborrower }}
<applicant v-model="form.coborrower"></applicant>
</div>
<script type="x-template" id="applicant-container">
<div class="row"><span class="label">Applicant Template:</span>
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
Vue.component('applicant', {
template: '#applicant-container',
props: ['value'],
watch: {
'applicant': function(valueChanged) {
// When the internal value changes, we $emit an event. Because this event is
// named 'input', v-model will automatically update the parent value
this.$emit('applicant', this.applicant);
}
},
data: function() {
return {
applicant: {}
}
},
created: function() {
this.applicant = this.value;
}
})
// Root Vue instance
const app = new Vue({
el: '#app',
data: {
form: {
borrower: {
firstname: 'John',
middlenames: '',
surname: 'Rambo'
},
coborrower: {
firstname: 'Homer',
middlenames: '',
surname: 'Simpson'
}
}
}
});
.row {
border: 2px solid #5CD7FF;
margin: 2px;
padding: 4px;
}
.label {
font-style: italic;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
<h3>Borrower:</h3> in parent:{{ form.borrower }}
<applicant v-model="form.borrower"></applicant>
<h3>Co-borrower:</h3> in parent:{{ form.coborrower }}
<applicant v-model="form.coborrower"></applicant>
</div>
<script type="x-template" id="applicant-container">
<div class="row"><span class="label">Applicant Template:</span>
<div class="form-group col-md-4">
<label>Firstname</label>
<input type="text" class="form-control" v-model="applicant.firstname" />
</div>
<div class="form-group col-md-4">
<label>Middlename/s</label>
<input type="text" class="form-control" v-model="applicant.middlenames" />
</div>
<div class="form-group col-md-4">
<label>Surname</label>
<input type="text" class="form-control" v-model="applicant.surname" />
</div>
</div>
</script>
edited Sep 9 at 4:20
answered Jan 8 at 6:04
Sᴀᴍ Onᴇᴌᴀ
8,13861752
8,13861752
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f181375%2fdatabinding-entire-objects-between-child-vue-components-and-the-root-vue-instanc%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown