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

2.1k Views Asked by At

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

There are 4 best solutions below

0
On

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

0
On

I kind of like dynamically populating the form from the json data. There is some talk of adding this in as an actual feature, but it isn't hard to do just as a plug-in.

 getNode('attributes').input(data);
  let test = getNode('attributes').input(data);
  getNode('attributes').hook.commit((payload, next) => {
  console.log(payload);
  const newPayload = {};
  Object.keys(payload).forEach((key) => {
    if(getNode('attributes').children.map((el) => el.name).includes(key)) { 
      newPayload[key] = payload[key];   
    }
  });      
  return next(newPayload);

Basically just loops through the json data and populates any control with a name that matches the key from the data.

There is a playground example in this discussion: https://github.com/formkit/formkit/issues/395

Also, I made a working example of the above code here: http://vue.qwest4.com/playground/cascading%20dropdowns.html

The gotchas. If you do this on the full form, it can reset nodes you didn't want reset. In my working example, I had to put the non-select lists into a group and just repopulate that group. Just populating the entire form, it reset the dropdowns/select lists every time new selections were made. Even now it needs a bit of work, but it was just a quick demo.

0
On

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>
0
On

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"
/>