Stimulus controller action firing twice

Viewed 1184

I'm new to StimulusJS, I just want to show the post content appended after other posts when the user adds a new post. Everything seems to work but the post is appended two times so it looks like the form was submitted twice.

  <div data-controller="posts">
     <div data-target="posts.add">
     </div>
     <!-- this is from a rails partial but it's all inside the data-controller -->
     <%= form_with scope: :post, url: posts_path, method: 'post', data: { action: "post#addBody" } do |form| %>
     <%= form.text_field :content, class: "form-control", data: { target: "posts.body"} %>
     <%= form.submit class: "btn btn-primary" %>
  </div>

The actual controller:

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = ["body", "add"]

  addBody() {
    let content = this.bodyTarget.value;
    this.addTarget.insertAdjacentHTML('beforebegin', `<div>${content}</div>`);
  }
}

I know this works because it shows the post on the page when the form submits, but the function is called again and the post appears two times. I've tried this with debugger and it seems like something internal in Stimulus is calling addBody() a second time?

As context this is what the posts_controller is doing:

  def create
    @post = current_user.post.build(post_params)

    respond_to do |format|
      if @post.save
        format.json {head :ok}
      else
        raise ActiveRecord::Rollback
      end
    end

  end
2 Answers

Turns out the issue was in my application.js file. I had:

const application = Application.start()
const context = require.context("../controllers", true, /\.js$/)
application.load(definitionsFromContext(context))

import "controllers"

I don't know how the line: import "controllers" got there or what I thought it did but after removing it things are only firing once.

So I know that by default, a form should listen for the submit event so you don't need to include the event name (See here for event shorthands) but I wonder if because it is a form with remote: true then it is also listening to the ajax:success event. If you try changing your data action to only listen for the ajax:success event does that solve it?

data: { action: "ajax:success->post#addBody" }

P.S I know this is a kind of speculative answer so might warrant a comment rather than an answer, but I do not have the reputation points to make a comment.

Related