10

I have a list of items, and each one has a link to click to edit it. I am using stimulus to make the edit "modal" form visible when they click that edit link. The id of what is going to be edited is present as an id= on the corresponding link tag of the list

So, the edit link looks like this:

<td>
  <a data-action="click->content#edit"
     data-target="content.editBtn"
     id="<%= url_for(content) %>")>
    Edit
  </a>
</td>

And the idea is that the content#edit action in the stimulus controller examines the and locates the id of it and uses that to edit the right row.

However the problem I am having is, I think, that as a result all the rows of this list have a data-target with the same name and the wrong one (the first one?) gets bound to the target..

However if I wanted to make each data-target different by e.g. appending the id to it, now I have a long list of targets in the controller.js so that doesn't make sense.

What's the right way to handle?

ssuperczynski
  • 3,190
  • 3
  • 44
  • 61
pitosalas
  • 10,286
  • 12
  • 72
  • 120
  • Just to make sure I'm on the same page, are you loading one modal into the view for each item you're displaying? – s_dolan Jul 13 '18 at 21:36
  • I’m trying to avoid that. I have one instance of the modal forms markup that is to be made visible to edit the particular row being edited. – pitosalas Jul 15 '18 at 00:48
  • If you're using Rails as the backend like your other questions seem to indicate, there may be a simpler, non-Stimulus solution. To use Stimulus, you'd need to fetch the data for the item from the server or from the DOM, display it in a form, then submit the correct form with the correct ID to the server through JavaScript. Why not just have a remote `link_to` button to the edit action for each item? Rails gets a `JS` request to the `edit` controller action, and you can load the modal form with the data that you have from your Ruby object. I can write up a full answer if you like that approach. – s_dolan Jul 15 '18 at 15:29
  • Yes it sounds like you are exactly right in your diagnosis of how it went with Stimulus and that a remote form would be better and easier.My specific goal was really to learn Stimulus, which I did :) But this use case got a little convoluted! – pitosalas Jul 16 '18 at 00:59
  • I think Stimulus is still a *great* tool for this scenario, just not for the part of it that you're using it for. I'd use this opportunity to craft a Stimulus controller that listens to the `ajax->send/error/complete` events and automatically disables/enables buttons, sets loading spinners on buttons, and closes the modal. Those would at least be good areas to sprinkle in some functionality that Stimulus makes super easy. – s_dolan Jul 16 '18 at 12:43
  • @S_dolan can you post an answer (copy your comment)and I will upvote and accept! Thanks ! – pitosalas Jul 16 '18 at 12:50

3 Answers3

4

If you're using Rails as the backend like your other questions seem to indicate, there may be a simpler, non-Stimulus solution. To use Stimulus, you'd need to fetch the data for the item from the server or from the DOM, display it in a form, then submit the correct form with the correct ID to the server through JavaScript. Why not just have a remote link_to button to the edit action for each item? Rails gets a JS request to the edit controller action, and you can load the modal form with the data that you have from your Ruby object.

If you use Stimulus for anything on the form, I'd use this opportunity to craft a Stimulus controller that listens to the ajax->send/error/complete events and automatically disables/enables buttons, sets loading spinners on buttons, and closes the modal. Those would be good areas to sprinkle in some functionality that Stimulus makes very simple.

s_dolan
  • 1,196
  • 1
  • 9
  • 21
4

This is actually a good use of Stimulus since it is modular. You add a controller for each row instead of having the controller around the page or table.

<tr data-controller="content">
  <td>
    <a data-action="click->content#edit" data-target="content.editBtn" id="<%= url_for(content) %>")>
      Edit
    </a>
  </td>
</tr>
sam
  • 966
  • 6
  • 10
3

I was just having a similar problem.
This helped: https://codepen.io/smashingmag/pen/ExPprPG

Basically you can loop over the targets like:

for(let tgt of this.mySameNameTargets) {
  tgt.innerHTML = "Some Value"
}

This assuming you have this in the controller:

state targets = ["mySameName"]

You can also use "Action Parameters" to put the id in each row: https://stimulus.hotwired.dev/reference/actions#action-parameters

From those docs it looks like this:

<div data-controller="item spinner">
  <button data-action="item#upvote spinner#start" 
    data-item-id-param="12345" 
    data-item-url-param="/votes"
    data-item-payload-param='{"value":"1234567"}' 
    data-item-active-param="true">…</button>
</div>

// ItemController
upvote(event) {
  // { id: 12345, url: "/votes", active: true, payload: { value: 1234567 } }
  console.log(event.params) 
}

You can set the id of the item in that row in a param, and then when they click on that row you can dig it out of the params.

Pere Joan Martorell
  • 2,608
  • 30
  • 29
jacklin
  • 2,739
  • 1
  • 24
  • 31