parsecer
parsecer

Reputation: 5106

How to get data from parent form component to child component nested components data from parents to children

I have three Vue components: FormField.vue, GenericForm.vue (contains FormField) and SignupPage.vue (contains GenericForm)

The GenericForm.vue has a inputFunction prop which is a function that is passed to it by a child component. It gets executed on button click.

The SignupPage.vue has a function register which sends a post request to a certain endpoint.

I need to somehow get the data of the fields from the fields in the GenericForm.vue so that that data gets sent when the button is clicked when inside SignupPage.vue component.

GenericForm.vue:

<template>
  <form v-on:submit.prevent="execute()"

        class="signup-form   rounded-lg
              p-10 m-auto  align-middle content-center
              space-y-6
              flex flex-col  items-center justify-center
                ">
    <div class="title-text light-text text-xl">Signup</div>

    <FormField v-for="(field) in fields"
               v-bind:key="field" :placeholder="field"
    />

    <GenericButton :text="buttonText"/>

  </form>
</template>
export default {
  components: {GenericButton, FormField, ArticleList},

  props: {
    title: {
      type: String,
      required: true
    },
    fields: {
      type: Array,
      required: true
    },
    buttonText: {
      type: String,
      required: true
    },
    inputFunction: {
      type: Function
    }
  },
...
...
  methods: {
    execute() {
      console.log("GenericForm.vue")

      if (this.inputFunction) {
        this.inputFunction()
      }

     },


  }
...

FormField.vue:

<template>

  <input :placeholder= "placeholder"
      class = "  form-field
            p-2 pl-0  pt-4 pb-2  w-1/3 "

  />

</template>

<script>
export default {
  props: ['placeholder']
}
</script>

SignupPage.vue:

<template>
  <div class=" ">
    <GenericForm title = "Sign Up" button-text= "Sign Up"
             :fields="['Username', 'Email', 'Password']"
             :inputFunction = "register"
    />
  </div>
</template>
...
  methods:  {
    async register() {
      console.log("register()")
      const response = AuthenticationService.register({
        email: 'wwwwww',
        password: 'frgr'
      }).then((response) => {

        console.log(response)
        console.log(this.$store)
        this.$router.push({
          name: 'ha'
        })
      });
    }
  }
...

Upvotes: 0

Views: 134

Answers (2)

tony19
tony19

Reputation: 138336

For this, I would name the inputs, and use new FormData() on the <form> element, which would automatically collect all named fields anywhere in the form (even deep nested ones).

  1. In GenericForm.vue, update the v-on:submit value from execute() to execute (just the method name), so that the submit-event data is automatically passed to the handler. We'll use this event data to get the form. Also bind <FormField>.name to each field.

    <template>
      <form v-on:submit.prevent="execute">
        <FormField v-for="(field) in fields" :name="field" />
      </form>
    </template>
    
  2. Update execute() to receive the event data, create the FormData from it, and pass the result as an argument to inputFunction():

    execute(e) {
      const form = e.target
      const formData = new FormData(form)
    
      if (this.inputFunction) {
        this.inputFunction(formData)
      }
    }
    
  3. In SignupPage.vue, update register to receive the form data:

    async register(formData) {
      const email = formData.get('Email')
      const password = formData.get('Password')
      //...
    }
    

demo

Upvotes: 1

AhmadKZX
AhmadKZX

Reputation: 303

you can use reference by path in js objects for sync data in vue like that:

SignupPage.vue:

data: {
  formData: {}
}
<GenericForm :formData="formData" :fields="['Username', 'Email', 'Password']" />

GenericForm.vue:

props: ['formData']

<FormField v-for="(field) in fields" v-bind:key="field" :field="field" :formData="formData" />

FormField.vue:

props: ['formData', 'field']

<input type="text" v-model="formData[field]" />

then you have synced form data in formData Object in signupPage.vue

Upvotes: 1

Related Questions