How to populate FormKit input fields with dynamic data fetched from a database

Viewed 226

I'm making a fullstack app with vue3, axios using FormKit. For editing existing records I want to populate the input fields with the current data fetched from a mysql database. I stripped down the code to everything needed to display my problem, which in this code example is populating the FormKit input field with the lotnumber I fetched via the asynchronous function "getLotById". The lotnumber appears in the paragraph section but not in the input field. How can I properly delay the rendering of the FormKit element until the lotnumber has been fetched? Here's my code:

<script>
// import axios
import axios from "axios";
  
export default {
    name: "LotEdit",
    data() {
        return {
            lotnumber: this.lotnumber
        }
    },
    props: {
      lotid: Number
    },
    created: async function () {
        await this.getLotById();
    },
    methods: {
        // Get Lot By Id
        async getLotById() {
            try {
                const response = await axios.get(`http://localhost:5000/lot/${this.$route.params.id}`);
                this.lotnumber = response.data.lotnumber;
                console.log(response.data);
            }
            catch (err) {
                console.log(err);
            }
        },
    }
};
</script>

<template>
  <div>
    <FormKit
      type="text"
      name="lotnumber"
      label="lotnumber"
      placeholder=""
      validation="required"
      :value="lotnumber"
    />
  </div>
  <div>
    <p> Here the lotnumber appears: {{ lotnumber }}</p>
  </div>
</template>
3 Answers

Getting a little smarter I managed to solve the problem in the following way:

<script>
// import axios
import axios from "axios";
  
export default {
    name: "LotEdit",
    data() {
        return {
            lotnumber: this.lotnumber
        }
    },
    props: {
        lotid: Number
    },
    mounted: async function () { 
        const response = await this.getLotById();
        const node = this.$formkit.get('lotnumber')
        node.input(response.data.lotnumber, false) 
    },
    methods: {
        // Get Lot By Id
        async getLotById() {
            try {
                const response = await axios.get(`http://localhost:5000/lot/${this.$route.params.id}`);
                console.log(response.data);
                return response;
            }
            catch (err) {
                console.log(err);
            }
        },
    }
};
</script>

<template>
  <div>
    <FormKit
      type="text"
      id="lotnumber"
      name="lotnumber"
      label="lotnumber"
      placeholder=""
      validation="required"
      :value="lotnumber"
    />{{ lotnumber }}
  </div>
</template>

Feel free to post any recommendations as I'm not a pro yet...

I'm also still figuring out how to handle controlled forms but I guess an alternative way to do it is with Form Generation

<script>
export default {
  // ...
  async setup() {
    try {
      const response = await axios.get(`http://localhost:5000/lot/${this.$route.params.id}`);

      const schema = [
        {
          $formkit: "text",
          label: "Lot Number",
          value: response.data.lotnumber,
          validation: "required",
        },
      ];
    } catch (err) {
      console.log(err);
    }

    return { schema }
  }
  // ...
}
</script>

<template>
  <FormKit type="form">
    <FormKitSchema :schema="schema" />
  </FormKit>
</template>

I suggest using a v-model on the FormKit input. Because it is two-way bound it means as soon as the async/await completes the data is populated on the template too. Something like...

<FormKit
  v-model="lotnumber"
  type="text"
  name="lotnumber"
  label="lotnumber"
  placeholder=""
  validation="required"
  :value="lotnumber"
/>
Related