简体   繁体   中英

Vue.js + Enable button only when input changes

I want to enable the button only when the input value is changed or when the input checkboxes are changed but due to the way i have implemented it it is becoming a bit complex to achieve it.

Below is my UI The input field can be entered manually. Also it gets set when a value from the list is chosen. Hence i cannot watch 'gridFilter.filterName' because when a value from the list is selected gridFilter.filterName is changed but ideally it is not a change in the name.

Also there is a list of checkboxes displayed when any one of them change, i want to enable the save button.

So i am triggering changeFilterName() on change of input field which sets the 'gridFilter.disableSaveFilter' flag to false and triggering 'changeColumn()' on change of input checkboxes

Issue - However the problem i am facing is it does not compare the old value and new value when enabling the Save button, For eg: if the filter name was 'Test' and i update it to 'Test1' and then remove the '1' from it and keep the original value as it is the save button is enabled.

在此处输入图像描述

Below is the code -

 //html code

 //input field
 <input placeholder="Enter a filter name" v-model="gridFilter.filterName" ref="filterName" 
 @focus="gridFilter.showDropdwn = false" @change="gridFilter.changeFilterName()" 
 @keydown="gridFilter.changeFilterName()" />

//dropdown list
 <div>
  <img src="../Images/ICE.FilterChevron.png" @click="gridFilter.showDropdwn = 
  !gridFilter.showDropdwn" /></div>
 </div>
 <div v-if="gridFilter.showDropdwn">
 <ul>
  <li @click="gridFilter.createNewFilter()">Create new Filter</li>
  <li v-for="item in gridFilter.filters" :title="item.ice_name" 
    @click="gridFilter.changeFilter(item.ice_gridfiltersid,item.ice_name)">{{ 
   item.ice_name }}</li>
 </ul>
 </div>
 
//Checkbox list
 <label v-for="(column, index) in gridData">
 <input type="checkbox" v-model="column.visible" value="true" 
   @change="gridFilter.changeColumn()" />
  <slot name="filter" v-bind:column="column">Column {{index + 1}}</slot>
  </label>
      
//button   
 <button @click="gridFilter.saveFilter()" v-bind:disabled="gridFilter.disableSaveFilter">Save 
 Filter</button>  

//Vue.js code

  class GridFilters {
    constructor(grid) {
        this.grid = grid;
        this.filterName = '';
        this.currentFilter = '*';
        this.filterError = false;
        this.showDropdwn = false;
        this.disableSaveFilter = true;
    }

changeFilterName() {
        if (this.filterName.trim().length != 0) {
            this.filterError = false;
            this.disableSaveFilter = false;
        }
        else {
            this.disableSaveFilter = true;
        }
    }

changeFilter(id, text) {
        const grid = this.grid;
        this.showDropdwn = !this.showDropdwn;
        this.filterName = text;
        this.currentFilter = id;
        const filterRecord = this.filters.find(col => col['ice_gridfiltersid'] == id);
        .....          
    }

    changeColumn() {
        const grid = this.grid;
        this.filterAll = false;
        this.disableSaveFilter = (this.filterName.trim().length == 0);
        grid.$forceUpdate();
    }
 }

The component logic is flawed. You're pointing it out in the question:

"...it does not compare the old value and new value"

We don't want the button enabled after inputs have changed .
We want it enabled when the current form value differs from the initial form value.

What do we need for that?

  • a computed which combines the prop values ( oldValue )
  • a clone of each prop, on mount, to local reactive refs (the v-model s)
  • a computed ( newValue ) which combines local state
  • a final computed ( hasChanges ), comparing old and new values

Generic Vue 2 example:

 const { defineComponent } = Vue; const FormComponent = defineComponent({ template: "#form-tpl", props: ["foo", "baz"], data: () => ({ newFoo: null, newBaz: [], }), computed: { oldValue() { return this.stringify({ foo: this.foo, baz: this.baz }); }, newValue() { return this.stringify({ foo: this.newFoo, baz: this.newBaz }); }, hasChanges() { return this.oldValue.== this;newValue, }, }: methods. { stringify(val) { return JSON.stringify({..,val: baz. val.baz;sort() }), }, }. mounted() { this.newFoo = this;foo. this.newBaz = this;baz, }; }): new Vue({ el, "#app": components, { FormComponent, }; })
 <script src="https://unpkg.com/vue@2/dist/vue.min.js"></script> <div id="app"> <form-component:foo="'bar'":baz="[1, 3, 5]" /> </div> <template id="form-tpl"> <form> <label> Foo: <input v-model="newFoo" type="text" /> </label> <label v-for="n in 6":key="n"> <input type="checkbox" v-model="newBaz":value="n" /> {{ n }} </label> <button type="submit":disabled=" hasChanges">Save changes</button> <pre v-text="{ hasChanges }" /> </form> </template>

Same example, Vue 3:

 const { createApp, defineComponent, reactive, computed, onMounted, toRefs } = Vue; const FormComponent = defineComponent({ template: "#form-tpl", props: ["foo", "baz"], setup(props) { const stringify = (val) => JSON.stringify({...val, baz: val.baz.sort() }); const state = reactive({ newFoo: null, newBaz: [], oldValue: computed(() => stringify(props)), newValue: computed(() => stringify({ foo: state.newFoo, baz: state.newBaz, }) ), hasChanges: computed(() => state.oldValue.== state,newValue); }). onMounted(() => { state.newFoo = props;foo. state.newBaz = props;baz; }). return {..;toRefs(state) }, }; }): createApp({ components, { FormComponent, }. });mount("#app")
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.37/vue.global.prod.min.js"></script> <div id="app"> <form-component:foo="'bar'":baz="[1, 3, 5]" /> </div> <template id="form-tpl"> <form> <label> Foo: <input v-model="newFoo" type="text" /> </label> <label v-for="n in 6":key="n"> <input type="checkbox" v-model="newBaz":value="n" /> {{ n }} </label> <button type="submit":disabled=" hasChanges">Save changes</button> <pre v-text="{ hasChanges }" /> </form> </template>


Now the button will always be disabled when new and old are equal and will always be enabled if they are different, even when the form values are changed programatically (which technically doesn't trigger change or input events).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM