We've moved discussions to Discord

Pointers on a Stimulus conditional select

Dan Tappin
I have a model where you select two related model attributes.  Once you select these two I want the third select to be active and the select values from a DB query based on the id's chosen in the first two selects.

Anyone seen a good screencast etc. on anything close to this?
Brandon B.
--Following--
Dan Tappin
I am walking through this (https://stimulusjs.org/handbook/hello-stimulus) and I am seeing how powerful Stimulus is.  I have a basic controller built and can tigger events (basic alerts etc.) to test drive this.

Intermediate questions for the experts:

  • Can you add nested folders to organize your controllers? I can see this getting messy.
  • Can you use CoffeScript and JQuery here also?  Plain JS just seem so clunky after using them.

I see where this is going what I don't get is how I pull the query from the DB and update the target select. I know there are the Rails reponds_to JS controllers that do similar results like  Chris Oliver   does here https://gorails.com/episodes/nested-comment-threads-in-rails-part-3?autoplay=1.

I just don't get yet how you combine Stimulus with the Rails Active Record calls etc.
Brandon B.
So,  Dan Tappin - when are we going to build an app together?  I see us plastering these message boards with questions and answering each others questions.  I figure lets cut through the crap and get some of these ideas that we have implemented, haha.
Dan Tappin
Brandon B.  🤣😉👍
Dan Tappin
Soooooooooo close.  It works except that my dynamic select populates twice like this:

  • item 1
  • item 2
  • item 3
  • item 1
  • item 2
  • item 3

Can anyone see what I am missing?  The whole controller is not being run twice because the existing contents are wiped clean on the first line.  It's in that 'request.onload' function that seems to be looping twice somehow.

I have a custom controller action that does the JSON via jbuilder:

related.json.jbuilder

json.array!(@related) do |exp|
  json.extract! exp, :id
  json.extract! exp, :related_select_label
end

custom related controller action

  def related
    
    if params[:vendor_id].nil? && params[:budget_id].nil?
      @related = [ { } ]
    else
      @related = Expenditure.includes(:budget, :vendor, :project).where(flag_active: true).where( vendor_id: params[:vendor_id], budget_id: params[:budget_id] )
    end
    
    respond_to do |format|
      format.json  #{ render :json => @related.to_json }
    end
  end

I added some logic to confirm the input has values

_form.html.erb

<div data-controller="expenditure">
<%= form_with(model: expenditure) do |form| %>
  <div class="form-group">
    <%= form.label :category %>
    <%= select(:expenditure,
               :category,
               [ [ "Purchase Order" , :purchase_order ],[ "Work Order", :work_order], [ "Invoice", :invoice ], ["Accrual", :accrual ], ["Field Ticket", :ticket ] ],
               {class: "form-control"} , { data: { target: "expenditure.category", action: "change->expenditure#update_related"} } )  %>
  </div>

  <div class="form-group">
    <%= form.label :budget_id %>
    <%= collection_select(:expenditure, :budget_id, @budgets, :id, :select_label_client, {include_blank: 'Select a budget...'}, {class: "form-control", data: { target: "expenditure.budget" ,action: "change->expenditure#update_related"} } )  %>
  </div>

  <div class="form-group">
    <%= form.label :vendor_id %>
    <%= collection_select(:expenditure, :vendor_id, @vendors, :id, :name, {include_blank: 'Select a vendor...'}, {class: "form-control", data: { target: "expenditure.vendor" ,action: "change->expenditure#update_related"} } )  %>
  </div>

  <div class="form-group">
    <%= form.label :parent_id %>
    <%= collection_select(:expenditure, :parent_id, @related, :id, :related_select_label, {include_blank: 'Select a parent expenditure...'}, {class: "form-control", data: { target: "expenditure.related"} } )  %>
  </div>

</div>
 
now the magic!... HT to https://www.codebyamir.com/blog/populate-a-select-dropdown-list-with-json

expenditure_controller.js

import { Controller } from "stimulus"

export default class extends Controller {
  
  static targets = [ "category", "budget", "vendor", "related" ]
  
  update_related() {

    let dropdown = this.relatedTarget;
    dropdown.length = 0;

    let defaultOption = document.createElement('option');
    defaultOption.text = 'Select parent expenditure...';

    dropdown.add(defaultOption);
    dropdown.selectedIndex = 0;

    const url = '/related_expenditures.json?vendor_id=' + this.vendorTarget.value + '&budget_id=' + this.budgetTarget.value;

    const request = new XMLHttpRequest();
    request.open('GET', url, true);
 
    request.onload = function() {
      if (request.status === 200) {
        const data = JSON.parse(request.responseText);
        let option;
        for (let i = 0; i < data.length; i++) {
          option = document.createElement('option');
          option.value = data[i].id;
          option.text = data[i].related_select_label;
          dropdown.add(option);
        }
       } else {
        // Reached the server, but it returned an error
      }   
    }
 
    request.onerror = function() {
      console.error('An error occurred fetching the JSON from ' + url);
    };
 
    request.send();

 }  

}
Murray Bryant
Don't have time to replicate your whole code, but I am doing something similar with json and using this

   Rails.ajax({
            url: "/notifications.json",
            type: "get",
            data: "",
            success: function(data) {}
            error:function() {})


And it is working well, maybe this way could help with the double unload event
Notifications
You’re not receiving notifications from this thread.