# Stimulus and Rails UJS

**URL:** <https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587>\
**Category:** General\
**Created:** [December 21, 2018, 5:06pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587 "2018-12-21T17:06:55Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![tomrossi7](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/tomrossi7/32/408_2.png) [@tomrossi7](https://discuss.hotwired.dev/u/tomrossi7)\
**Post date:** [December 21, 2018, 5:06pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/1 "2018-12-21T17:06:55Z")

</div>

I have an XHR form that triggers an action when the submit button is clicked:

`<input type="submit" name="commit" value="Enabled " data-disable-with="Disabled" data-action="click->myController#myAction">`

The action prevents the initial submitting before calling submit directly on the form. Everything works great except the `data-disable-with`. I could do it manually, but would rather rely on the Rails UJS.

**How do I allow Rails UJS to disable and reenable the button within the Stimulus controller?**

---

<div class="post-metadata">

**Author:** ![kaspermeyer](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/kaspermeyer/32/483_2.png) [@kaspermeyer](https://discuss.hotwired.dev/u/kaspermeyer)\
**Post date:** [December 21, 2018, 7:22pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/2 "2018-12-21T19:22:11Z")

</div>

Unless you have a good reason to submit the form yourself you might be better off letting `rails-ujs` handle it.

You can use all the `rails-ujs` request lifecycle events on your actions, so if you need to perform some logic before the request is sent, you can listen to `ajax:beforeSend` on your action:

```auto
<form data-action="ajax:beforeSend->controller#prepareParams" ... >

```

If you have to enable/disable the button yourself, you can:

```auto
<form data-action="ajax:send->controller#disableButton ajax:complete->controller#enableButton" ... >

```

You can see the full list of events here: [https://guides.rubyonrails.org/working\_with\_javascript\_in\_rails.html#rails-ujs-event-handlers](https://guides.rubyonrails.org/working_with_javascript_in_rails.html#rails-ujs-event-handlers)

---

<div class="post-metadata">

**Author:** ![tomrossi7](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/tomrossi7/32/408_2.png) [@tomrossi7](https://discuss.hotwired.dev/u/tomrossi7)\
**Post date:** [December 21, 2018, 8:01pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/3 "2018-12-21T20:01:38Z")

</div>

Ah! I like it, but can’t get it to work! I’ve tried putting the `data-action="ajax:beforeSend->controller#prepareParams"` on both the submit button and the form, but the form just submits over XHR without ever triggering my Stimulus action. I tried `ajax:before` as well, but no joy? What could I be missing? Since we are using Turbolinks, are the same events still triggered?

I added this to the connect method in my controller and don’t see anything in my console:

```
document.body.addEventListener('ajax:beforeSend', function(event) {
  console.log(event);
})
```

---

<div class="post-metadata">

**Author:** ![tomrossi7](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/tomrossi7/32/408_2.png) [@tomrossi7](https://discuss.hotwired.dev/u/tomrossi7)\
**Post date:** [December 21, 2018, 9:06pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/4 "2018-12-21T21:06:12Z")

</div>

Thanks for all the help on this! We figured this out, rails-ujs was still being loaded through the Asset Pipeline. In order to hook into those events, we moved rails-ujs into our web packer. Now, I’m able to bind to the `ajax:beforeSend` method.

One last question related to this form submission with UJS. The `prepareParams` action actually has to use a callback to update the form. Unfotunately, the action completes and the form submits before the callback executes. I can use `event.preventDefault()` in the action, but then I have to submit the form old school with `form.submit()` in the callback. Is that the best approach?

---

<div class="post-metadata">

**Author:** ![kaspermeyer](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/kaspermeyer/32/483_2.png) [@kaspermeyer](https://discuss.hotwired.dev/u/kaspermeyer)\
**Post date:** [December 22, 2018, 10:27am UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/5 "2018-12-22T10:27:54Z")

</div>

Ah, you’re right, the actions have to be attached to the form, not the submit button — sorry! I’m glad you figured it out. I updated my example above.

I don’t think `form.submit()` will work in your case because it won’t submit via XHR. In what way does the callback have to update the form? You can try to listen for the `ajax:before` or `submit` event instead of `ajax:beforeSend` and see if the callback executes in time. Those events should fire even earlier.

If that doesn’t work, maybe the external service handling the callback provides a way to determine if the callback has finished? Maybe it supports a second callback which is executed when the first callback completes or perhaps it emits an event you can listen for?

If all hope is lost, you can try to wait for an empty promise or use `setTimeout`, which might execute after the callback completes, and then trigger Rails UJS to submit the form:

```auto
<form data-target="controller.form" data-action="ajax:before->controller#prepareForm" ... >

```

```javascript
static targets = ["form"]

prepareForm(event) {
  event.preventDefault()
  ExternalService.call(this.callback.bind(this))

  // Solution 1
  Promise.resolve().then(() => {
    Rails.fire(this.formTarget, 'submit')
  })

  // Solution 2
  setTimeout(() => {
    Rails.fire(this.formTarget, 'submit')
  })  
}

callback(event) {
  // Do the callback dance
}

```

---

<div class="post-metadata">

**Author:** ![asecondwill](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/asecondwill/32/452_2.png) [@asecondwill](https://discuss.hotwired.dev/u/asecondwill)\
**Post date:** [February 21, 2019, 11:54am UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/6 "2019-02-21T11:54:26Z")

</div>

I’ve followd this thread and am using

`Rails.fire(form, 'submit')`

To successfully submit my form. Is there a way to have an onsuccess method with that? I’d like to change some stuff on my page once it finishes, based on which controller action triggered it.

---

<div class="post-metadata">

**Author:** ![kaspermeyer](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/kaspermeyer/32/483_2.png) [@kaspermeyer](https://discuss.hotwired.dev/u/kaspermeyer)\
**Post date:** [February 21, 2019, 2:28pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/7 "2019-02-21T14:28:09Z")

</div>

You can have an action that triggers on ajax success like so:

```auto
<form data-action="ajax:success->controller-name#actionName">

```

A complete list of ajax lifecycle events can be found here: [https://edgeguides.rubyonrails.org/working\_with\_javascript\_in\_rails.html#rails-ujs-event-handlers](https://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#rails-ujs-event-handlers)

---

<div class="post-metadata">

**Author:** ![asecondwill](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/asecondwill/32/452_2.png) [@asecondwill](https://discuss.hotwired.dev/u/asecondwill)\
**Post date:** [February 21, 2019, 2:39pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/8 "2019-02-21T14:39:35Z")

</div>

I want to know when it has finished within the action where I triggered the success, as I want to do more with the part of the form that triggered the submit.

Essentially, I just want it to be synchronus.

---

<div class="post-metadata">

**Author:** ![asecondwill](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/asecondwill/32/452_2.png) [@asecondwill](https://discuss.hotwired.dev/u/asecondwill)\
**Post date:** [February 21, 2019, 3:01pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/9 "2019-02-21T15:01:45Z")

</div>

This might explain what I am struggling with better.

> <https://stackoverflow.com/questions/54810075/wait-for-promise-to-finish>

---

<div class="post-metadata">

**Author:** ![kaspermeyer](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/kaspermeyer/32/483_2.png) [@kaspermeyer](https://discuss.hotwired.dev/u/kaspermeyer)\
**Post date:** [February 24, 2019, 3:39pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/10 "2019-02-24T15:39:30Z")

</div>

Is there any particular reason why you need it all to happen inside one action? It will be synchronous if you use the `ajax:success` event.

I’m not sure what you mean when you say “_I want to do more with the part of the form that triggered the submit_”. You’re submitting the form programmatically with `Rails.fire`, and you should be able to query the form object again in another action, or even better: make it a target.

I looked at the SO post you referred to, and it looks like you want to perform a request after the form is submitted. Is that correct? You should be able to to that inside the action:

```auto
<form data-action="ajax:success->survey#getMoreData"
      data-target="survey.form">

```

```javascript
// survey_controller.js
import { Controller } from "stimulus"

export default class extends Controller {
  static targets = ['form']
  
  submit() {
    Rails.fire(this.formTarget, 'submit')
  }

  getMoreData(event) {
    // The `event` object might have the information you need.
    // The `formTarget` object is available here as well.
    Rails.ajax({type: "GET", url: /* ... */ })
  }
}

```

---

<div class="post-metadata">

**Author:** ![asecondwill](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/asecondwill/32/452_2.png) [@asecondwill](https://discuss.hotwired.dev/u/asecondwill)\
**Post date:** [February 26, 2019, 7:12pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/11 "2019-02-26T19:12:44Z")

</div>

There are multiple parts of the form that can be changed and that triggers the form submit. After the form has submitted, i want to fetch some info on that little part of the form. I won’t know which part of the form was clicked if I just use the ajax:success.

Is it not possible to wait? It seems like this would be simple and I’m just being awful at JS. But judging from responses I’m actually trying to do the impossible?

---

<div class="post-metadata">

**Author:** ![asecondwill](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/asecondwill/32/452_2.png) [@asecondwill](https://discuss.hotwired.dev/u/asecondwill)\
**Post date:** [February 26, 2019, 7:13pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/12 "2019-02-26T19:13:54Z")

</div>

I’d love to be able to get the promise to work and to wait. Partially because having looked into how to do this all friday, it would be great to get it working : )

---

<div class="post-metadata">

**Author:** ![burmashave](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/burmashave/32/577_2.png) [@burmashave](https://discuss.hotwired.dev/u/burmashave)\
**Post date:** [July 15, 2019, 4:40pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/13 "2019-07-15T16:40:17Z")

</div>

> [@kaspermeyer](#):
>
> `<form data-action="ajax:success->controller-name#actionName">`

I’m trying to trigger an action on creation of a model object using this example. From my testing, it appears that ajax:success gets triggered whether or not the object gets created (I see it happening even when validations fail - is that still considered a successful ajax call? If so, what’s the preferred way to have Stimulus perform an action only on successful object creation?)

Thanks in advance!

---

<div class="post-metadata">

**Author:** ![kaspermeyer](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/kaspermeyer/32/483_2.png) [@kaspermeyer](https://discuss.hotwired.dev/u/kaspermeyer)\
**Post date:** [July 15, 2019, 10:12pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/14 "2019-07-15T22:12:20Z")

</div>

The `ajax:success` event is triggered when your Rails controller action (or any other endpoint) responds with a HTTP status code in the 2xx range. It’s not concerned with object creation.

Can you tell a bit more about how your solution is implemented? Do you use a server-side rendered response to create the modal or is it all client side?

---

<div class="post-metadata">

**Author:** ![burmashave](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/burmashave/32/577_2.png) [@burmashave](https://discuss.hotwired.dev/u/burmashave)\
**Post date:** [July 16, 2019, 12:16am UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/15 "2019-07-16T00:16:20Z")

</div>

I see what you’re saying. I was confusing the success of object creation with `ajax:success`. Whether the model saves or not is immaterial - it returns 200 status either way, and so it’s always `ajax:success`.

What I’m trying to do is trigger a Stimulus action once an object is created. The controller action:

```auto
 def create
    @comment = @commentable.comments.new(comment_params)
    @comment.user = current_user
    respond_to do |format|
      if @comment.save
        format.html { redirect_to @commentable }
        format.js
      else
        format.html { redirect_to @commentable, flash: { error: 'Problem saving comment.' } }
        format.js { flash.now[:error] = @comment.errors.full_messages }
      end
    end
  end

```

I had (mistakenly) believed that `ajax:success` might be the event I needed to listen for, but now see that’s entirely independent of object creation. So I’m assuming I’ve got to use the rendering of `create.js.erb` to do that, but not quite sure how? Currently I’m checking for errors and calling `alert` in that file in case of validation errors:

```auto
<% if @comment.errors.any? %>
alert("<%= j flash[:error].join('; ') %>")
<% else %>
.... (main code)

```

Just not sure how to trigger an action when it’s not directly attached to a click event or something similar. Or is there some other success event I’m overlooking?

---

<div class="post-metadata">

**Author:** ![kaspermeyer](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/kaspermeyer/32/483_2.png) [@kaspermeyer](https://discuss.hotwired.dev/u/kaspermeyer)\
**Post date:** [July 18, 2019, 12:00pm UTC](https://discuss.hotwired.dev/t/stimulus-and-rails-ujs/587/16 "2019-07-18T12:00:01Z")

</div>

Are you creating your modal element inside the Stimulus controller action that listens to the `ajax:success` event?

If so, you can render a status outside the 2xx range from your Rails controller to ensure the `ajax:success` event never fires when a comment didn’t save.

```ruby
format.js do
  flash.now[:error] = @comment.errors.full_messages
  render status: :unprocessable_entity
end

```
