Stimulus: getting the html button that was clicked

I have two buttons, Expense and Income in a form. If the user clicks Expense, I want to set in a hidden fld the value to “Expense”

So I have tried various ways of getting this to work. no luck. What am I doing wrong?

code:
from entryline_controller.js:
import ApplicationController from ‘./application_controller’

export default class extends ApplicationController {
static targets= [ “expense”, “income”, “itemType”]
clicktype(event){
event.preventDefault()
console.log(‘got clicktype’)
console.log(this.btnValue)
if (this.expenseTarget == “Expense”){
console.log(“Expense”)
this.itemTypeTarget.value = “Expense”}
else{
console.log(“Income”)
this.itemTypeTarget.value = “Income”
}
var priorValue = this.itemTypeTarget.value
console.log(priorValue)
}

connect () {
super.connect()
// add your code here, if applicable
this.element[this.identifier] = this
}
}

and from my show.html.erb:

<%= form.hidden_field :cashflow_id, value:@cashflow.id %>
<%= form.hidden_field :item_type, value:“Expense”, data:{
“entryline-target”:“itemType”
} %>
<%= form.hidden_field “user_id”, value: current_user.id %>
Expenses
Income

Calling super.connect()?

My understanding is that this is not necessary given we are extending ApplicationController - the controller will connect automatically. Please also confirm that the controller is in fact connecting?

Event Handler

Have you added the click event handler in the form?

<%= form.hidden_field :cashflow_id, value:@cashflow.id %>
<%= form.hidden_field :item_type, value:“Expense”, data:{
“entryline-target”:“itemType”, “action”:"click->entryliner#clicktype"
} %>
<%= form.hidden_field “user_id”, value: current_user.id %>

Side note: WARNING - Users might tamper with the data

If you’re doing all of this on the front end, then users will be able to tamper the data, and change something which should be an expense, into something that is not.

I don’t entirely follow your code, but this would be my take:

// entryline_controller.js
export default class extends ApplicationController {
  static targets = ["typeField"]

  clicktype(event) {
    event.preventDefault()
    this.typeFieldTarget.value = event.target.textContent
  }
}

// show.html.erb
<div data-controller="entryline">
  <%= form.button "Expense", data: { action: "entryline#clicktype" } %>
  <%= form.button "Income", data: { action: "entryline#clicktype" } %>
  <%= form.hidden_field :item_type, value: “Expense”, data: { entryline_target: “typeField” } %>
</div>

The key thing here is event.target , which gives you the button you clicked that resulted in the clicktype call.

One thought came to mind: presumably there’s a reason you can’t use a checkbox?

1 Like

this needs the event associated with a particular action?

 action: "**event_to_add**->entryline#clicktype"

Nah, Stimulus handles that for you for button clicks: Stimulus Reference: Actions

1 Like

the key for me was event.target.textContent that gave me a value I could conditionally act on.

where do I find a list of other things I can get from target?

It’s just a HTMLElement, so you can call anything you want, really.

An alternate solution would be to use the HTML attributes of formaction and formmethod.

For example, I have a “Create” button that submits using the main form tag. I then have a “Save” button n next to it that submits the form elements to a custom route and HTTP method:

<%= f.button "Save",
        formmethod: :post,
        formaction: account_saved_shipments_path(current_account), 
        class: tw_button, data: { disable_with: tw_spinner } %>

This approach will keep your Rails controller code cleaner as well.

1 Like