-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add property pipes/transforms #7265
Comments
I think for two way binding this sounds like a useful thing, for simple props this saves exactly one character and I don't see it solving a real problem there: <input value|trim={value} />
vs
<input value={trim(value)} /> I don't think chaining multiple of these transforms is a good idea. They most likely will always be asymmetric and once you have more than one of them chained it'll take some mental gymnastics to figure out what's happening with your two way binding.
In a similar scenario I'm using what I call "upgraded" stores. They are like derived stores, but two way. They have an let setStore = upgradeStore(
arrayStore,
(a) => new Set(a),
(s) => [...s]
); I'm sure you can apply something similar to your problem and abstract this nicely into a helper function. Once again stores save the day 🦸 |
The problem with the store solution is that it is quite verbose and requires the existence another store to begin with. This is an unfortunate tendency that I have observed when it comes to stores: They tend to proliferate. I would like to avoid introducing stores as much as possible, especially since there currently are some limitations (like using I agree that for just property input this feature is of limited use; my main use cases also revolve around Not being able to chain the pipes directly would not be that big of a deal, they can easily be combined manually in code. E.g. import { toUpper, trim } from './pipes';
const combined = x => toUpper(trim(x)); (Or higher order functions could be used to combine pipes arbitrarily.) |
That's not 100% accurate, as you could two-way sync the upgraded store with the local To me "stores" aren't really stores. They are the glue to make imperative code accessible in a declarative environment. The fact that you can treat Anyway, I agree that stores are not the solution here. But maybe what you are proposing does not capture the big picture. What I would love to see is being able to hook into reactivity in general. So that I can give regular variables the same treatment I do with stores. I want to hide imperative code behind declarative code. And that is essentially what you are asking for here as well, but only for a limited use-case. I want to do that everywhere. And I think some changes to reactivity are planned in v4 anyway, so let's hope someone comes up with a nice way to do that. Basically I want something like |
Just stumbled upon this issue which seems to be a more specific version of what I wrote here: #3937 Dummdidumm even suggested the same object-based extension:
|
Using actions is not too verbose: export function trim(node: HTMLInputElement, cb?: (val: string) => unknown) {
const updateVal = () => {
const oldValue = node.value;
node.value = node.value.trim();
if (oldValue !== node.value) {
cb?.(node.value);
}
};
node.addEventListener('blur', updateVal);
node.addEventListener('keydown', (val) => {
if (val.key === 'Enter') {
updateVal();
}
});
} and <input type="text" bind:value={filename} use:trim={val => filename=val}> |
Agree that this isn't desirable or necessary for props ( For bindings, this is solvable in Svelte 5 with a getter/setter pair as shown here: #9998 (comment). That issue (#9998) proposes a more general solution to this problem, so I'll close this issue in favour of that one. |
Describe the problem
Sometimes a value does not quite fit a property, or the component does not quite fit the value, so the value needs to be pre-processed before passing it in. Likewise, for
bind
-able properties, the output may not be in the correct format, so some post-processing is required.This is especially prone to happen with third-party components which cannot be easily changed.
So instead of being able to just use a property or
bind
directly, one may have to rely on additional events or pass the value through a temporary variable instead.Describe the proposed solution
To make this easier a pipe/transform syntax could be added to properties, to concisely perform pre-/post-processing in a reusable fashion. I would suggest using the
|
symbol, similar to how it used for event modifiers e.g.This would perform a trimming operation in both directions when used with
bind
. Alternatively an object could be supplied of the form:e.g.
in
would be called when passing the value into the component/element,out
when a value is provided from a property withbind
. If a function is not supplied, it acts as the identity function, i.e. the value is just passed through.When multiple pipes are supplied (
|
separated, like events), they would be executed left to right on input and right to left on output.The piping functions could potentially also be provided with the current element/component to make it even more flexible:
It could probably not be supplied in all cases, like when setting properties on
<svelte:options>
.Alternatives considered
Wrapping components is always an alternative, but not a very good one. It produces a lot of overhead and strongly couples the API if all component features should be exposed.
Temporary, intermediary variables tend to have problems with cyclical dependencies, as the updates should run both ways. If a component offers sufficient events this can be circumvented more easily.
I cannot really think of a good alternative but am happy to hear of any, if they exist.
Importance
would make my life easier
The text was updated successfully, but these errors were encountered: