This issue is to open a discussion about on the problem found here: https://twitter.com/devgummibeer/status/1223415287447461889?s=21
I replied to this tweet with an alternative syntax for this too, see here: https://twitter.com/ryangjchandler/status/1223664594784264194?s=21
I personally think this syntax would be pretty clean and takes a PHP-approach with the syntax too, using the 'as' keyword. Removed the need for nested x-fors, when you only need to do the second loop on a single nested item. In theory, this could be taken a lot further with deeply nested items.
I am playing around with the x-for code currently to find a good way of achieving this syntax, and if it's something people would find useful, I'll throw a PR in for Caleb to ponder over. Have a good one guys! 馃馃徏
As a short follow up to this and a quick chat with @SimoTod , there might still be some cases where you want to print something from the initial, 'parent' loop item. I'll find a syntax for this and report back.
This is my IMHO, but i hope it will main way.
If you think about alpine like vue replacement, you should correct some expectations. Alpine use to be small, DOM-oriented library, without massive DOM manipulation.
In Alpine way you should get not an items array, but a html fragment with rendered items. If you want other - go with Vue.
I think people would expect to be able to write
<div x-data="{items: [{title: 'test',tags: ['ok1','ok2']}, {title: 'test2',tags: ['ok2']}]}">
<template x-for="item in items">
<div>
<span x-text="item.title"></span>
<template x-for="tag in item.tags">
<span x-text="tag"></span>
</template>
</div>
</template>
</div>
which doesn't seem unrealistic to me.
In my opinion, either Alpine should support it or the documentation should make it clear that it's not a valid use case.
If it's the latter, I'm pretty sure it would alienate a few devs. Just imagine you start the project and close to the finish line, because a new requirement comes up, you have to convert everything to VueJS only because Alpine doesn't support nested loop, you would find it a bit annoying.
@ryangjchandler and I were chatting about that, we don't think it's impossible even with the current structure and it should't add any complexity to the project.
In response to this, I agree with @SimoTod , no reason this shouldn't be supported. Gonna throw a PR in tomorrow, it's currently midnight in the UK so too late for me.
Also going to investigate the syntax I proposed in the twitter thread, as a way of reducing the nested loops and hard to read code. If people don't like it, that's fine.
I agree that the documentation should describe the main approaches.
x-for inside x-for not only case that comes to my mind. How about x-if inside x-for or opposite, or x-data inside any of this. Some of this cases works, some not, But should we use them?
Now i know that x-for > x-data > x-for > x-data > x-if works perfect, but without x-props this apporach cannot be used. Why we should worry about x-for in x-for, if we can use x-props tomorrow? There is so many questions with one answer - use x-html with prerendered html.
EDIT:
For more clarity, (other portion of IMHO) prerendered html should come from backend ( you should not render html in js ). Therefore If your backend is json api - you should go with Vue or other vDOM lib.
I agree that backend should do most of the work but, with that in mind, we shouldn't have supported x-for and x-if at all, right?
As far as I know, x-if inside x-for works correctly. Looking at the source code, x-for is the only directive where we don't pass the extraVars variable, all the other combinations are supported as expected.
We will litteraly pass a variable in 3 points of the code, no added complexity nor massive increment in size, so it seems reasonable to support it.
I appreciate we can use x-html but it leads to complicated and error-prone code (my personal view) and I wouldn't suggest it as a best practice (devs with less experience would find that hard).
x-if and x-for has some use cases, where prerendered html is not applicable. For example - tags input component. or other cases when we need react to user input. But when we have x-for we can iterate over any list, why we can't get json from backend and iterate over it?
IMHO for more clarity and for avoiding wrong expectations we should get some preferences and declare it.
@ryangjchandler thanks for creating this issue.
I don't know if it's the valid scope of this package. But I don't want to load the whole Vue.js runtime only to render a simple dynamic list.
@ryangjchandler thanks for creating this issue.
I don't know if it's the valid scope of this package. But I don't want to load the whole Vue.js runtime only to render a simple dynamic list.
100%. I don't think you should have to load Vue for this single component. I'm going to throw a PR in tonight that should hopefully fix the problem you were having, we'll see how it goes.
Ah! I started using Alpine today on a project without checking here the issues on github. Immediately stumbled upon the same problem while I was building a form with nested repeater fields. I'd like for this feature to be added too so I can remove Vuejs from my project 馃憤
Adding my voice for nested x-for templates. We're using Alpine to present a single view of our application that other applications can inject, and I'd much rather use this than Vue for something so lightweight.
Our use case wouldn't work with the "item.iterable as thing in list" approach, as I'm having to loop through one list of items, then finding all the matching items in a second list. For example:
const list1 = [{id: 1, text: "hello"},{id: 2, text:"there"}]
const list2 = [{ref: 1, addlText: "world"}, {ref: 1, addlText: "everyone"}]
<template x-for="item in list1">
<div>
<template x-for="itemMatch in list2.filter(i => i.ref === item.id)">
...
</template>
</div>
</template>
It's not a big deal if this isn't possible, but it makes sense to me that if statements can be nested, they can use the scope of the current iteration for the nested loops.
Hi, guys. Obviously, we need this feature to loop through an array of objects twice. So, this happens mostly with people working with APIs and it's just another day for a front-end developer. Most of the people here just want this feature to use Alpine mainly in their projects. Which is why the maintainers should take this into consideration.
IMHO this should be a most feature. And am glad we are going on the right direction these days focusing on stability bugs.
But there is something we actually (maybe) forgot about. Which is the loop "index". We mainly use this for keying loop elements or manipulating the code of a specific iteration (sometimes using math). I think it shouldn't be ignored for another pull request and should be considered carefully while making a solution for this issue. The "x-for" is one of the complicated features in Alpine right now and this should be taken into count. For the future. That's all. I hope others feels that same about this. Thanks for this useful tool.
HI @the94air, good point. My understanding is that accessing the index variable using the same syntax as VueJS is in the pipeline (see https://github.com/alpinejs/alpine/issues/133).
There is how to deal with indexes right now (not Vue-way)
<h3>Iterate array</h3>
<div x-data="{list:['a', 'b', 'c']}">
<template x-for="[idx, val] in Object.entries(list)">
<div>
<span x-text="idx"></span>
<span x-text="val"></span>
</div>
</template>
</div>
<h3>Iterate object</h3>
<div x-data="{obj: {a: 'A', b: 'B', c: 'C'}}">
<template x-for="[idx, val] in Object.entries(obj)">
<div>
<span x-text="idx"></span>
<span x-text="val"></span>
</div>
</template>
</div>
One notice about idx from Object.entries(Array) - it is always has string type, So if you want check it with === you should firstly convert it to number.
Also check browser support at caniuse
I'm interested in this issue.
@SimoTod has this been fixed now that the new reactivity core has been merged?
I believe it's still an issue. I mentioned in #230 that the new reactivity component won't fix it, this is the reason why it shows in this conversation.
It's not related to the reactivity core but to the extraVars not being passed in the directive handler.
I'm waiting to know if we are interested in merging it. If we are, I can spend more time to update the PR.
Have just seen that PR mention! Sorry I missed it.
Hi. I am confused. Does alpine support nested loops in current version(2.x.x)?
@samadadi not yet
Is there any plan from alpine team to add nested loop implementation in future?
@samadadi pretty sure it's something that will be added, you've seen the PR for it right? https://github.com/alpinejs/alpine/pull/183
@SimoTod is just waiting on feedback from Caleb that his approach is going to get accepted.
yeah, that PR needs updating since there have been a few changes to the x-for logic since so it won't work straight away.
I'm waiting for Caleb to confirm that it's something we want to integrate before spending more time on it.
@samadadi check this out and see if it fixes your issue temporarily :)
https://github.com/alpinejs/alpine/issues/158#issuecomment-587398297
Also it seems to be supported everywhere except IE
https://caniuse.com/#feat=object-entries
Any updates on this?
Thanks everyone, this issue will be fixed in the next release. Here is the PR: #316
Note: for now, we are not supporting directly nesting <temlate> tags, but we WILL support nesting template tags with wrapping elements like so:
<div x-data="{ foos: [{bars: [{bobs: ['one', 'two']}, {bobs: ['three', 'four']}]}, {bars: [{bobs: ['five', 'six']}, {bobs: ['seven', 'eight']}]}] }">
<template x-for="foo in foos">
<div>
<template x-for="bar in foo.bars">
<div>
<template x-for="bob in bar.bobs">
<span x-text="bob"></span>
</template>
</div>
</template>
</div>
</template>
</div>
Most helpful comment
I think people would expect to be able to write
which doesn't seem unrealistic to me.
In my opinion, either Alpine should support it or the documentation should make it clear that it's not a valid use case.
If it's the latter, I'm pretty sure it would alienate a few devs. Just imagine you start the project and close to the finish line, because a new requirement comes up, you have to convert everything to VueJS only because Alpine doesn't support nested loop, you would find it a bit annoying.
@ryangjchandler and I were chatting about that, we don't think it's impossible even with the current structure and it should't add any complexity to the project.