Consider a simple Vue component with text input (link).
<script setup>
import { ref } from 'vue'
const msg = ref('')
function onInput(e) {
let value = e.target.value;
if (value === ' ') value = '';
msg.value = value;
}
</script>
<template>
<input :value="msg" @input="onInput" />
</template>
I want to disable first space in this input, i.e. if a user inputs space then the inputfield should remain empty. But it doesn't work. I guess it happens because Vue checks that msg
doesn't change and rejects component render.
My next attempt is to force render the component (link).
<script setup>
import {getCurrentInstance} from 'vue'
import { ref } from 'vue'
const msg = ref('')
const instance = getCurrentInstance();
function onInput(e) {
let value = e.target.value;
if (value === ' ') {
value = '';
msg.value = value;
instance?.proxy?.$forceUpdate();
return;
}
msg.value = value;
}
</script>
<template>
<input :value="msg" @input="onInput" />
</template>
It works, but with limits. My project has a big tree of components and $forceUpdate
updates current component only without children.
I also tried to re-render the whole sub-three with changing key
on the component, but in this case I lose input's focus.
To sum up, it seems that I miss something. I can't believe that such simple task requires weird workarounds. Please help me to find a simple and "best practice" way to disable first space in html input.
P.S. React version works as expected.
import React, {useState} from 'react';
export function App(props) {
const [value, setValue] = useState('');
function onInput(e) {
let v = e.target.value;
if (v === ' ') v = '';
setValue(v);
}
return (
<div className='App'>
<input value={value} onInput={onInput} />
</div>
);
}
Based on your code: don't react to the input event. It's too late. React before the input event occurs. And filter out that space character.
This will save the application a lot of unnecessary calculations (msg=" ", then msg="").
<script setup>
import { ref } from 'vue'
const msg = ref('')
const filterFirstSpace = e => {
const isEmpty = !e.target.value.length
const isSpace = /\s/.test(e.data)
if (isEmpty && isSpace) {
e.preventDefault()
}
}
</script>
<template>
<input
:value="msg"
@beforeinput="filterFirstSpace"
/>
</template>