简体   繁体   中英

reset autocomplete field text by clicking outside vue

I have an autocomplete field. If i put any text and it matches the result set then it will populate the dropdown result. If it doesn't match anything then by clicking outside it will reset the input field forcefully.

So, for this approach i have created the vue click outside directive

    import Vue from 'vue';

const nodeList = [];
const ctx = '@@clickoutsideContext';

let startClick;
const counter = 0;

const isServer = Vue.prototype.$isServer;

/**
 * added this on event function for direct dom manipulation
 */
const onEvent = (function() {
    if (!isServer && document.addEventListener) {
        return function(element, event, handler) {
            if (element && event && handler) {
                element.addEventListener(event, handler, false);
            }
        };
    }
    return function(element, event, handler) {
        if (element && event && handler) {
            element.attachEvent(`on${event}`, handler);
        }
    };
})();

!isServer &&
    onEvent(document, 'mousedown', e => {
        startClick = e;
    });

!isServer &&
    onEvent(document, 'mouseup', e => {
        nodeList.forEach(node => node[ctx].documentHandler(e, startClick));
    });

// setting up mouse events

function createDocumentHandler(el, binding, vnode) {
    return function(mouseup = {}, mousedown = {}) {
        if (
            !vnode ||
            !vnode.context ||
            !mouseup.target ||
            !mousedown.target ||
            el.contains(mouseup.target) ||
            el.contains(mousedown.target) ||
            el === mouseup.target ||
            (vnode.context.popperElm &&
                (vnode.context.popperElm.contains(mouseup.target) ||
                    vnode.context.popperElm.contains(mousedown.target)))
        )
            return;

        if (
            binding.expression &&
            el[ctx].methodName &&
            vnode.context[el[ctx].methodName]
        ) {
            vnode.context[el[ctx].methodName]();
        } else {
            el[ctx].bindingFn && el[ctx].bindingFn();
        }
    };
}

/**
 * v-clickoutside
 * @desc Only trigger when click outside
 * @example
 * ```vue
 * <div v-element-clickoutside="handleClose">
 * ```
 */
export default {
    bind(el, binding, vnode) {
        nodeList.push(el);
        const id = counter + 1;
        el[ctx] = {
            id,
            documentHandler: createDocumentHandler(el, binding, vnode),
            methodName: binding.expression,
            bindingFn: binding.value
        };
    },

    update(el, binding, vnode) {
        el[ctx].documentHandler = createDocumentHandler(el, binding, vnode);
        el[ctx].methodName = binding.expression;
        el[ctx].bindingFn = binding.value;
    },

    unbind(el) {
        const len = nodeList.length;

        for (let i = 0; i < len; i += 1) {
            if (nodeList[i][ctx].id === el[ctx].id) {
                nodeList.splice(i, 1);
                break;
            }
        }
        delete el[ctx];
    }
};

Here is the autocomplete field in forms field

<div v-if="field.type == 'autocomplete'">
                <vu-auto-complete
                    v-model="fieldvalues[field.key]"
               :items="formFieldAutocompleteItems[fieldvalues[field.key]] || []"
                    :label="labelrequired(field)"
                    :placeholder="field.placeholder"
                    :error-message="errorMsg[field.key]"
                    @input="handleOnInput($event, field)"
                    @selected="getSelectedData($event, field)"
                >
                </vu-auto-complete>
            </div>

methods for handleOnInput

handleOnInput(inputKey, field) {
        if (inputKey !== null && inputKey.length >= 3) {
            this.fieldvalues = {
                ...this.fieldvalues,
                [field.key]: inputKey
            };
            const data = {
                url: field.autocompleteUri,
                search: field.autocompleteUriKey,
                text: inputKey,
                key: field.key
            };
            clearTimeout(this.timer);
            this.timer = setTimeout(() => {
                this.$emit('autocompleteInput', data);
            }, 500);
        } else if (inputKey.length === 0 || inputKey === null) {
            const formData = { ...this.fieldvalues };
            if (field.dependentFields && field.dependentFields.length > 0) {
                for (let i = 0; i < field.dependentFields.length; i += 1) {
                    formData[field.dependentFields[i]] = '';
                }
            }
            this.fieldvalues = formData;
        }
    },

Autocomplete field is working fine. So, i need directive or methods to reset any input by clicking outside.

Any suggestions or examples will be helpful to understand.

I'd suggest you use the onClickOutside utility from VueUse.

VueUse is effectively a collection of super useful utility functions for Vue with support for Vue2, Vue3 and Typescript.

There's over 90 different utilities for so many different use cases and the library is treeshakable so you only have to bundle what you use.

The onClickOutside utility expects a target ref and a callback along with an optional third param for configuration.

Something like this should work for you:

onClickOutside(
  inputRef,
  (event) => {
    console.log(event);
    this.inputText = '';
  },
  { event: 'mousedown' },
)

This saves you the time of writing custom code where you may miss out on important considerations such as accessibility. If you want, you can dig into the source of the utility and explore how it works internally.

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