stimulusjs

Dynamicly add a Button that is linked to an action


On connect, I want to add some markup that is connected to an action within the same controller. Is this possible? How is it done?

This is what I am trying so far in my tricksmods controller:

addEmbedButton() {
    const buttonHTML = '<button type="button" class="trix-button" data-trix-attribute="embed"   data-action="click->tricksmods#showembed" title="Embed" tabindex="-1">Embed</button>'
    this.buttonGroupBlockTools.insertAdjacentHTML("beforeend", buttonHTML)
  }

showembed(){
  console.log('showembed')
}

The markup is added, but the showembed action is not fired on click.


Solution

  • I worked this out. I needed to use the toolbarElement of the trix editor to get at my button and dialog.

    import { Controller } from "@hotwired/stimulus"
    import Trix from 'trix'
    import Rails from "@rails/ujs"
    
    export default class extends Controller {
      static get targets() {
          return [ "field" ]
      }
    
      connect() {
        this.addEmbedButton()
        this.addEmbedDialog()
        this.eventListenerForEmbedButton()
        this.eventListenerForAddEmbedButton()
      }
    
      addEmbedButton() {
        const buttonHTML = '<button  type="button" class="trix-button tricks-embed"  data-trix-attribute="embed" data-trix-action="embed"   data-action="click->tricks#showembed" title="Embed" tabindex="-1">Embed</button>'
        this.buttonGroupBlockTools.insertAdjacentHTML("beforeend", buttonHTML)
      }
    
      addEmbedDialog() {
        const dialogHTML = `<div class="trix-dialog trix-dialog--link" data-trix-dialog="embed" data-trix-dialog-attribute="embed" data-tricks-target="embeddialog">
                              <div class="trix-dialog__link-fields">
                                <input type="text" name="embed" class="trix-input trix-input--dialog" placeholder="Paste your URL" aria-label="embed code" required="" data-trix-input="" disabled="disabled">
                                <div class="trix-button-group">
                                  <input type="button" class="trix-button trix-button--dialog" data-trix-custom="add-embed" value="Add">
                                </div>
                              </div>
                            </div>`
        this.dialogsElement.insertAdjacentHTML("beforeend", dialogHTML)
      }
    
      showembed(e){
        console.log('showembed')
        const dialog = this.toolbarElement.querySelector('[data-trix-dialog="embed"]')
        const embedInput = this.dialogsElement.querySelector('[name="embed"]')
        if (event.target.classList.contains("trix-active")) {
          event.target.classList.remove("trix-active");
          dialog.classList.remove("trix-active");
          delete dialog.dataset.trixActive;
          embedInput.setAttribute("disabled", "disabled");
        } else {
          event.target.classList.add("trix-active");
          dialog.classList.add("trix-active");
          dialog.dataset.trixActive = "";
          embedInput.removeAttribute("disabled");
          embedInput.focus();
        }
      }
    
      eventListenerForEmbedButton() {
        this.toolbarElement.querySelector('[data-trix-action="embed"]').addEventListener("click", e => {
          this.showembed(e)
        })
      }
    
      eventListenerForAddEmbedButton() {
        this.dialogsElement.querySelector('[data-trix-custom="add-embed"]').addEventListener("click", event => {
          console.log('embeddy')
          const content = this.dialogsElement.querySelector("[name='embed']").value
          if (content) {
            let _this = this
            let formData = new FormData()
            formData.append("content", content)
            Rails.ajax({
              type: 'PATCH',
              url: '/admin/embed.json',
              data: formData,
              success: ({content, sgid}) => {
                const attachment = new Trix.Attachment({content, sgid})
                _this.element.editor.insertAttachment(attachment)
                _this.element.editor.insertLineBreak()
              }
            })
          }
        })
      }
    
      //////////////// UTILS ////////////////////////////////////////////////////
    
      get buttonGroupBlockTools() {
       return this.toolbarElement.querySelector("[data-trix-button-group=block-tools]")
     }
    
     get buttonGroupTextTools() {
       return this.toolbarElement.querySelector("[data-trix-button-group=text-tools]")
     }
    
     get buttonGroupFileTools(){
       return this.toolbarElement.querySelector("[data-trix-button-group=file-tools]")
     }
    
     get dialogsElement() {
       return this.toolbarElement.querySelector("[data-trix-dialogs]")
     }
    
     get toolbarElement() {
        return this.element.toolbarElement
      }
    }