-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Implement {#with}
block construct
#4601
Conversation
modifier: (node: Node) => Node; | ||
} | ||
|
||
function unpack_destructuring(contexts: Context[], node: Node, modifier: (node: Node) => Node) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would obviously be simplified once #4596 is merged.
So I can find it when I'm making the changelog, this would close #1521. |
I also notice that in #4169, I expressed doubts about the name |
What if we supported some kind of destructuring?
|
@arxpoetica Deconstructing is already supported by both each blocks and my pull request.
Well I'm open the renaming it if you think it's a good idea. What alternative name should we use? I posted a few at the end of my original post but I'm not really partial to anything. |
Personally, I like |
I personally much prefer the |
Workaround for some cases:
|
I vote for calling it Until then, abuse the language like this: {#await {} then {foo = 10, bar = 20}}
{foo}/{bar}
{/await} Edit: I forgot.. Javascript actually has the If svelte should have {#with {foo: "bar"}}
{foo}
{/with} Which would display the string "bar" |
either way it doesn't make sense in the xml tree |
Rebased off master and added changes from #4596. @Conduitry Any thoughts based on the discussion? If you think we need more user feedback how do we go about that? |
I don't think anyone has raised this issue yet but I think this is a bad idea from a design perspective. One of Svelte's advantages, for me, is that the template is kept relatively clear of logic due to the constraints of the syntax. This forces developers to put the bulk of their logic in the script where you would expect it to be and also keeps it in one place. This feature muddies that line and paves the way for arbitrary logic anywhere in the template. I don't understand the value of being able to alias variables directly in the template and the other uses cases can be dealt with by preparing your data ahead of time, instead of performing computations directly in an Additionally, I think this kind of API addition should go through the RFC process, it changes the template constraints pretty significantly and should be discussed in full. |
One of Svelte's advantages, for me, is that I can test out ideas with relatively few lines of code. the When I'm prototyping components I like to manage the data where it appears, and not send it back and forth if there is no reason for it. I also don't like to be forced by a language to do things a certain way. If In some cases, I could also create a component without any |
How? You can still do everything inside a loop if you need to, you certainly don't need to split it out to a separate component. I'd love to see an example of the problem that this actually solves.
Svelte forces you do to do all kinds of things in a very specific way (as does every other framework/library), those constraints generally make for a better experience. Adjustments are always needed but that is the trade-off. This makes tools, pattern and integrations simpler. It makes Svelte code across projects more consistent. This is basically a design goal at this point, even though it has evolved organically.
Guidelines do very little. Developer discipline is not a reliable method of encouraging best practices, they have to be enforced to be reliable. If something isn't a great idea, the tools should support that approach. Adding an API for something is an endorsement of that approach. |
For me with #with i can run helper function once in template
Instead of calling |
Something like this, maybe.... {#each array as element}
{#with status}
{#await status}
Updating...
{:then value}
<button on:click={ () => status = fetch(element.url) }>{value}</button>
{/await}
{/with}
{/each} |
Or something like this: <script>
let files;
function uploader(node, file) {
const reader = new FileReader();
const ref = firebase.storage().ref();
const fileRef = ref.child(file.name);
const task = fileRef.put(file);
task.on('state_changed', function progress(snapshot) {
const percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
let event = new CustomEvent("progress", { detail: percentage });
node.dispatchEvent(event);
});
reader.addEventListener("load", function () {
node.src = reader.result;
}, false);
reader.readAsDataURL(file);
}
</script>
<input type="file" multiple bind:files>
{#if files}
<ul>
{#each files as file, index}
{#with progress = 0}
<li>Upload:
<progress id="file" bind:value={progress} max="100"> {progress}% </progress>
<img on:progress={ ({detail}) => progress = detail }
use:uploader={ file } style="height: 50px;" />
</li>
{/with}
{/each}
</ul>
{/if} |
Or, better written like this. Though, if stores could be defined in a <script>
import { tweened } from 'svelte/motion';
let files;
const upload = (file) => {
// simulate upload
const progress = tweened(0, {delay: 500});
progress.set(100);
return progress;
}
</script>
<input type="file" multiple bind:files>
{#if files}
{#each files as file}
{#with progress = upload(file)}
<progress id="file" value={ $progress } max="100" />
{/with}
{/each}
{/if} |
Without <script>
import {tweened} from 'svelte/motion';
let files;
let progress = [];
const upload = (file, index) => {
// simulate upload
const p = tweened(0, {delay: 1000});
p.set(100);
p.subscribe(val => {
progress[index] = val
});
}
$: files && Array.from(files).forEach((file, i) => upload(file, i));
</script>
<input type="file" multiple bind:files>
{#if files}
{#each files as file, index}
<progress value={ progress[index] || 0 } max="100" />
{/each}
{/if}
<style>
progress {
display: block;
}
</style> |
I've just opened an RFC that proposes a similar addition, |
Whenever I encountered this issue, this is what I did:
It works and its easy to understand what it does. I don't see why we need a |
This PR implements the
{#with}
block constructs to be used as the following.This construct would be useful to alias deep values, destructure values, or to avoid recalculating expensive operations. There are times such aliasing can be done using a computed variable but this is not always the case and can make the template less readable.
There are at least two situations where it is not possible to use a computed variable.
While it is true that this can be accomplished in the above cases using a child component, this isn't always desirable, such as when only a few lines use the alias or when decoupling from the rest of the template would be nontrivial.
Alternative syntax
{#alias a as b}
{#let b = a}
{#set b = a}
{#assign b = a}
{#assign a to b}