Search code examples
typescriptvue.jsvuejs2vue-componentfocus

How to focus on input field after change edit mode Vue.js + Typescript


I try to set the focus of an input field, after I have changed mode d'édition. But the focus is not set on the input field. Before the input appears, we have a field on which we must click to display the input and so I would like that by clicking on this field the focus of the input is directly set and that I have not click again on the input. Help me please

Thanks for your help

<script lang="ts">
    import Vue from 'vue';
    import ObjetDocument from '../../../models/IObjetDocument';
    import { textearaAutoHeight } from '../../../assets/scripts/animateInput';

    export default Vue.extend({
        props: {
            objetDocument: {
                type: String,
                required: true
            },
            enEditionObjet: {
                type: Boolean,
                required: true
            },
            typeDocument: {
                type: String,
                required: true
            }
        },
        data: function () {
            return {
                enEdition: this.enEditionObjet,
                messageErreur: "",
                objet: "",
                objetTextarea: ""
            }
        },
        watch: {
            objet: function () {
                if (!this.objet) {
                    this.messageErreur = this.$t('messageInputObjetVide').toString();
                }
                else {
                    this.messageErreur = "";
                }
            },
            objetTextarea: function () {
                if (!this.objetTextarea) {
                    this.messageErreur = this.$t('messageInputObjetVide').toString();
                }
                else {
                    this.messageErreur = "";
                }
            },
            objetDocument: function () {
                this.objet = this.objetDocument;
                this.convertObjetHtmlToObjetTextarea(this.objetDocument)
            },
            enEditionObjet: function () {
                this.enEdition = this.enEditionObjet;
            }
        },
        methods: {
            undoChange: function () {
                this.objet = this.objetDocument;
                this.convertObjetHtmlToObjetTextarea(this.objetDocument);
                this.changeModeEdition();
            },
            updateObjet: function (e) {
                if (!this.messageErreur) {
                    this.$emit('update', this.objet);
                }
                e.preventDefault();
            },
            changeModeEdition: function () {
                this.enEdition = !this.enEdition;
                this.$emit('changeModeEdition', this.enEdition);
                textearaAutoHeight()
            },
            convertObjetTextareaToObjetHtml: function (value: string) {
                this.objet = value.replace(/\n/gi, "<br/>");
            },
            convertObjetHtmlToObjetTextarea: function (value: string) {
                this.objetTextarea = value.replace(/<br\/>/gi, "\n");
            }
        },
        mounted: function () {
            textearaAutoHeight()
        },
        created: function () {
            this.objet = this.objetDocument;
            this.convertObjetHtmlToObjetTextarea(this.objetDocument);
        }
    })
</script>
<template>
    <div class="editable-container">
        <div v-if="objet" class="editable hover-pointer"
             v-show="!enEdition"
             @click="changeModeEdition"
             v-html="objet">
        </div>
        <div v-if="!objetDocument" class="editable hover-pointer text-grey"
             v-show="!enEdition"
             @click="changeModeEdition"
             style="font-style:italic">
            <div v-if="typeDocument=='Facture'">{{ $t('visualisationObjetVide_dela', { typeDocument : typeDocument.toLowerCase() } )}}</div>
            <div v-if="typeDocument=='Avoir' || typeDocument=='Acompte'">{{ $t('visualisationObjetVide_del', { typeDocument : typeDocument.toLowerCase() } )}}</div>
            <div v-if="typeDocument=='Devis'">{{ $t('visualisationObjetVide_du', { typeDocument : typeDocument.toLowerCase() } )}}</div>
        </div>

        <div v-show="enEdition">
            <form @submit="updateObjet">
                <div class="inputGroup inputGroup-white inputGroup-facturation">
                    <textarea v-model="objetTextarea" class="inputGroup--input form-control" rows="1"></textarea>
                    <label class="inputGroup--label">{{$t('texteLabelObjet')}} </label>
                    <div v-if="messageErreur" class="text-invalid">{{messageErreur}}</div>
                </div>
                <div class="navAction">
                    <button type="submit" class="navAction--btn" @click="convertObjetTextareaToObjetHtml(objetTextarea)"><i class="fas fa-check"></i></button>
                    <button type="button" @click="undoChange" class="navAction--btn"><i class="fas fa-undo-alt"></i></button>
                </div>
            </form>
        </div>
    </div>
</template>
<i18n src="../../../localization/facturation/Objet.json"></i18n>


Solution

  • Add a ref to the input as follows :

      <textarea ref='objet' v-model="objetTextarea" class="inputGroup--input form-control" rows="1"></textarea>
                
    

    then in your method add this line :

     this.$nextTick(() => this.$refs.objet.focus());
    

    like

      changeModeEdition: function () {
                    this.enEdition = !this.enEdition;
                    this.$emit('changeModeEdition', this.enEdition);
                    textearaAutoHeight();
                     this.$nextTick(() => this.$refs.objet.focus());
                },
    

    and declare the $refs in your component instance :

    import Vue, { VueConstructor } from 'vue';
    
     export default (Vue as VueConstructor<Vue &
        {
            $refs:
            { objet: HTMLFormElement },
        }
        >).extend({
     props:{
      ...