Skip to content
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

Supporting two way derived parameters #9357

Closed
mrh1997 opened this issue Oct 25, 2023 · 3 comments
Closed

Supporting two way derived parameters #9357

mrh1997 opened this issue Oct 25, 2023 · 3 comments

Comments

@mrh1997
Copy link

mrh1997 commented Oct 25, 2023

Describe the problem

In svelte two way bindings are somewhat limited as it allows only binding values 1:1. But it is not possible to use derived values in a two way binding. I.e. if you use an <input type="date"/> (which value is of type string) and you want to bind the value to a variable of type Date two way bindings do not work.

Of course you could avoid two way bindings and use the on:changed event to update the date field. But what if you do not use a component but a custom component that does not provide a on:changed event?

Describe the proposed solution

Provide a rune (i.e. $connect) that receives a $state rune and one or multple filters. Every filter is an object that provides a convert and an un-convert method. When using this value in a two way binding the unconvert method could be implicitly used to set the original $state value.

This way for my example you would write:

let date = $state(new Date())
let dateAsStr = $connect(date, {
       convert:(date) => date.toISOFormat(), 
       unconvert:(str) => new Date(str)
});

The big advantage is, that you could refactor the second parameter into reusable "connector-functions" like "asDateStr":

...
let dateAsStr = $connect(date, asDateStr);

If the convert/unconvert method receives not only the new source value but also (optionally) the old destination value it would be even possible to create connector-functions like "asSorted" or "asFiltered":

let lst = $state([1,2,3,4,5]);
let sortedAndFilteredLst = $connected(lst, asSorted(), asFiltered(x => x < 4));

Alternatives considered

I am not away of existing alternatives.

Importance

would make my life easier

@Conduitry
Copy link
Member

You can do this today (even in Svelte 4) via two stores which keep each others values in sync. Example REPL: https://svelte.dev/repl/a4be9207ed7a4df6a3ce14514614d94c

You can also do this with runes today by having a object that exposes two properties, each with their own getter and setter, which keeps the other one in sync. I don't think we need more primitives for this.

@brunnerh
Copy link
Member

Related:

I think it would be worthwhile to have proper language support in the form of modifiers/pipes for this, so you do not have to clutter the scope with additional variables that only serve to modify a binding.

What is currently possible without additional language support or a new rune is not horrible but I would still call it a bit ugly.
Whether that should justify adding a new rune, I am unsure.

With existing runes (preview)

<script>
	import { dateStringProxy } from './date-utility.js';
	let date = $state(new Date());
	let dateString = dateStringProxy(() => date, v => date = v);
</script>

<input bind:value={dateString.value} type=date />

VS. hypothetical $connect

<script>
	import { dateStringProxy } from './date-utility.js';
	let date = $state(new Date());
	let dateString = $connect(date, dateStringProxy);
</script>

<input bind:value={dateString} type=date />

@mrh1997
Copy link
Author

mrh1997 commented Oct 26, 2023

@Conduitry : The Problem with stores is, that they work only if both variables may be provided by the store.
This means if one of the variables is a parameter you got from outside or is provided from another store this solution won't work.

@brunnerh: thanks for your tip. Will follow up on #7265 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants