2

I am trying to implement dynamic select on the in the following code. I have product and product has many batch nos. as soon as i select Product associated Batch no should be displayed. Form details are as follows.

<div class ="prod"><%= f.association :product, :collection => Product.in_stock %> </div><br/>

<div class ="batch"><%= f.grouped_collection_select :batch_no, Product.in_stock, :store_opening_stocks, :title, :batch_no, :batch_no, :prompt => "Select Batch"%></div>

and jquery for the form is as follows

jQuery(document).ready(function(){
  var child = jQuery('.batch').html();
  jQuery('.prod').change(function() {
   var parent = jQuery('.prod :selected').text();
   var escaped_parent = parent.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1')  
    var options = jQuery(child).filter("optgroup[label='#{escaped_parent}']").html()
     if (options) {
      jQuery('.batch').html(options);
      return jQuery('.batch').parent().show();
    } else {
      jQuery('.batch').empty();
    }
   });
}); 
 

Now the problem is options is returning null. this i found out when i did alert(options) it is showing null. Can anyone please poitn me to right direction?? is there any other way i can achieve my task. Thanks in advance :)

2
  • It looks like someone is trying to translate some CoffeeScript from a Railscast into jQuery :) Commented Jun 29, 2012 at 22:32
  • @ScottJShea- Yeah true :) i have mentioned it in the comment of the answer :) Commented Jun 30, 2012 at 3:54

4 Answers 4

5
+50
jQuery(document).ready(function(){
  var child = jQuery('.batch').html();
  jQuery('.prod').change(function() {
   var parent = jQuery('.prod :selected').text();
   /* var escaped_parent = parent.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1') */  
    var options = jQuery(child).filter("optgroup[label='" + parent + "']").html()
     if (options) {
      jQuery('.batch').html(options);
      return jQuery('.batch').parent().show();
    } else {
      jQuery('.batch').empty();
    }
   });
}); 

does this do any magic for you?

It might be cleaner to do a ajax call to your controller and return the set of options, then fill the batch with the options returned.

Something like

var data = {
  product_id: jQuery('.prod :selected').attr("data-id")           
}
jQuery.ajax({
  url: controller/get_batch,
  type: 'GET',
  dataType: 'script',
  data: data
});

with a get_batch.js where you put

jQuery('.batch').html(<%= escape_javascript(render :partial => "select_box_for_batch") %>);

Code is not complete, you still need to add an ID to the product select and stuff, but I think you'll get the idea.

edit: I made a repository with a simple example

Sign up to request clarification or add additional context in comments.

3 Comments

Yeah i get the idea..was just trying to implement a Railcast by Ryan bates. so Ajax is the best way to do it???
Well if you dont want visible page reloads every time you change the select box ajax is the way to go, loading the complete list and filtering the options by jquery is a bit heavy on the client side.. plus it will take LOADS of data if the amount op options grow. By using a ajax call you only load the amount of options you are going to actually use. For instance: 100 products with 20 options each is a select box with 2000 options where 1980 are discarded, where an ajax call just has 20 each time you change. In my opinion: only load what you use!
@Vikko- I am Really Sorry mate i couldn't do as u directed me. can you please post the rest of code.? Extremely Sorry i am asking you this Late. Any other Data you want me to post related to this. please let me knw. again Deeply Sorry i am asking this favour. I am totally new to coding. tried to understand and do things. couldnt do it. :( :(
1

after some effort this is working for me....but any other answers better than this is welcome. since i dunno much about ajax calls and how to connect it to controller and stuff... i modified with jquery only.

Here is the code.

        jQuery(document).ready(function(){
      var batchNo = jQuery('.batch').html();
      jQuery('.prod').bind('change',function() {
      var  productSelected = jQuery('.prod :selected').val();
    var options = jQuery(batchNo).find("optgroup[label='" + productSelected + "']").html();
   ;  if (options) {
      jQuery('.batch select').html(options);
      return jQuery('.batch').parent().show();
    } else {
      jQuery('.batch').empty();
    }
    });
 });

4 Comments

Could you share the complete code somewhere online so I can review it? I don't have a lot of time lately, but I might give you a pointer here and there :)
pastebin.com/JcRzJz5p hey Buddy this is the code...:) i am working on..what u said i understood theoritically... :) but couldnt do it..cause i m not only new to ruby..i m new to coding itself...Learning everythin frm sample codes...:/
See the link in my first post of an example that uses 2 selectboxes where the first selectbox' value fills the data of the 2nd through ajax.
@vikko- million Thanks.. :) _/\_ u saved me a lot of time and learnt alot from this method...Thanks A lot again.. :) + 50 for the answer.. :) and i guess instead of url: "products_test/get_batch" oly "get_batch shld be the code" But understand the code and implementation Perfectly.. :) Thanks again... :)
1

Looks like you're getting tripped up by using the class selectors on your containing div tags.

Specifically, the goal of var child is to return an array of option tags. Ideally, you should use the ID attribute the form builder assigns to each element. Not knowing how you opened your form (ie. not knowing the parent model), let's assume your open statement looks something like:

<%= form_for @product_batch do |f| %>

This will make your product and batch_no select fields look something like:

<select name="product_batch[product_id]" id="product_batch_product_id">
<select name="product_batch[batch_no]" id="product_batch_batch_no">

Now, we can refactor your jQuery as follows:

jQuery(function() {
  var child = $('#product_batch_batch_no').html();
  $('#product_batch_product_id').live("change", function() {
    var escaped_parent, parent, options;
    parent = $('#product_batch_product_id :selected').text();
    escaped_parent = parent.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1');
    options = $(child).filter("optgroup[label='" + escaped_parent + "']").html();
    $('#product_batch_batch_no').html(options);
  });
});

The last bit of the your code:

if (options) {
  jQuery('.batch').html(options);
  return jQuery('.batch').parent().show();
} else {
  jQuery('.batch').empty();
}

is literally destructive. When a product does not have a batch_nojQuery('.batch').empty(); removes the html inside:

<div class="batch"></div>

Once removed, this code is gone...which is probably not what you want.

Anyway, I agree with Ryan Bates' opinion that this is a great, unobtrusive way to implement dynamic select boxes. You may want to checkout the revised RailsCast at http://railscasts.com/episodes/88-dynamic-select-menus-revised

Best of luck!

1 Comment

Thanks...yeah i did this with help of revised rails cast...was getting stuck... and in code i think its escaped_parent rite?? instead of escaped_stat?? :)
0

I like Vikko's method of using an Ajax call to only load what is needed, especially as the database grows.

But for the specific code in the question, this worked for me: (in coffee script). Note the key difference being the line assigning the options variable

jQuery ->
  child = $('.batch').html()
  $('.prod').change ->
    parent = $('.prod :selected').text()
    options = $(child).filter((index) ->
      $(this).attr("label") is parent)

    if options
        $('.batch').html(options)
        $(".batch").parent().show()
    else
    $(".batch").empty()
    return

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.