NetManiac

Witold Rugowski on web20 wave with Ruby on Rails

Don’t use array as argument for AJAX call with Prototype

Posted on March 31, 2008 - Filed Under AJAX, JavaScript, RubyOnRails

I’m using Prototype JavaScript library and today I have learned one thing. To make Your life easier do not use JavaScript Arrays as arguments for AJAX calls.

I’m talking about parameters option in Ajax objects (Ajax.Request, Ajax.Updater, etc). Let’s take simple HTML snippet (public/test.html):

<div id="out"></div>
<script src="/javascripts/prototype.js" type="text/javascript"></script>
<script type="text/javascript">
    addr = []
    addr[1] = 2
    new Ajax.Updater ("out", "/controllers/test", {parameters: addr })
</script>

Now simple Controller controller :)

class ControllersController < ApplicationController
  def test
    render :layout => false
  end
end

And test.html.erb:

<%= debug params %>

Simple, isn’t it? What do You expect to be displayed when You point Your browser to /test? Something like:

--- !map:HashWithIndifferentAccess
action: test
"1": "2"
controller: controllers

Wrong!

Real output is like:

--- !map:HashWithIndifferentAccess
uniq: |-
  function (sorted) {
      return this.inject([], function (array, value, index) {if (0 == index || (sorted ? array.last() != value : !array.include(value))) {array.push(value);}return array;});
  }
without: |-
  function () {
      var values = $A(arguments);
      return this.select(function (value) {return !values.include(value);});
  }
size: |-
  function () {
      return this.length;
  }
zip: |-
  function () {
      var iterator = Prototype.K, args = $A(arguments);
      if (Object.isFunction(args.last())) {
          iterator = args.pop();
      }
      var collections = [this].concat(args).map($A);
      return this.map(function (value, index) {return iterator(collections.pluck(index));});
  }
toArray: |-
  function () {
      return [].concat(this);
  }
findAll: |-
  function (iterator, context) {
      iterator = iterator.bind(context);
      var results = [];
      this.each(function (value, index) {if (iterator(value, index)) {results.push(value);}});
      return results;
  }

[CUT]

What is going on?

It seems that it is some bug with serialization of Arrays. Prototype does iterate through all properties, and dumps them not matter if it property is function or not (maybe Prototype has own reasons for that behavior). So how to get output like in the first dump? Use Hash, Luke:

//    addr = []
    addr = {}

Does work as expected.

Popularity: 9% [?]

Hits for this post: 7189

Similar Posts

Comments

3 Responses to “Don’t use array as argument for AJAX call with Prototype”

  1. Nabble - RubyOnRails Fans - passing an array of javascript objects to server? on May 14th, 2008 11:44

    Kramer auto Pingback[...] passing, if I use an array of objects, it’s a mess of function definitions, (same as noted here: http://nhw.pl/wp/2008/03/31/dont-use-array-as-argument-for-ajax-call-with-prototype/), if I use a hash, I pass something like " "1"=>"[object Object]", [...]

  2. Patryk Januszewski on March 29th, 2009 22:26

    I’ve had a few issues with this solutions. When I tried your suggestion and declared the array as:

    var something = {};

    It came through as [object Object]. I found that the complete solution was the following:

    var something = [];
    something[0] = “bimmer”;
    something[1] = “empire”;
    Ajax.Request(‘process.php’, { method:’post’, parameters: { ‘something[]‘:something } });

    This actually results in PHP having an associative array with proper structure/etc.

    Sorry if this isn’t completely related to your example above. I was simply trying to pass a js array through Prototype’s Ajax.Request()|Updater()

  3. anu on June 24th, 2009 7:05

    Thank you. It helped me really…

Leave a Reply