Alpine: Dynamic $refs

Created on 7 Mar 2020  路  9Comments  路  Source: alpinejs/alpine

I'm making a little Todo app in AlpineJS and I'm wondering how to access $refs dynamically. Let's say we have a list of todos in an array and whenever a user wants to _edit_ a todo, I want the input field to be _autoselected_. However, the problem I'm running into is that I can't access that particular todo item with the ID of that todo.

Here's the CodePen I've made. The point of interest here is the edit(todo) function where it has the $nextTick function to auto select the todo. It seems to be working fine when you make one todo, but when you make more than one todo (let's say two), then the input field does not _autoselect_ anymore.

Here's some code to go along with it:

edit(todo) {
    todo.editing = !todo.editing
    this.$nextTick(() => {
      this.$refs.edit.select()
    })
  }

Here, I've tried things like this.$refs[todo.id].edit and this.$refs.edit[todo.id], but nothing seems to be working.

Now I don't know whether this is a limitation in the Javascript framework or my lack of understanding of the whole issue, but I would appreciate a response since the framework is kind of new and I tend to search for VueJS solutions online.

Thanks for the help!

Most helpful comment

So, currently you ACTUALLY could bind a dynamic x-ref like this:

<span :x-ref="todo.id"></span>

Then you can access it dynamically as well: $refs[todo.id].something...

I think I'm going to put converting x-ref to just ref like Vue for v3 of Alpine.

Thoughts?

All 9 comments

Currently refs can't be expressions, just strings (so they can't be dynamic).

So you would have to work around it, probably doing something like this.$el.querySelector('#' + todo.id)

This could be something that we want to add, I know @calebporzio likes features to work the same as they would in Vue.js

So, currently you ACTUALLY could bind a dynamic x-ref like this:

<span :x-ref="todo.id"></span>

Then you can access it dynamically as well: $refs[todo.id].something...

I think I'm going to put converting x-ref to just ref like Vue for v3 of Alpine.

Thoughts?

So that it looks like a regular attribute that can be bound? Seems like a good idea.

On the other hand, having the x- prefix makes it obvious what's alpine and what's not.

Yep, exactly, I think binding x-ref feels weird.

That's true re: Alpine, but the parity with Vue is probably better anyways.

Might be time to start a v3 label.

@HugoDF I've tried a similar approach using dynamic :ids.

So what I did is write the binded ID like this to the input field:

:id="`edit-${todo.id}`"

and in my function, I have this:

edit(todo) {
    todo.editing = !todo.editing
    this.$nextTick(() => {
      document.getElementById(`edit-${todo.id}`).select()
    })
  },

it works for the first todo I make, but when there is more than one, it doesn't _autoselect_ it (the first one still autoselects though).

Would you know what's wrong with my logic? Here's my CodePen for your reference. Thanks!

@bnikkhah
it works for me
edit(todo) { todo.editing = !todo.editing; setTimeout(() => { document.getElementById("edit-${todo.id}").select() }, 0); }

@KiryaAfimin Thanks it works!

Was this page helpful?
0 / 5 - 0 ratings