Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

[OT?] formatting response text for AJAX widget

by geektron (Curate)
on Aug 04, 2006 at 19:05 UTC ( [id://565721] : perlquestion . print w/replies, xml ) Need Help??

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

I'm working with a small AJAX-ish application chunk, and for the life of me I can't get the request.responseText to end up working properly. I'm sure the root of the problem is the text that I'm sending back (via a mod_perl handler), so I'm asking here.

The AJAX portion takes a name out of a text field, sends it to a mod_perl handler, and sends back the 'original' javascript to rebuild the same link (the new name) with an onClick handler associated with it. the code, before being clicked and turned into the AJAX widget, looks like this:

<span id='override_123'> <a href='#' onClick='javascript:makeForm( "123", "linktype" "titleVal +ue");'>titleValue</a> </span>
When the link is clicked, the span's innerHTML is changed to a text box and a button with the associated onClick handler added to the button. The AJAX portion works; the database is updated with the new value, and I try to recreate the above code using the values passed to the handler.

I can't seen to get the quoting right, and I've been fighting with it for hours now. What I'm currently sending back to the AJAX request is:

$response = "\$('override_$componentId').innerHTML=\"<a href='#' onCl +ick='javascript:makeForm( \"$componentId\", \"$componentType\", \"$ne +wTitle\");'>$newTitle</a>';";
Which, when evaluated on the client side
eval( request.responseText );
throws a syntax error: Syntax Error: missing semicolon before statement.

(I'm using the Prototype libraries to handle the AJAX abstraction.)

Replies are listed 'Best First'.
Re: formatting response text for AJAX widget
by ikegami (Patriarch) on Aug 04, 2006 at 19:17 UTC

    The JavaScript code you are sending (as seen by using print $response) is:

    $('override_...').innerHTML="<a href='#' onClick='javascript:makeForm( +"...", "...", "...");'>...</a>';

    but it should be

    $('override_...').innerHTML="<a href='#' onClick='javascript:makeForm( +\"...\", \"...\", \"...\");'>...</a>";

    The first double-quote is wrongly closed with a single quote, and you have unescaped double-quotes.

    Other potential problems:

    • Is $('override_123') valid JavaScript? I've never seen that syntax before, but I have little JavaScript experience.
    • Are $componentId, $componentType and $newTitle properly escaped to be used in a JavaScript double-quoted string? (\ => \\, " => \")
    • Are $componentId, $componentType and $newTitle properly escaped to be used in an HTML single-quoted value? (& => &amp;, ' => &#39;)
    • Is $newTitle properly escaped to be used in HTML? (& => &amp;, < => &lt;)

    Update: The following addresses quoting issues:

    use strict; use warnings; use HTML::Entities qw( encode_entities ); sub js_from_text { for (@_ ? $_[0] : $_) { s/([\\"])/\\$1/g; return qq{"$_"}; } } sub html_from_text { for (@_ ? $_[0] : $_) { return encode_entities($_); } } my ($text_componentId, $text_componentType, $text_newTitle) = ...; my $js_component = js_from_text("override_$text_componentId"); my $js_componentId = js_from_text($text_componentId); my $js_componentType = js_from_text($text_componentType); my $js_newTitle = js_from_text($text_newTitle); my $js_onClick = "makeForm($js_componentId, $js_componentType, $ +js_newTitle);"; my $html_onClick = html_from_text($js_onClick); my $html_newTitle = html_from_text($text_newTitle); my $html = qq{<a href="#" onClick="javascript:$html_onClic +k">$html_newTitle</a>}; my $js_html = js_from_text($html); my $js_response = "\$($js_component).innerHTML = $js_html;"; print("$js_response\n");

    There is a situation where hungarian notation is very useful. Making Wrong Code Look Wrong is a worthwhile read.

      The $('someId') is syntactic sugar provided by the Prototype library to fetch the DOM object for the element with that tag. If passed anything rather than a string it returns that object. More info here on the wiki.

      I did just catch the first issue -- the improperly closed double quote. I switched the 'main' quoting back to  qq{} to ease up on the toothpick syndrome. Fixing that ... didn't help.

      the values i've been using for the three vars don't need escapes. i can tackle that issue once i have a working repsonseText replacer. they've been simple strings.

      $('overide_123').innerHTML is valid javascript. the same handler uses it for another (working) part of the application.

        Is it still the same error?
      I already had some initial entity encoding, but .... it seems the
      entity still interferes with the javascript quoting ....
Re: [OT?] formatting response text for AJAX widget
by jfluhmann (Scribe) on Aug 04, 2006 at 19:35 UTC
    What about trying a different approach using JSON:
    print qq{ {"componentId": "$componentId", "html": "<a href='#' onClick='javascript:makeForm( \"$componentId\", +\"$componentType\", \"$newTitle\");'>$newTitle</a>"} };
    Inside your JavaScript, use:
    jsonText = eval( '(' request.responseText ')' ); $('override_' + jsonText.componentId).innerHTML = jsonText.html;
      I haven't read up enough on JSON to use it, so for now, the nasty extra escapes will have to do.

      Regardless, thanks for the suggestion.

Re: [OT?] formatting response text for AJAX widget
by jfluhmann (Scribe) on Aug 04, 2006 at 19:25 UTC
    I'm not sure if this is it, but your innerHTML enclosing quotes don't match. The next to last '; should be \"; And I think you need to escape the backslashes within the innerHTML quotes.
    $response = "\$('override_$componentId').innerHTML=\"<a href='#' onCli +ck='javascript:makeForm( \\"$componentId\\", \\"$componentType\\", \\ +"$newTitle\\");'>$newTitle</a>\";";
      Adding more toothpicks (  \\" ) is what fixed it.