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










share|improve this question
















bumped to the homepage by Community 12 mins ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.



















    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










    share|improve this question
















    bumped to the homepage by Community 12 mins ago


    This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.

















      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










      share|improve this question















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 8 at 6:08









      Sᴀᴍ Onᴇᴌᴀ

      8,07461751




      8,07461751










      asked Nov 27 '17 at 5:35









      CodeMonkey

      63




      63





      bumped to the homepage by Community 12 mins ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.







      bumped to the homepage by Community 12 mins ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
























          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.





          1. Change the property from applicant to value.



            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>



          2. Add applicant via the the local data properties:



            data: function() {
            return {
            applicant: {}
            }
            },



          3. When the component is created, set the applicant to the value property:



            created: function() {
            this.applicant = this.value;
            }



          4. 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>








          share|improve this answer























            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
            });


            }
            });














            draft saved

            draft discarded


















            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.





            1. Change the property from applicant to value.



              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>



            2. Add applicant via the the local data properties:



              data: function() {
              return {
              applicant: {}
              }
              },



            3. When the component is created, set the applicant to the value property:



              created: function() {
              this.applicant = this.value;
              }



            4. 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>








            share|improve this answer



























              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.





              1. Change the property from applicant to value.



                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>



              2. Add applicant via the the local data properties:



                data: function() {
                return {
                applicant: {}
                }
                },



              3. When the component is created, set the applicant to the value property:



                created: function() {
                this.applicant = this.value;
                }



              4. 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>








              share|improve this answer

























                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.





                1. Change the property from applicant to value.



                  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>



                2. Add applicant via the the local data properties:



                  data: function() {
                  return {
                  applicant: {}
                  }
                  },



                3. When the component is created, set the applicant to the value property:



                  created: function() {
                  this.applicant = this.value;
                  }



                4. 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>








                share|improve this answer














                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.





                1. Change the property from applicant to value.



                  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>



                2. Add applicant via the the local data properties:



                  data: function() {
                  return {
                  applicant: {}
                  }
                  },



                3. When the component is created, set the applicant to the value property:



                  created: function() {
                  this.applicant = this.value;
                  }



                4. 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>






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Sep 9 at 4:20

























                answered Jan 8 at 6:04









                Sᴀᴍ Onᴇᴌᴀ

                8,07461751




                8,07461751






























                    draft saved

                    draft discarded




















































                    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.




                    draft saved


                    draft discarded














                    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





















































                    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







                    Popular posts from this blog

                    Create new schema in PostgreSQL using DBeaver

                    Deepest pit of an array with Javascript: test on Codility

                    Costa Masnaga