0

I have a parent component ChangeInfo, inside it is a child component ShowWorkInfo. Inside the ShowWorkInfo component, I have several input forms to update the job information. I created a variable work_info which is an object and then used the v-model for the fields inside. But I don't know how to make the parent component get data from the child component. I don't have any button inside the child component, I'll try to handle the data from WorkInfo with a button in the parent. This is my code. Should I write directly into ChangeInfo without splitting it into a child component

ChangeInfo (parent component)

export default class ChangeInfo extends Vue {
  public isUpdated: boolean = false
  updateWorkInfo(workInfo: any) {
    if (
      workInfo.company == '' ||
      workInfo.department == '' ||
      workInfo.position == '' ||
      workInfo.postcode == '' ||
      workInfo.prefectures == '' ||
      workInfo.municipality == '' ||
      workInfo.address == '' ||
      workInfo.building == '' ||
      workInfo.phone_number == '' ||
      workInfo.url == ''
    ) {
      alert('完全な情報を入力してください')
      this.isUpdated = false
    } else {
      axios
        .put('https://609b82962b549f00176e394f.mockapi.io/work_info/1', {
          status: workInfo.status,
          company: workInfo.company,
          department: workInfo.department,
          position: workInfo.position,
          postcode: workInfo.postcode,
          prefectures: workInfo.prefectures,
          municipality: workInfo.municipality,
          address: workInfo.address,
          building: workInfo.building,
          phone_number: workInfo.phone_number,
          url: workInfo.url
        })
        .then(response => {
          workInfo = response.data
          console.log(workInfo)
          InformationModule.CHANGE_WORK_INFO(workInfo)
        })
        .catch(error => console.log(error))
      this.isUpdated = false
      workInfo.status = false
      workInfo.company = ''
      workInfo.department = ''
      workInfo.position = ''
      workInfo.postcode = ''
      workInfo.prefectures = ''
      workInfo.municipality = ''
      workInfo.address = ''
      workInfo.building = ''
      workInfo.phone_number = ''
      workInfo.url = ''
    }
  }

  updatePersonalInfo(personalInfo: any) {
    if (
      personalInfo.nearest_station == '' ||
      personalInfo.postcode == '' ||
      personalInfo.prefectures == '' ||
      personalInfo.municipality == '' ||
      personalInfo.address == '' ||
      personalInfo.building == '' ||
      personalInfo.phone_number == '' ||
      personalInfo.url == ''
    ) {
      alert('完全な情報を入力してください')
      this.isUpdated = false
    } else {
      axios
        .put('https://609b82962b549f00176e394f.mockapi.io/personal_info/1', {
          gender: personalInfo.gender,
          nearest_station: personalInfo.nearest_station,
          postcode: personalInfo.postcode,
          prefectures: personalInfo.prefectures,
          municipality: personalInfo.municipality,
          address: personalInfo.address,
          building: personalInfo.building,
          phone_number: personalInfo.phone_number,
          url: personalInfo.url
        })
        .then(response => {
          personalInfo = response.data
          console.log(personalInfo)
          InformationModule.CHANGE_PERSONAL_INFO(personalInfo)
        })
        .catch(error => console.log(error))
      this.isUpdated = false
      personalInfo.gender = false
      personalInfo.nearest_station
      personalInfo.postcode = ''
      personalInfo.prefectures = ''
      personalInfo.municipality = ''
      personalInfo.address = ''
      personalInfo.building = ''
      personalInfo.phone_number = ''
      personalInfo.url = ''
    }
  }

  triggerSubmit() {
    this.isUpdated = true
  }

I call two functions like this

<template>
  <div class="d-block">
    <ShowProfile />
    <ShowWorkInfo :isUpdated="isUpdated" @update-work-info="updateWorkInfo" />
    <ShowPersonalInfo
      :isUpdated="isUpdated"
      @update-personal-info="updatePersonalInfo"
    />
    <div class="w--27 mw-100 mx-auto my-9">
      <button
        @click="triggerSubmit"
        v-b-modal="'update-success'"
        class="btn btn-primary w-100"
      >
        {{ $t('common.btn.btn_update') }}
      </button>
    </div>
    <ModalUpdateSuccess />
  </div>
</template>
4
  • So you don't want to use a button in your child component ? Commented Jul 1, 2021 at 10:22
  • yes, my design doesn't have any buttons inside the child. I have three same components like this inside one parent component. And I'll update all three children with a button inside the parent component Commented Jul 1, 2021 at 10:27
  • Maybe not the best practice but you use watch for it and emit a function in watch to capture your v-models in your parent component ? I can put an example below if you want Commented Jul 1, 2021 at 10:32
  • it would be nice if you could give me an example Commented Jul 1, 2021 at 10:35

2 Answers 2

2

Well... there are multiple ways to do this:

  1. Quick and dirty: Pass another prop from the parent to component, this will be set to true when the common.btn.btn_update is pressed, in the updateWorkInfo function, you set up a watcher in the child component for this prop, and when this pro changes to true, you do an emit('submitted', data) and this will emit the data to your parent component and then just handle this event in the parent as a submit event. In action:

//#region Parent script
import {
  Component,
  Vue
} from 'vue-property-decorator'
import ShowWorkInfo from './Components/ShowWorkInfo.vue'
import ModalUpdateSuccess from '@/components/Modal/ModalUpdateSuccess.vue'

@Component({
  components: {
    ShowWorkInfo,
    ModalUpdateSuccess
  }
})
export default class ChangeInfo extends Vue {
  private isFormSubmitted: boolean = false;
  private validationMessage: string = '';
  updateWorkInfo(workInfo) {
    console.log('recieved workinfo: ', workInfo);
    const { isFormValid, validationMessage } = await validateForm(workInfo);// function that validates your data, and returns a message and a boolean.
    if(!isFormValid) { //if form is not valid, you have to set the variable that triggers 
                       //the submit to false so the child component can set  it to true and trigger submit once again
      this.isFormSubmitted = false;
      this.validationMessage = validationMessage;
      return;
    } 
    //...data handling logic and stuff... you can make the PUT request here, or anuy other data related action
  }
  triggerSubmit() {
    //this triggers the watch in the child component
    this.isFormSubmitted = true;
  }
}
//# endRegion Parent script

//# region Child script
@Component({
  components: {
    Title
  }
  //the prop
  props: {
    isFormSubmitted: {
      default: false,
      type: boolean,
    },
  }
})
export default class ShowWorkInfo extends Vue {
  private showWorkInfo: boolean = false
  private workInfo: any = { ...
  }
  //watch for change (you can also put it in a computed if it does not trigger change)
  watch: {
    isFormSubmitted: function(newValue) {
      if (newValue) {
        console.log('form-submitted', this.workInfo)
        emit('form-submitted', this.workInfo);
      }
    }
  }
}
//#endRegion Child script

Now I don't really like this approach... but it works, just how you wanted it to!

  1. Traditionally: You would have the submit button in the child component and emit a submitted event, together with the data, way nicer, and more reusable approach:

#region Parent script
@Component({
  components: {
    ShowWorkInfo,
    ModalUpdateSuccess
  }
})
export default class ChangeInfo extends Vue {
  updateWorkInfo(workInfo) {
    console.log('recieved workinfo: ', workInfo);
    //...data handling logic and stuf...
  }
}


ShowWorkInfo (child component)
#endRegion Parent script

#region Child script
@Component({
  components: {
    Title
  }
})
export default class ShowWorkInfo extends Vue {
  private showWorkInfo: boolean = false
  private workInfo: any = { ... }
  //watch for change (you can also put it in a computed if it does not trigger change)
  submitForm() {
    console.log('submit form: ', this.workInfo);
    //you could also validate the form at this point and dont emit unti the data is valid
    this.$emit('form-submitted', this.workInfo);
  }
}
#endRegion Child script
<!-- parent template -->
<template>
  <div class="d-block">
    <ShowWorkInfo @form-submitted="updateWorkInfo"/>
    <ModalUpdateSuccess />
  </div>
</template>
<!-- parent template end -->

<!-- child template -->
<template>
  <div class="form">
  <!-- your form fields -->
   <div class="w--27 mw-100 mx-auto my-9">
      <button
        @click="submitForm"
        v-b-modal="'update-success'"
        class="btn btn-primary w-100"
      >
        {{ $t('common.btn.btn_update') }}
      </button>
    </div>
  </div>
</template>
<!-- child template end -->

NOTE1: Apologies if I misused these variables and the this, since i am not familiar with this version of Vue and typescript, and tbh i have not touched vue.2 in like a year, but the concepts remain the same, essentially i just wanted to show you the methods of how to use the features vue gives, the above code is far from perfect but i think it illustrates the uses and answers you question.

NOTE2: There are more ways to do this, if you are interested in them please tell me. The above-mentioned two ways are the most common I have seen

UPDATE: Form validation in the first block. Try it, this is an overall form validation. DISCLAIMER: If you want to do field by field validation, that would be real hard, and would advise you to move the submit logic to your child component.

Sign up to request clarification or add additional context in comments.

6 Comments

because I don't have any button in the child component so I have to use the first way. It's working very fine, but if I want to validate the form, Where do I need to put that validation?
If I need to change the data with the PUT method by using Axios, Can I use this way?
I have a problem that when I write two functions for two same components, it's only working for the first function. In my case, I want to check if all the input in the two components are not null, I'll using Axios to change the information. But it's just working for the first one. The second function isn't not working. You can see ChangeInfo in the post I just changed
@thinh6699 can you show me how you call those functions?
you can see my post I just changed. I did exactly what you said, but then when I put the second component with the same function as the first one, it's just working with the first one. In the two components, I just emit the data when isUpdated = true, and some v-model for the input, don't have any logic inside those.
|
0

As I said it may not be the best practice. What I thought if you don't have a button and we want to send info to our parent component, we can use watch and v-model with lazy.

It is a small example, not related to your code.

ChildComponent:


<template>
  <div class="hello">
    <input type="text" placeholder="Enter something" v-model.lazy="myObj.message">
    <input type="text" placeholder="Enter something" v-model.lazy="myObj.name"> 
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data () {
    return {
      myObj : {
        message:"",
        name : ""
      }
    }
  },
  watch: {
    myObj : {
      handler (newVal) {
      this.$emit('change', newVal)
    },
    deep: true
    }
  }
};
</script>

ParentComponent:


<template>
  <div id="app">
    <HelloWorld @change="change"/>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld
  },
  methods: {
    change (obj) {
      console.log(obj)
    }
  }
};
</script>

console will log your message after you click outside input. If we don't use v.model.lazy then whenever input changes it will send data like that. You can give it a try and see if it is going to work or not.

EDIT: I have added deep:true to watch the whole object. Now in parent component you can actually console.log(obj.name) or (obj.message)

1 Comment

it's working very well but not working with an object. In my code, it's an object with many properties inside. What do I need to change to get the data correctly?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.