S
SolidJS10mo ago
Mobs

[SOLVED] Textfield patterns (input masks)

Hello, I am working on something where I want to no allow the user to delete a certain part of text in an input.
function CustomInput() {
// Define state for the input value
const [value, setValue] = createSignal(".meas example foo ");

// Function to handle changes to the input value
function handleChange(event: any) {
const inputValue = event.target.value;

// Check if the user tries to modify the static parts ".meas" or "foo"
const regex = /^\.meas\s[a-zA-Z]+\sfoo\s/;
if (inputValue.match(regex)) {
setValue(inputValue);
}
}

return (
<input
type="text"
value={value()}
onInput={handleChange}
pattern="\.meas\s([a-zA-Z]+)\sfoo\s(.*)"
/>
);
}
function CustomInput() {
// Define state for the input value
const [value, setValue] = createSignal(".meas example foo ");

// Function to handle changes to the input value
function handleChange(event: any) {
const inputValue = event.target.value;

// Check if the user tries to modify the static parts ".meas" or "foo"
const regex = /^\.meas\s[a-zA-Z]+\sfoo\s/;
if (inputValue.match(regex)) {
setValue(inputValue);
}
}

return (
<input
type="text"
value={value()}
onInput={handleChange}
pattern="\.meas\s([a-zA-Z]+)\sfoo\s(.*)"
/>
);
}
I have something like this, but the input's display value does not get updated if the pattern fails to match. What I want to achieve is if the user tries to delete the area of text that is not supposed to be touched we don't update state and the same should be reflected in the UI.
14 Replies
Jasmin
Jasmin10mo ago
Maybe the contenteditable attribute could be used for that https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable
MDN Web Docs
contenteditable - HTML: HyperText Markup Language | MDN
The contenteditable global attribute is an enumerated attribute indicating if the element should be editable by the user. If so, the browser modifies its widget to allow editing.
Alex Lohr
Alex Lohr10mo ago
You can use the input-mask primitive for that: https://primitives.solidjs.community/package/input-mask
Solid Primitives
A library of high-quality primitives that extend SolidJS reactivity
Mobs
MobsOP10mo ago
So actually I want be able to edit a certain part of the text. For example
.meas tran foo abc xyz
^^^^^^^^^^^^^^ ^^^^^^^
no edit editable
.meas tran foo abc xyz
^^^^^^^^^^^^^^ ^^^^^^^
no edit editable
Only abc xyz should be editable and not the first bit. I have tried using labels for the first bit and having the editable bit in its input but this causes me to write some super messy logic and its not scalable if want to add a different pattern Does this work if I have a default value?
Alex Lohr
Alex Lohr10mo ago
You can use this to add a default value. It really depends on your use case. I'm currently busy, but will have more time in 1h 10min. If you want personal support, I can provide it (since I'm the author of that primitive).
Mobs
MobsOP10mo ago
I actually have to go sleep in a bit I'll try to explain the use case more
Alex Lohr
Alex Lohr10mo ago
Okay. I'll provide a working example then.
Mobs
MobsOP10mo ago
So I am trying to make a generic platform different electrical/electronic circuit sims and long story short they use these instructions which look like this more or less depending on the simulator.
.meas tran Delay_fall trig v(Vinp) val =0 td =1n fall =3 targ v(Vout) val =0 fall=3
.meas tran Delay_fall trig v(Vinp) val =0 td =1n fall =3 targ v(Vout) val =0 fall=3
And I need to keep track of the name in this case it is 'Delay_fall' for the above instruction. So in this case I can't let the user change the .meas tran Delay_fall (this is for one case and one kind of syntax) So I really don't know what kind of other cases I will run into in the future so I would like to have a flexible system.
Alex Lohr
Alex Lohr10mo ago
I think I got the idea from your description. It's a bit difficult, because you need to use both the mask and provide an initial value. The mask alone would only provide an initial value if there is a value at all. Maybe we can use mask and pattern for that effect.
Alex Lohr
Alex Lohr10mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Alex Lohr
Alex Lohr10mo ago
Hope that helps.
Mobs
MobsOP10mo ago
This is great. Thank you But can you explain how this is working here?
const mask = createInputMask((value, selection) => value.length < len
? [protectedText, [len, len]] // little confused here
: maskArrayToFn([protectedText, /.*/])(value, selection) // here too
);
const mask = createInputMask((value, selection) => value.length < len
? [protectedText, [len, len]] // little confused here
: maskArrayToFn([protectedText, /.*/])(value, selection) // here too
);
Also how is setRef being called here?
<textarea ref={setRef} oninput={mask}>{protectedText}</textarea>
<textarea ref={setRef} oninput={mask}>{protectedText}</textarea>
Nevermind I played around with it I understand whats going on here.
function Counter() {
const [text, setText] = createSignal(".meas analysis_type Delay_fall");

const protectedTextRegex = new RegExp("^\.meas (?:[A-Za-z]+) Delay_fall");
const mask = createInputMask((value, selection) => {
return !protectedTextRegex.test(value)
? [text() + value.slice(text().length), [text().length, text().length]]
: maskArrayToFn([value])(value, selection)
});

return (<div>
<input value={text()} oninput={(e) => setText(mask(e))} />
<button onclick={() => console.log(text())}>print text to console</button>
</div>);
}
function Counter() {
const [text, setText] = createSignal(".meas analysis_type Delay_fall");

const protectedTextRegex = new RegExp("^\.meas (?:[A-Za-z]+) Delay_fall");
const mask = createInputMask((value, selection) => {
return !protectedTextRegex.test(value)
? [text() + value.slice(text().length), [text().length, text().length]]
: maskArrayToFn([value])(value, selection)
});

return (<div>
<input value={text()} oninput={(e) => setText(mask(e))} />
<button onclick={() => console.log(text())}>print text to console</button>
</div>);
}
This is pretty cool.
Alex Lohr
Alex Lohr10mo ago
The setRef is used in order to receive the value. If you want, you can also use the value from the return value of the input mask, but I usually like it better to get the value from an input ref once the user is done; less reactivity involved. How input mask works: it collects the selection start and end and the value out of an event. That gets fed to a function that returns a new value and selection start/end, which then is set. It accepts a number of formats: plain function, regex/replace function tuple, regex/string mask pattern, string pattern (in order of complexity). In this case, I needed to protect some text, which could not be easily achieved with the other types. If the value is shorter than the protected text, it returns the protected text and places the cursor at its end to protect it. Otherwise, it uses the mask to fix the text. It's basically the simplest possible way to mask user input.
Mobs
MobsOP10mo ago
In my case there are a variable number of inputs so keeping track of so many refs seems like a nightmare.
Alex Lohr
Alex Lohr10mo ago
that's fine too. That is why I made the mask handler return the value, so you can capture it in a setter.
Want results from more Discord servers?
Add your server