-
-
Notifications
You must be signed in to change notification settings - Fork 41
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
Looping (webc:for
)
#28
Comments
Okay, I don't have a whole thought here but I want to get it down: Web components use Webc uses the For loops, what about something like <ul :each="`data`" :as="`item`">
<@template>
<li @html="`item.name`"></li>
</@template>
</ul> Conditionals are harder because you want to be able to use them inline with other markup, which would make them harder to read rather than easier to read. Conditionals are kinda when you cross over from being markup to being something else. |
Definitely agree with that. What I've found from working on Vue codebases is that it can be easy to overlook a control structure when it's expressed as an attribute on an HTML node. Compare: <li @for="p in this.collections.post">{post.title}</li> with the Svelte's handlebars-inspired approach: {#each this.collections.post as post}
<li>{post.title}</li>
{/each} It just feels breaking the control structures out to be their own entities feels more honest, explicit, and readable. |
Another incomplete thought.... (Blame @MWDelaney for setting the precedent!) Could you implement syntactic sugar for flow control as... just a small library of web components? Would you want to? <for-each :in="`data`" :as="`item`">
...
</for-each> Not sure if that's doable or advisable. |
Oh heck are we learning why WordPress went with HTML comments in real time? <!-- webc:each data as item -->
<li @html="`item.title`"></li>
<!-- webc:endeach --> |
Could you ship this separately and then build special-class support for it into webc to pre-render it? |
I'd suggest looking to Alpine's directive syntax for inspiration here. It's inspired by Vue but uses the real DOM so it's more HTML-forward. For example the
|
This is genuinely the whole version of the half-thought I had above. Thank you for this. I mean this in a credit-giving, not a credit-taking way. |
Just for folks visiting this issue prior to its completion (and do not take this comment as detracting from the enhancement proposed here) this is possible today using |
Right. It was actually putting together the home page for https://11ty.webc.fun/ that prompted me to open this issue in the first place. I use a render function to list recent posts there. An example of looping with render functions is on the site, if anyone wants to see how I did it. |
This plus reprocessing would be beautiful together! |
For fun i experimented with putting jsx directly in a template tag using a custom transform: <template webc:type="jsx">
<my-component>
<p>Hello, {this.name}!</p>
<ul>
{[1, 2, 3].map(i => <li>{i}</li>)}
</ul>
<p>
<slot></slot>
</p>
{Math.random() > 0.5 ? <span>high</span> : <span>low</span>}
</my-component>
</template> It works sort of like the built in render type, but first it passes the template contents through esbuild to transform the jsx Edit: in case it's not clear, this results in a plain html string, no virtual DOM or anything like that |
One thing that I think would really benefit beginners would be differentiating variables/code from strings. Take this line for instance: <li @html="title"></li> It is not clear to a beginner if Consider instead this: <li @html={ title }></li> It's much clearer that To my mind this is much simpler to understand. Also this: <li @html={ title }></li> Could then be syntactic sugared into <li>{ title }</li> Having the content between the HTML tags makes it a little clearer. I suspect that this would also make creating a styling/formatter plugin for VSCode that much easier to accomplish. |
Follow along to #73 for render functions that just return the value from the last statement (similar to dynamic attributes). Lots of amazing inspiration in this thread! Gotta say my favorite so far is: #28 (comment) Though I think it’d be more intuitive to copy JS looping syntax (with <ul>
<template webc:for="let entry of myArray">
<li @html="entry"></li>
</template>
</ul> <ul>
<template webc:for="let key in myObject">
<li @html="myObject[key]"></li>
</template>
</ul> |
Moved |
I still think there is a place for |
What if the Eleventy plugin added |
webc:for
)
I experimented a bit with eleventy-plugin-webc. With the use of a filter function say: config.addFilter("loop", function(array, callback) {
return array.map((item, index, source) => callback(item, index, source)).join("\n");
}); Now I can write something like: <ul @html="loop(collections.all, (item) => `
<li>${item.data.title}</li>
<ul>
<li>${item.data.description}</li>
<li><a href='${item.page.url}'>${item.page.fileSlug}</a></li>
</ul>`
)">
</ul> I can imagine an integration where you could have: <ul @loop="(collections.all, (item) => `
<li>${item.data.title}</li>
<ul>
<li>${item.data.description}</li>
<li><a href='${item.page.url}'>${item.page.fileSlug}</a></li>
</ul>`
)">
</ul> Just an idea. 😄 |
Have used alpine before and am a big fan :) I tried some of the solutions above, but ended up falling back to My halfway solution for now is:
|
As far as I can tell, this wouldn't just be syntax sugar. Maybe I'm missing something? Currently, using Maybe I could get clever and use item indexing to generate more complex arguments that get output in dynamic attributes and re-compiled? But that feels like a hack, if it would even work? The alternative is mixing template languages, which gets messy fast. Especially since the render shortcodes expect an object, and liquid has no way of creating objects on the fly… |
Agree with @mirisuzanne here. It's not appropriate to call this "sugar". This enables common use cases that are currently not possible to do in When using 11ty, we can use <main role="main">
{%- for item in collections.all reversed %}
{% renderTemplate "webc", item.data %}
<post-item webc:nokeep></post-item>
{% endrenderTemplate %}
{% endfor -%}
</main> This is 11ty providing a way to do this. Not necessarily |
webc:for
)webc:for
)
Docs are up at https://www.11ty.dev/docs/languages/webc/#webcfor-loops |
Implementation feedback is welcome—looking to ship WebC v0.9.4 somewhat soon (within the next few business days) |
This is awesome and opens new possibilites! now i'll make another example using webc:for so i can showcase more ways to do the same! thank you for your amazing work! |
Wow @zachleat, this is extremely rad. Thank you! Just doing a quick test (grabbed 11ty repo and dropped it into my project, overriding the existing folder at ✅ This works as expected
✅ As does this!
Am very excited about this :)
Stopping the server and starting it again sorts it out, but only for the first build. I'm doing tests in an existing project, so will set up a cleaner env to see if I can pin it down.
Edit 1: Here is a quick test repo , inspired by @mdarrik in #115 Edit 2: Fetching of dynamic data doesn't seem to be related. I've got a branch here with a hardcoded file in |
@d3v1an7 can you copy and paste your comment whole-sale to a new issue? (please!) |
Just FYI this milestone changed to 0.10.0! |
Flow control — conditionals and loops — is handled with render functions. This is powerful, since you can write arbitrary JavaScript, but it’s a bit ugly in the template. Even a simple loop listing posts from an Eleventy collection is a bit noisy, and it’s not necessarily obvious what is happening inside the
<script>
tag.Although you could combine WebC with another template language (e.g. Nunjucks) for flow control, it would be nice to have a less verbose way to write loops and conditionals, similar to how we have
@html
for setting the contents of an element.Example loop
For context, this is a simple loop generating a list of links to pages from an Eleventy collection using a render function.
Update: As of WebC 0.7, the above render function can now be written using
webc:type=js
like this, which is a little more succinct.Inspiration
One solution to this problem could look like how Vue handles this with an attribute;
v-for
in Vue, so maybe@for
in WebC.Another option might be the JSX-like approach in Astro. Perhaps instead of using
{}
as if it’s a template literal the way Astro does, the render function script tag could just omit the function and return statement and just return the value of the last statement (like Ruby).The text was updated successfully, but these errors were encountered: