dynamische Select-Menüs mit JavaScript 0

Posted by fwoeck
on Tuesday, November 04

Wenn man Ajax umgehen möchte, um die Auswahl eines bestimmten Select-Feldes von der Auswahl eines anderen abhängig zu machen, kann man diese Funktion auch mit JavaScript allein auf der Clientseite regeln.

Ein javascript-Controller

Wir legen einen Controller javascript an. Der Trick an der Sache besteht darin, dass wenn der Client später eine URL /javascript/...js aufruft und eine entsprechende Route gesetzt ist, der neue Controller aufgerufen wird und dynamisch ein js-File erzeugen kann.

Hier befüllt der Controller das @jobs-Array, das später mit dem js-Skript auf die einzelnen Customer-Bereiche aufgeteilt wird:

class JavascriptsController < ApplicationController
  def dynamic_jobs
    @jobs = Job.all_cached
  end
end

Die Route dorthin

müsste dann so lauten:

map.connect ':controller/:action.:format'

Der View-Abschnitt

In diesem Falle sollen innerhalb eines Formulars für das Project-Modell die möglichen Jobs von der Auswahl des Customers abhängen:

<% javascript 'dynamic_jobs' %>
...
<% form_for @project do |f| %>
  ...
<p>
  Kunde<br />
  <%= f.collection_select :customer_id, Customer.all_cached, :id, :name, :prompt => "" %>
</p>

<p id="job_field">
  Job<br />
  <%= f.collection_select :job_id, Job.all_cached, :id, :name, :prompt => "" %>
</p>

Das File dynamic_jobs.js.erb

befindet sich im views/javascripts-Ordner. Es erzeugt das js-File mit den Kunden und Jobs. Die Funktion customerSelect teilt die Daten des Arrays in Kunden ein.

var jobs = new Array();
<% for job in @jobs -%>
  jobs.push(new Array(<%= job.customer_id %>, '<%=h job.name %>', <%= job.id %>));
<% end -%>

function customerSelected() {
  customer_id = $('project_customer_id').getValue();
  options = $('project_job_id').options;
  options.length = 1;
  jobs.each(function(job) {
    if (job[0] == customer_id) {
      options[options.length] = new Option(job[1], job[2]);
    }
  });
  if (options.length == 1) {
    $('job_field').hide();
  } else {
    $('job_field').show();
  }
}

document.observe('dom:loaded', function() {
  customerSelected();
  $('project_customer_id').observe('change', customerSelected);
});

und schließlich

benötigen wir noch einen Helper, der das dynamisch erzeugt js-File in das Rendering einbaut – z.B. in der application_helper.rb:

def javascript(*args)
  args = args.map { |arg| arg == :defaults ? arg : arg.to_s }
  content_for(:head) { javascript_include_tag(*args) }
end

Ausgeblendete Formularfelder löschen 0

Posted by fwoeck
on Friday, October 24

Das Umschalten von Sichbarkeiten im View mit toggle() geht schnell, aber nur weil ein div-Element unsichtbar ist, bedeutet dies nicht, dass sein Inhalt beim Formularversand nicht mitgeschickt würde.

Damit der Controller eindeutig wissen kann, welches Feld gewählt wurde, muss man das jeweils ausgeblendete Feld nullen:

<div id="personselect"> 
  <p >
    Person<br />
    <%= select_tag 'project[person_id]', options_for_select([["",""]] + 
             Person.all.map {|w| [w.gname + " " + w.sname, w.id]}), :id => 'personid' %>
  </p>
  <p>
    <%= link_to_function "Person neu anlegen", "$('personselect').toggle(); 
             $('personcreate').toggle(); $('personid').clear();" %>
  </p>
</div>

<div id="personcreate" style="display: none"> 
  <p >
    Vorname Nachname<br />
    <%= text_field_tag 'gname', {}, :size => 10, :id => 'gnameid' %> 
    <%= text_field_tag 'sname', {}, :size => 20, :id => 'snameid' %>
  </p>
  <p>
    <%= link_to_function "Person wählen", "$('personcreate').toggle(); 
             $('personselect').toggle(); $('gnameid').clear(); $('snameid').clear();" %>
  </p>
</div>