As I was learning Alpine.js for a new project I came across a problem when using HTML inputs in nested x-for loops. Data binding was working great in a single x-for loop wrapped around an HTML input tag. But, when I nest nested loops, the data entered in the inner loop inputs is not binding to the data object.
The Non-Working Code
Here’s an example to demonstrate:
<script>
book_data = { books: {
a1: ['one', 'two', 'three' ],
a2: ['four', 'five', 'six' ],
a3: ['seven', 'eight', 'nine' ]
}
};
</script>
<!-- PROOF OF CONCEPT OF NESTED X-FOR LOOP IN ALPINE!
<div x-data = "book_data">
<template x-for="book in books">
<div>
<template x-for="number in book">
<input x-model="number" type="text" />
</template>
<button @click="book.push('ten')">Add Number</button>
</div>
</template>
<button @click="console.log(book_data);">Submit</button>
</div>
In this example, I have a nested x-for loop that loops through each of the books and then through multiple values for each book.
In the inner loop, there is an HTML input tag that has data with bi-directional binding using x-model.
So, when you type in data into an input, you would expect to see that data in the book_data object (in my example you can press submit to dump the object to the console). But this doesn’t work!
The Solution
The problem is that the inner loop operates on a copy of the data (number), not the data itself (book). Thus, the solution is to reference the data in the inner loop using the variable from the outer loop. Here’s the working code using the same data object:
<div x-data = "book_data">
<template x-for="book in books">
<div>
<template x-for="(number,index) in book">
<input x-model="book[index]" type="text" />
</template>
<button @click="book.push('ten')">Add Number</button>
</div>
</template>
<button @click="console.log(book_data);">Submit</button>
</div>
The problem was solved by changing x-model=”number” to x-model=”book[index]”, i.e., referencing the variable from the outer loop with the appropriate index, instead of the inner.
If you type in data into an input, then press the submit button, you’ll see that data in the object.
As a bonus, I have a repeater button just to show that things are working well.
I feel like this is a potential “gotcha” for beginners (like me) in Alpine.js. Did it help for you? Let me know in the comments! – Brian
I am a freelance web developer and consultant based in Santa Monica, CA. I’ve been designing websites using WordPress and from scratch using HTML, CSS, PHP, and JavaScript since 2010. I create websites and web applications for businesses, nonprofits, and other organizations. I have a degree in Electrical Engineering (BSEE) from California Institute of Technology and a degree in Engineering Management (MSEM) from Stanford University.
Discover more from Web Developer Tips and Tricks
Subscribe to get the latest posts sent to your email.
Please Leave a Question or Comment
This help me a lot. Thank you
Hi Tuan,
Thanks for commenting! I’m glad this was helpful.
Best,
Brian