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

feature request: {#await let promise} #4665

Closed
knobo opened this issue Apr 12, 2020 · 7 comments
Closed

feature request: {#await let promise} #4665

knobo opened this issue Apr 12, 2020 · 7 comments

Comments

@knobo
Copy link

knobo commented Apr 12, 2020

When iterating over a list, I would like to be able to perform actions on that list without creating a separate component with its own local variables.

<script>
  let promise = 0
  let next = (value) =>  
    new Promise(resolve => setTimeout(() => resolve(value + 1), 1000))
</script>

{#each {length: 5} as i}
  {#await promise}
    Waiting
  {:then result}
    <button on:click={() => promise = next(result)}>Next</button>
    result: {result}
  {:catch error}
    error: {error}
  {/await}
{/each}

repl example

with {#await let promise} The action is local to each iteration.

and with a default value {#await let promise = "foo"}

@knobo knobo changed the title {#await let promise} feature request: {#await let promise} Apr 13, 2020
@Conduitry
Copy link
Member

What would the code you want to be able to write look like? Is this different from the more general {#with} proposal in #4601?

@knobo
Copy link
Author

knobo commented Apr 15, 2020

The difference is

-  {#await promise}
+  {#await let promise}

or even like this:

  {#await let promise = new Promise(...)}

Which is kind of, already supported. Since I can write:

{#await new Promise(resolve => resolve("yay!"))}
{:then result}
  {result}
{/await}

I want to make promise local in the {#each} loop.
The {#with} (please call it {#let} :) ), is more general since then you can get the same effect as I want here. Except with two more lines of code. I would say that #4601 is useful regardless of this feature. If you implement #4601, then implementing {#await let promise = new Promise()}, would make svelte consistent. So saying yes to #4601 would mean saying yes to #4665 (this one).

What I want to write is this:

{#each {length: 5} as i, index}
  {#await let promise = index}  
    Waiting for next
  {:then count}
    <button on:click={() => promise = next(count)}>{count}</button>
  {/await}
{/each}`

the promise is then local in every iteration. Then I don't have to write a compleatly new component. It is also much clearer code, as you know the promise is not littering the component variable namespace.

The goals:

  1. Shorter code
  2. Fewer components.
  3. Clean component variable namespace

@knobo
Copy link
Author

knobo commented Apr 15, 2020

without #4665, I would have to write:

<script>
	const promiseArray = []
	const next = i => new Promise(resolve => resolve(++i))
	const nextPromise = (index, i) => promiseArray[index] = next(i)
</script>

{#each {length: 5} as i, index}
{#await promiseArray[index]}
  Waiting
{:then count}
  <button on:click={ () => nextPromise(index, count || index) }>{count || index}</button>
{/await}
{/each}

@knobo
Copy link
Author

knobo commented Apr 15, 2020

Closer to real world example:

<script>
	const fetchData = () => new Promise(resolve => resolve(/* info from server */))
	const update = (info) => new Promise((resolve, reject) => {
		resolve(/* updated info from server */ info) 
		// reject({info, errorMessage: "Could not update"})
	})
</script>

{#await fetchData()}
 Fetching data from server...
{:then dataSet}
  {#each dataSet as data}
    {#await let status} // this is the let...
      Updating data...
    {:then info}
      <button on:click={ event => status = update(info) }>{info.title}</button>
      <input on:input={ event => info.newTitle = event.target.value } value={info.title}/>
    {:catch error}
      Could not update {error.info.title}
      <button on:click={ () => status = update(error.info) }>Retry</button>
      <button on:click={ () => status = error.info }>Cancel</button>
    {/await}
  {/each}
{/await}

@igorovic
Copy link

In my opinion the svelte should keep the markup syntax simple and clean.

This proposal sure adds a lot of possibilities to the markup language, but from my perspective data fetching should be done in the <script> tag.

@knobo
Copy link
Author

knobo commented Aug 30, 2020

Ok, I can update my example to not use data fetching. But it is still relevant.

@dummdidumm
Copy link
Member

Closing as this would introduce local state to the markup, which makes the code harder to reason about. It also doesn't seem like something like this is missed since this feature request hasn't gathered any traction.

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

No branches or pull requests

6 participants