views:

422

answers:

1

So I have a have a solution for this, but I wanted to get some opinions and see if there was a better way to do this.

My problem is basically that I list of data that will get generated on load by RoR and then have JS controls to view subsets. I would rather not have to support two versions of what is basically the same HMTL. So my solution is this, I have a ruby partial that looks something like this:

<% value1 = jsmode ? '#{value1}' : object.value1
value2 = jsmode ? '#{value2}' : object.value2 $>
<div class="object_template">
<div><$= value1 $></div>
<div><%= value2 %></div>
</div>

So when I render the partial with ruby, I pass in a jsmode of false and it renders like a normal partial. Then I will render the partial again wrapped with a div with an ID of template but this time with a jsmode of true. This will render the html with the #{} strings. I can then pass the template to prototype Template object like this:

new Template($('template')).evaluate({value1: '111', value2: '222'});

So my question is, is there a better way to do this?

I know that I can use the #{} construct to pass variables to RoR if I wrap them with double quotes, but I need the #{} to render for the JS template.

Thoughts?

A: 

The general approach looks good and actually probably a little better than what I've done before in some cases.

However, it looks to me like you're actually rendering the JS version to a div and then passing that into Prototype Template. Template also accepts a string so you can just pass the raw js template straight to it. Unless I'm missing something, the #template div is not necessary on its own. So the string route is probably the better way to go.

From Rails, it would probably look something like this:

<script type="text/javascript">
  var raw_template = "#{escape_javascript(render(:partial => 'template', :locals => { :jsmode => true }))}";
  var output = new Template(raw_template).evaluate({value1: '111', value2: '222'});
  // Do something with the output
</script>

escape_javascript uses the following map:

JS_ESCAPE_MAP = {
  '\\'    => '\\\\',
  '</'    => '<\/',
  "\r\n"  => '\n',
  "\n"    => '\n',
  "\r"    => '\n',
  '"'     => '\\"',
  "'"     => "\\'" }

This means that given your suggested template, you should end up with a result along the lines of:

 var raw_template = "<div class=\"object_template\">\n<div>#{value1}<\/div>\n<div>#{value2}<\/div>\n<\/div>";

Which should do the trick nicely.

Peter Wagenet
This is kind of what i wanted to do, but I was concerned about newlines on the template. I haven't tested this yet, but will escape_js convert this into a single line?
Rodrigo
Just to add to my comment. JS has no HEREDOC construct. I would have like to do to some sort of HEREDOC render partialHEREDOCWhat I found was people saying to use the HTML for that.
Rodrigo
I've edited my post to clarify how escape_javascript works.
Peter Wagenet