Search code examples
javascriptarraysperlmojolicious

mojolicious assign an array to a javascript variable


I have an array reference ($sections) in the stash. I'm trying to dereference this and assign it to a javascript array but nothing that i try works.

for example

%= javascript begin
    var list = <%== $sections %>;
    etc...
% end

leads to list equaling ARRAY0x23456 (which is correct since $sections is a ref)

%= javascript begin
    var list = <%== @$sections %>;
    etc...
% end

Assigns the array length to list (which is correct since list is treated as a scalar assignment).

%= javascript begin
    var list = <%== $sections %>.slice();
    etc...
% end

gives an error because $sections is a ref

%= javascript begin
    var list = <%== @$sections %>.slice();
    etc...
% end

Arguably is the most likely candidate but resolves to [array.length].slice() (e.g. 3.slice()), and fails.

How can I do this?

EDIT; I've managed to do this by forming a string with the array values in it within the stash and then creating the array I want from this.

e.g. stash contains the string 5,6,7,8 in $string within the javascript i can then do

array = [ <%= $string %> ];

I'd still be interested to know if there is a way to do this using the arrayref in the stash.


Solution

  • The fragment:

    <%== @$sections %>
    

    is equivalent to:

    print scalar @$sections;
    

    ...so that is why you are getting the array length: an array in scalar context is the length of the array.

    To get a javascript array, you have to replace <...> below with something that will cause the output to look like a js array:

    print scalar <....>;
    

    You can do something like this:

    use Mojolicious::Lite;
    
    get '/test' => sub {
        my $c = shift;
        $c->stash(sections => [1, 2, 3]);
    
        {
            local $" = ", ";  #The value that gets inserted between array elements 
                              #when an array is interpolated into a string. The default
                              #value is a space.
            $c->render('template1');
        } 
        # $" gets reset to its previous value here
    };
    
    app->start;
    
    __DATA__
    
    @@ template1.html.ep
    %= javascript begin
      var arr =  <%== "[@$sections]" %>;
      console.log(arr[0]);
    % end
    
    Examine your browser's javascript console....