title: Conditional props in Vue2
body: <p>I have a use case where I may need to pass an object <code>props</code> as props to a child component. </p>
  
  <p>Initially, I had a form and a table contained within a component. This form would take input, an asynchronous request would be performed and the table would be rendered for the user to make a selection. The user could then hit a button and have the table hidden and the form brought back up so parameters could be re-entered. Since the content of the form was dependent on the state of its parent, the last search parameters were still in the form. </p>
  
  <p>The issue arose when I refactored the component to make both the form and the table sub-components of the parent. Now the form would <code>$emit</code> the event to its parent, which would perform the asynchronous operation and pass the result as <code>props</code> to the table. This worked fine, but when the user hits the "return to form" button, the form is re-rendered, thus resetting its state to the initial value. </p>
  
  <p>I tried storing the content of the form in the parent and passing it back to the form as <code>props</code> but that led to the problem of initially setting the values. I didn't want to mutate the props directly, so I tried this approach:</p>
  
  <h1>FormContainer.vue</h1>
  
  <pre><code>&lt;template&gt;
    &lt;div v-if="formShown"&gt;
      &lt;form-component :initialValues="formValues" @formSubmitted="displayResults"&gt;&lt;/form-component&gt;
    &lt;/div&gt;
    &lt;div v-if="tableShown"&gt;
      &lt;table-component :results="fetchedResults" @returnToForm="returnToForm"&gt;&lt;/table-component&gt;
    &lt;/div&gt;
  &lt;/template&gt;
  &lt;script&gt;
    export default {
      data(){
        return{
          formShown: true,
          tableShown: false,
          formValues:{
            address1: '',
            address2: '',
            address3: '',
            country: ''
          },
          fetchedResults: []
        }
      },
      methods:{
       async displayResults(){
          this.fetchedResults = await someAsynchronousCall();
          this.formShown = false;
          this.tableShown = true;
       },
       returnToForm(){
         this.tableShown = false;
         this.formShown = true;
       }
      }
    }
  &lt;/script&gt;
  </code></pre>
  
  <h1>FormComponent.vue</h1>
  
  <pre><code>&lt;template&gt;
    &lt;!--Some form fields here, bound to data(){}, ommitted for brevity--&gt;
  &lt;/template&gt;
  &lt;script&gt;
    export default{
      props:['initialValues'],
      data(){
        return{
          //Original structure
          /*selectedAddress:{
            address1: '',
            address2: '',
            address3: '',
            country: ''
          }*/
          selectedAddress: JSON.parse(JSON.stringify(this.initialValues)) //Object.assign({}, this.initialValues) //tried both of these for deep copy
        }
      }
    }
  &lt;/script&gt;
  </code></pre>
  
  <p>The problem with this was that when the component was initially created, it is getting passed an empty object (or rather an object with only empty properties, I assume they amount to the same thing), which means my data properties are getting initialized as <code>undefined</code>. </p>
  
  <p>I then tried using a ternary to initialize the data object with the values in the props or an empty string, like this:</p>
  
  <pre><code>data(){
    return{
      selectedAddress: {
        address1: this.initialValues.address1 ? this.initialValues.address1 :'',
        address2: this.initialValues.address2 ? this.initialValues.address2 :'',
        address3: this.initialValues.address3 ? this.initialValues.address3 :'',
        country:this.initialValues.country ? this.initialValues.country :''
      }
  
    }
  },
  </code></pre>
  
  <p>But this throws errors saying that <code>selectedAddress</code> is not defined on the instance but is referenced during render. I'm guessing this means that using a ternary to initialize props is wrong. </p>
  
  <p>I then tried to check for props in the <code>mounted(){}</code> lifecycle hook and set the data properties there, like this:</p>
  
  <pre><code>mounted(){
        if(!this.initialValues || _.isEmpty(this.initialValues)){
          Logger.info(`no props passed, no setup needed`);
          return;
        }
        if(this.initalValues.address1){
          Logger.info(`setting address 1`);
          this.selectedAddress.address1 = this.initalValues.address1;
        }
        if(this.initialValues.address2){
          Logger.info(`setting address 2`);
          this.selectedAddress.address2 = this.initalValues.address2;
        }
        if(this.initialValues.address3){
          Logger.info(`setting address 3`);
          this.selectedAddress.address3 = this.initalValues.address2;
        }
        if(this.initialValues.country){
          Logger.info(`setting country`);
          this.selectedAddress.country = this.initalValues.country;
        }
      }
  </code></pre>
  
  <p>This works for the first run of the form, but <code>this.initialValues</code> is always <code>undefined</code> when the component is mounted. I have inspected the component state and found that <code>initialValues</code> does exist, just not during the <code>mounted</code> life cycle hook. This approach felt 'hacky' anyway.</p>
  
  <p>I'm not really sure where to go from here. I could commit the form data to the store and get it again if the form is remounted, but I don't feel like committing something that should only exist while its parent is mounted is the right approach. </p>
  
  <p>Can anyone guide me to a more Vue way of achieving this?</p>