Stimulus Discourse

Data target in partials


#1

I’m using Stimulus ina Rails (5.2) app and I have created a controller to manage Tags (A Project have many Tags).
Within the controller, I currently display the form used to add a Tag,

<div class='' data-controller='tags'>
    <div class='tags'>
      <%= render @project.tags %>
      <div class='' data-action='click->tags#displayForm' data-target='tags.addButton'>add tag</div>
    </div>

    <%= form_with model: Tag.new, url: project_tags_path(@event) do |f|  %>
      <div class='' data-target='tags.form'>
        <%= f.text_field :name, class: '', data: { action: 'keyup->tags#toggleSubmitButton', target: 'tags.textField' } %>
        <%= button_tag 'add tag', type: 'submit', class: '', data: { target: 'tags.submitButton' } %>
        <%= tag.a 'dismiss', class: '', data: { action: 'click->tags#hideForm', target: 'tags.dismissButton' } %>
    </div>
  <% end %>
</div>


import { Controller } from "stimulus"

export default class extends Controller {
  static targets = ["form", "addButton", "submitButton", "textField"]

  connect() {
   ...
  }

  displayForm() {
   ...
  }

  hideForm() {
   ...
  }

  toggleSubmitButton() {
  ...
  }
}

Now I’d like to add the ability to delete a tag by clicking on a button inside the tag.

#_tag.html.erb
<div class=''>
  <%= tag.name %>
  <button class=''></button>
</div>

My first idea was to add this functionality to the TagsController as follows

<div class=''>
  <%= tag.name %>
  <button class='' data-action='click->tags#deleteTag' data-target='tags.deleteButton'></button>
</div>

However, this works only for the first Tag.

So, what is the preferred way to deal with repeated elements (partials)?
Should I have a controller dedicated to deleting the Tag like below

<div class='' data-controller="deleteTags">
  <%= tag.name %>
  <button class='' data-action='click->deleteTags#deleteTag' data-target='deleteTags.deleteButton'></button>
</div>

Having already all the logic related to the creation in the TagController it makes sense to me to keep also the one responsible for deleting Tags in same controller.


#2

Show us your tags#deleteTag handler.

If it removes the tag clicked on by targeting the parent of the event.target element - it should work for all tags without any data-target on the them.


#3

Hi @stevenchanin,
I’m very new to Stimulus so I probably do if the wrong way.

Compared to the code above, I have added to the button an extra data attribute, data-url, which contain the action to call.

<button class='' data-action='click->tags#deleteTag' data-target='tags.deleteButton' data-URL=<%= projects_tag_path(@project, tag) %>></button>

Now in deleteTag I just need to be able to access the data-URL of the button I click (the ajax call is not an issue). So I have

        deleteTag() { console.log(this.deleteButtonTarget.getAttribute('data-url'))
        } 

Thanks


#4

you need to use the event that is passed to the delete function

deleteTag(event) { 
  console.log(event.target.getAttribute('data-url'))
} 

You can read more details here : https://stimulusjs.org/reference/actions especially regarding the difference between event.target and event.currentTarget


#5

@adrienpoly Thanks for the reply.


#6

@adrienpoly response is right, I just want to add that you can get the data attributes using the ES API:

console.log(event.target.dataset.url)

Examples