1

I have a form with submit prevent enabled:

<form method="get" :action="urls.baseUrl" ref="productsFilterForm" @submit.prevent>

Form submit button looks like this:

<button type="submit" @click="submitForm" class="btn">{{ translations['search'] }}</button>

SubmitForm function:

submitForm() {
    this.validateFilterValues();
    let form = this.$refs.productsFilterForm as HTMLFormElement;
    form.submit();
}

validateFilterValues:

validateFilterValues() {
    for (const [key, filter] of Object.entries(this.filters)) 
        filter.enabled = !(filter.value === null || filter.value === '' || filter.value == 0);
    }
}

filters data looks like this:

private filters: Record<string, Input> = {
    categories: { enabled: true, value: null },
    productId: { enabled: true, value: null },
    modificationId: { enabled: true, value: null },
    title: { enabled: true, value: null },
    barcode: { enabled: true, value: null },
    status: { enabled: true, value: null },
    descriptionStatus: { enabled: true, value: null },
    supplierCode: { enabled: true, value: null }
}

Filter data goes into input component:

<input-component id="formProductId"
                 type="number"
                 name="productId"
                 :label="translations['product_id']"
                 :placeholder="translations['product_id']"
                 :enabled="filters.productId.enabled"
                 :value="filters.productId.value"
/>

And input component looks like this:

<div class="form-element">
    <label :for="id" :class="['form-element-title', { 'js-focused': focused }]">{{ label }}</label>
    <input :id="id" :name="enabled ? name : false" v-model="inputData" type="text" :placeholder="placeholder" @focus="focused = true" @blur="focused = false">
</div>

Form submit works but there is a problem. validateFilterValues function removes the name of the inputs if they are empty. If I console.log the form variable before submitting it. I see that the empty inputs have their names removed. But the problem is that those inputs still submit through the form into the backend side. What am I missing here?

Also if I use the validation method on submit - it works fine:

<form method="get" :action="urls.baseUrl" @submit="validateFilterValues()">

But I need to make the submit as a separate function and prevent enter key form submit.

The50
  • 1,096
  • 2
  • 23
  • 47
  • without seeing validateFilterValues() it will be hard to tell what it's doing.. – chad_ Sep 01 '20 at 13:30
  • I added more code, I hope this is more clear now. – The50 Sep 01 '20 at 13:41
  • Is your issue that some inputs become nameless after validation or these nameless inputs are submited ? – Pierre Burton Sep 01 '20 at 14:00
  • They should become nameless and they do. But they are still submitted through the form. – The50 Sep 01 '20 at 14:02
  • Have you tried replacing the value false by undefined, like so : :name="enabled ? name : undefined" ? – Pierre Burton Sep 01 '20 at 14:06
  • Tried it right now - didn't helped. What's interesting is that all the values are submitted correctly, but somehow empty values of nameless inputs also gets through. – The50 Sep 01 '20 at 14:11
  • Can you try to delay the submit and see what happens ? Pushing to the end of the event loop using setTimeout(() => form.submit(), 0) or whatever delay you want. Just to be sure the form is submited after all the validations occured. – Pierre Burton Sep 01 '20 at 14:19
  • Ohh.. Yes it helped. Is this a good practice to set the timeout or I could do something else? Post an answer so I can accept it. – The50 Sep 01 '20 at 14:30

2 Answers2

2

So as I was saying, you should try to delay the execution of the submit to make sure your validation loop is complete before the submit is triggered.

The most basic thing you could do is triggering the submit in timeout with a 0sec delay.

setTimeout(() => form.submit(), 0)

This way, the submit is queued at the very end of the event loop.

I don't know if this is a good practice at all and I doubt it very much. But you have other possibilities to trigger the submit only after the end of something.

You could use a classic callback

validateFilterValues(callback) {
    for (const [key, filter] of Object.entries(this.filters)) 
        filter.enabled = !(filter.value === null || filter.value === '' || filter.value == 0);
    }
    callback();
}

submitForm() {
    let form = this.$refs.productsFilterForm as HTMLFormElement;
    this.validateFilterValues(form.submit());
}

or a Promise

validateFilterValues() {
  return new Promise((resolve, reject) => {
    try {
        for (const [key, filter] of Object.entries(this.filters)) 
            filter.enabled = !(filter.value === null || filter.value === '' || filter.value == 0);
        }
        resolve();
    } catch (err) {
        reject(err);
    }
  });
}

async submitForm() {
    await this.validateFilterValues();
    let form = this.$refs.productsFilterForm as HTMLFormElement;
    form.submit();
}

or any other form of waiting/delaying. The choice is up to you.

Pierre Burton
  • 1,954
  • 2
  • 13
  • 27
0

Another solution I found is to use @keypress.enter.prevent: https://stackoverflow.com/a/60228936/5470563

But it's still no quite what I wanted, because it would be nice to be in full control of all the actions before actually submitting the form from the submitForm() method.

The50
  • 1,096
  • 2
  • 23
  • 47