Rainmaker has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm using a tool SAJAX. http://www.modernmethod.com/sajax/

The perl function i'm calling takes the data from the database and stores it in an array and returns it to javascript. I dont know how to copy a perl array in a javascript array.

Actually what i need to do is this:- I've 2 drop down box, and the options in the second drop-down box depends on the choice made in the first drop down box. So as the user selects an option from the first drop-down box, i call the perl function using SAJAX and it retrieves the records from the database based on this selection. I stores these values in a perl array. Now i need to return these values to the javascript function, which will populate the second drop down box. But i dont knw how to return this array back to the javascript which will populate the drop down box.

Can you help me with this?

Thanks,

Gaurav

Replies are listed 'Best First'.
Re: copying perl array to javascript array
by ikegami (Patriarch) on Aug 01, 2005 at 22:44 UTC

    You have to convert the array to a string in Perl, then back to an array in JScript. A while ago, I wrote a serializer I can adapt to this situation. Here it is:

    In Perl, change

    sub populate { my @array = (...); return @array; }

    to

    # Serializes an array, a hash or a list which contains only # strings and undefs. Everything else will be stringified. sub serialize_string_list { return join('|', map { (defined($_) ? do { local $_=$_; s/\^/^1/g; s/\|/^2/g; $_ } : '^0' ) } @_ ); } sub populate { my @array = (...); return serialize_string_list @array; }

    In the emitted JavaScript, change

    function do_populate_cb(s) { ... do something with s... }

    to

    // Deserializes a list serialized with serialize_string_list. function deserialize_string_list(s) { var fields = s.split("|") var i; for (i=0; i<fields.length; i++) { if (fields[i] == "^0") { fields[i] = null; } else { var re; re = /\^2/g; fields[i] = fields[i].replace(re, "|"); re = /\^1/g; fields[i] = fields[i].replace(re, "^"); } } return fields; } function do_populate_cb(s) { var array = deserialize_string_list(s); var i; for (i=0; i<array.length; i++) { ... do something with array[i]... } }

    Important: The above only supports lists (and arrays) of strings. Lists of numbers will work, but they will be converted to arrays of strings. List containing references of any sort will not work as expected.

    Background: I didn't use a single-character escape mechanism (such as preceeding metacharacters with a slash) since it makes deserialization hard. (i.e. "Should I split on this pipe, or is that an escaped pipe?") The escape mechanism I used -- replacing the seperator character with another character -- avoids that problem, simplifying parsing. IP over Serial Line (SLIP) and maybe Point to Point Protocol (PPP) use a similar escaping algorithm to escape packet delimiters because the delimiters cannot appear inside a packet.

      Greetings ikegami
      I tried using your code. Its works fine except for the fact that the last array value is followed by the whole html code in the form.
      For eg:- If the array values are A,B,C,D and i add them in the drop down menu then the last option(D) is followed by the whole html code. So I have four options in the drop down box A,B,C,D<htmlcode>
      Am i doing something wrong?
      See code below.
      sub serialize_string_list { return join('|', map { (defined($_) ? do { local $_=$_; s/\^/^1/g; s/\|/^2/g; $_ } : '^0' ) } @_ ); } sub populate{ @n=(); my $dt; my $row; #course contains the values fetched from the database foreach $row (@$course) { ($dt) = @$row; push(@n,$dt); } return serialize_string_list @n; }; //deserializes the array function deserialize_string_list(s) { var fields = s.split("|") var i; for (i=0; i<fields.length; i++) { if (fields[i] == "^0") { fields[i] = null; } else { var re; re = /\^2/g; fields[i] = fields[i].replace(re, "|"); re = /\^1/g; fields[i] = fields[i].replace(re, "^"); } } return fields; } //calling Sajax wrapper function from a javascript function function do_populate() { x_populate(do_populate_cb); } function do_populate_cb(s) { var arr = deserialize_string_list(s); var i; for (i=0; i<arr.length; i++) { with(document.doc1.selCourseNm) { options[i]=new Option(arr[i],arr[i]); } } }

        Did you forget to close your SELECT tag?

        How about you show us runnable code that exhibits the problem.

        By the way. I can't find any documentation for Option's contructor. In fact, according to the documentation, nodes should be created using createElement and createTextNode methods. What follows uses the correct methods.

        function do_populate_cb(s) { var arr = deserialize_string_list(s); var options = document.doc1.selCourseNm.options; var i; // Remove any options it currently has. options.length = 0; // Add new options. for (i=0; i<arr.length; i++) { var option = document.createElement('OPTION'); option.value = arr[i]; option.innerText = arr[i]; options.add(option); } }
Re: copying perl array to javascript array
by gryphon (Abbot) on Aug 02, 2005 at 01:08 UTC

    Greetings Rainmaker,

    I don't have any experience with SAJAX, but I've had significant (and quick and easy) success with JSON. There's a CPAN module for it, and it's crazy-simple/easy.

    use JSON; print "Content-Type: text/html\n\n", objToJson('list' => [ 'a', 'b' ]) +;

    Obviously, this is very simple, but complex structures are a piece of cake.

    gryphon
    Whitepages.com Development Manager (DSMS)
    code('Perl') || die;

Re: copying perl array to javascript array
by Joost (Canon) on Aug 01, 2005 at 21:07 UTC
Re: copying perl array to javascript array
by Anonymous Monk on Aug 02, 2005 at 06:46 UTC
      Data::Javascript

      That's good, but I prefer the output of Data::JavaScript::Anon, which uses JavaScript's array construction syntax and avoids messily repeating the variable name for every element.

      Smylers

Re: copying perl array to javascript array
by chanio (Priest) on Aug 02, 2005 at 06:33 UTC
Re: copying perl array to javascript array
by GoCool (Scribe) on Aug 04, 2005 at 05:08 UTC
    I was wondering why none of the replies to this thread had suggested the use of XML. Is there any particular reason behind that? since the first thing that comes to my mind when talking about AJAX or I imagine SAJAX is Asynchronous communications to client side Javascript through XML which is what these acronyms stand for, right?

    -GoCool

      Greetings GoCool,

      Just my own personal opinion (and it seems to work out well for me in my particular situation) is: Why translate a data structure from Perl to XML and then from XML to JavaScript data object if all you're ever going to do with AJAX is talk between Perl and JavaScript? Seems faster, simpler, and easier to just go direct from Perl to JavaScript, which is why I like JSON so much.

      I'm not against XML, but I am against having to use XML when there's really no reason to do so. If I were going to de-link my data provider (Perl CGI/mod_perl) from my GUI (JavaScript) so that some developer who's not me could build a hook into the data source and build their own GUI, then XML would make a lot of sense. However, if I don't really care about exposing my data source, then I don't want to waste the time with XML.

      Just my opinion. There's more than one way to do it.

      gryphon
      Whitepages.com Development Manager (DSMS)
      code('Perl') || die;