Replies: 12 comments 16 replies
-
Yeah this one is a pain. React does something special here. I'm not sure who else does. The problem is you need to hack the input to actually maintain this. And add a bunch of other even listeners. I don't think this is something that I intend to ever implement. Someone did an audit a while back and realized only React was doing this out of all the libraries they tested. I don't see us changing natural DOM behavior and implementing this. I'm pretty much a won't fix on this. But if there is overwhelming support in other libraries like Preact, Inferno, and Svelte I might consider it (but if memory serves none of these outside of compat do this). |
Beta Was this translation helpful? Give feedback.
-
FWIW, my background is mainly in Angular but I find the current functionality expected. In fact, I'd be very surprised if the input value didn't update. From this conversation, I gather that, in React, the input wouldn't update. But if react is re-rendering the function component on every keypress I could see this making sense (as it is effectively re-initializing the input with a static value on every keypress). But the current behavior of Solidjs seems consistent with the DOM itself (e.g. if you create an |
Beta Was this translation helpful? Give feedback.
-
I'm going to move this to discussions as no activity for 2 weeks and I don't see implementing this. |
Beta Was this translation helpful? Give feedback.
-
here is how I created a controlled text using two state , (this might not be optimized ) import { render } from "solid-js/web";
import { createSignal } from "solid-js";
function Counter() {
const [length, setLength] = createSignal(0);
const [value, setValue] = createSignal("");
return (
<input type="text" maxLength={length()} value={value()} onKeyPress={(event)=>{
setLength(length()+1);
setValue(value()+String.fromCharCode(event.keyCode));
}} />
);
}
render(() => <Counter />, document.getElementById("app"));
|
Beta Was this translation helpful? Give feedback.
-
I think I got it: Action:
Condition:
Question:
If:
import { createSignal } from 'solid-js'
const App = () => {
const [state, setState] = createSignal('')
const inputHandler = (e) => {
const value = e.currentTarget.value
if (value.match('^[0-9]*$')) setState(value) // TRUE <- ¿Only numbers? Ok, update the state.
else e.currentTarget.value = state() // FALSE <- ¿Not a number? Go back.
}
// Or in a single line:
// onInput={e => e.currentTarget.value.match('^[0-9]*$') ? setState(e.currentTarget.value) : e.currentTarget.value = state( )}
return <form>
<input
type="text"
value={state()}
onInput={e => inputHandler(e)}
/>
</form>
}
export default App Update: If you want to preserve the cursor position: const idHandler: JSX.EventHandlerUnion<HTMLInputElement, InputEvent> = (e) => {
const input = e.currentTarget
const value = input.value
const selectionStart = input.selectionStart - 1
if (value.match(/^[a-zA-ZáéíóúÁÉÍÓÚüÜñÑöÖ0-9_\-]+$/)) setState(value)
else {
const previousValue = state()
input.value = previousValue
input.setSelectionRange(selectionStart, selectionStart)
}
} |
Beta Was this translation helpful? Give feedback.
-
Proposed solutions are unnecessarily verbose, it is best to set a new value to the element inside the event handler using the event object: event.currentTarget.value = 'new value'; Now you have a controlled component. |
Beta Was this translation helpful? Give feedback.
-
I always get so confused when I look at this convo import { createSignal, type Component } from "solid-js";
const ControlInput: Component = () => {
const [search, setSearch] = createSignal("");
return (
<form>
<input
type="number"
value={search()}
onInput={(e) => setSearch(e.currentTarget.value)}
/>
</form>
);
};
export default ControlInput; |
Beta Was this translation helpful? Give feedback.
-
We had a similar problem building a multi-line textarea that submits on enter key. Sharing this to add another use-case for solid devs to consider, along with a solution. Requirements
Problems
SolutionIn the end, I was inspired by old jQuery answers on stackoverflow that basically do Here's the playground and code: const [input, setInput] = createSignal('')
return (
<form id='formId' onSubmit={e => {
e.preventDefault()
console.log('Submitted: ' + input())
setInput('')
}}>
<textarea
value={input()}
onInput={e => setInput(e.currentTarget.value)}
onKeyDown={e => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault()
const form = document.getElementById('formId') as HTMLFormElement
form.requestSubmit()
}
}}
/>
<button>Submit</button>
</form> |
Beta Was this translation helpful? Give feedback.
-
This is one of the topics gets out of hand and the one that people try to force React's way of thinking in Solid. First of all you don't need controlled components to validate your form values. Controlled components does not work well with natural order of browser events. Just use regular state management and indicate an error for the invalid inputs and do not post your values until they are all valid. Controlled inputs are good for forcing the correct value while typing. |
Beta Was this translation helpful? Give feedback.
-
I found a very easy fix, NOT HACKY AT ALL, for that and @ryansolid maybe could point that out on some side documentation for Solid newcomers from React. Use a normal Let the createEffect modifies your input in real time instead of trying to do some hacky workaround over the input event callback. |
Beta Was this translation helpful? Give feedback.
-
How about this? At first glance seems to work on ff, chromium https://playground.solidjs.com/anonymous/7db5e732-718d-40b5-8a4d-a47ff29109e2 import { render } from "solid-js/web";
import {
createSignal,
createEffect,
on,
type ComponentProps,
splitProps,
onMount,
onCleanup,
} from "solid-js";
function ControlledInput(props: ComponentProps<"input">) {
const [local, others] = splitProps(props, [
"value",
"ref",
"oninput",
"onInput",
]);
let ref: HTMLInputElement | undefined;
const updateInput = () => {
if (!ref || !local.value) return;
ref.value = (local.value || "").toString();
};
createEffect(
on(
() => local.value,
() => {
if (!ref) return;
updateInput();
},
),
);
const onInput = (
e: InputEvent & {
target: HTMLInputElement;
currentTarget: HTMLInputElement;
},
) => {
void Promise.resolve().then(updateInput);
if (typeof local.onInput === "function") {
local.onInput(e);
}
if (typeof local.oninput === "function") {
local.oninput(e);
}
};
return <input ref={ref} onInput={onInput} value={local.value} {...others} />;
}
function App() {
const [state, setState] = createSignal("");
onMount(() => {
const i = setInterval(() => {
setState("[FOO]");
}, 3e3);
onCleanup(() => {
clearInterval(i);
});
});
return (
<ControlledInput
placeholder="HELLO"
value={state()}
onInput={(e) => {
if (e.target.value.length > 10) return;
setState(e.target.value);
}}
/>
);
}
render(() => <App />, document.getElementById("app")!); |
Beta Was this translation helpful? Give feedback.
-
Using import { createSignal } from 'solid-js'
const Example = () => {
const [phoneNumber, setPhoneNumber] = createSignal('')
return (
<input
value={phoneNumber()}
onBeforeInput={e => e.data?.match(/\D/) && e.preventDefault()}
onInput={e => setPhoneNumber(e.target.value)}
/>
)
}
export default Example |
Beta Was this translation helpful? Give feedback.
-
IMPORTANT: If you have a question or an idea for a new feature use Github Discussions instead
Describe the bug
I passed a string as value into
<input/>
. when user type, I didn't change the value, but the value in the input element are still changed.To Reproduce
see playground
Expected behavior
if I do not change the value, the value in element should not change. (as what is in react)
Beta Was this translation helpful? Give feedback.
All reactions