Need a little help nesting variables in ES6 backticks - backticks

I am trying to dynamically create a html UL with my own json data and a map function incorporating js ES6 backticks. I am almost there but I'm stuck with nesting a value in a variable.
I have tried escaping the nested tool but no success
let frontList = data[i].tools.Front.map(tool => {
return `<li>${tool.tool}</li>`
}).join("")
This way above is working as you suggested, thank you!
let output = ''
output += `
<span class="closeBtn">×</span>
<h3>${data[i].title}</h3>
<p> ${data[i].desc}</p>
<h5>Front End</h5>
<ul>
${data[i].tools.Front.map(tool => {
return `<li>${tool.tool1}</li>`
}).join("")}
</ul>
`
if (data[i].tools.Back) {
output += `<h5>Back End</h5>
<ul>
<li>${data[i].tools.Back[0].tool1}</li>
<li>${data[i].tools.Back[1].tool2}</li>
<li>${data[i].tools.Back[2].tool3}</li>
<li>${data[i].tools.Back[3].tool4}</li>
<li>${data[i].tools.Back[4].tool5}</li>
</ul>`
}
I expected the nested tool to be escaped but i'm getting error..
Uncaught SyntaxError: Invalid or unexpected token

Related

How to convert HTML with Ruby helper method ERB into Slim syntax

Trying to convert some HTML code in a template to Slim syntax. The original code uses a Ruby helper method (in Rails) to dynamically determine the class of the li element.
Here is the original code in HTML:
<li class="<%= is_active_controller('dashboards') %>">
The online converter gives:
| <li class="
= is_active_controller('dashboards')
| ">
This not only is ugly and clunky--it doesn't work.
I've tried various options without success. Such as:
li class=is_active_controller('dashboards')
...as well as several other variations without success.
li class=(is_active_controller('dashboards'))

Rails 4 - Moving js inline script inside View to JS file

I would like to move some js inline scripts I have on my homepage to a javascript file (in Assets) but there is some complexity due to variables.
home.html.erb
<div>
this is the homepage
</div>
<script>
<% #deal.deal_details.each_with_index do |popin, index| %>
<% index_plus_one = index + 1 %>
function loadInfoPopin() {
var msg;
msg = Messenger().post({
message: '<%= j render partial: "deals/info_popin/info_popin#{ popin['popin_id'] }",
locals: { popin: popin, index: index_plus_one } %>'
});
}
<% end %>
</script>
For the sake of information here is the format of the Deal's column/attribute 'deal_details' (it's a json attribute):
[{"popin_id":"4","text1":"qqq","text2":"sqsq","image1":"sqqs"},{"popin_id":"5","text1":"sqqs","video1":"s"}]
This is an example and you can have as many json block inside the array as possible.
deals/info_popin/info_popin5.html.erb (it's an example)
<div>
<p>cool image</p>
</div>
</div>
Now, how can I move the whole script or at least the function loadInfoPopin() to a javascript file (that is to say away from the view home.html.erb) ?
Thanks
How about moving the loadInfoPopin() function into a separate JS file and altering the function slightly to take in an argument for the html message?
function loadInfoPopin(html_message) {
Messenger().post({
message: html_message
});
Setup the html for the message within the loop before passing into and calling loadInfoPopin.
.js.erb is an option. This way the js files will be parsed before compiling. Not sure though it will work the way you want.
I would recommend to leave the variables in the layout as vars and moving only the static JS parts to the assets.

ujs + remotipaart - when running jQuery `.html(...)` calls, the appended html becomes just text

I am using rails 5, with remotipart. The remotipart version is:
gem 'remotipart', github: 'mshibuya/remotipart'
(At the moment of this question, the current commit is 88d9a7d55bde66acb6cf3a3c6036a5a1fc991d5e).
When I want to submit a form having multipart: true andremote: true` but without sending any attached file, it works great. But when I send a file, it fails.
To illustrate the case, consider a response like this:
(function() {
modelErrors('<div class=\'alert alert-danger alert-dismissible\' role=\'alert\'>\n <div aria-label=\'Close\' class=\'close fade in\' data-dismiss=\'alert\'>\n <span aria-hidden>\n ×\n <\/span>\n <\/div>\n Code can\'t be blank\n<\/div>\n');
}).call(this);
When this response is executed, immediately after arriving (since it is js), the form looks as it expected (in this case, this validation error is right to happen, and the rendered danger alert is right to appear with such text):
However, when I fill the file field, and repeat the exact same case (exact same validation error), the form looks quite different:
If you can guess, the contents are passed as text. The actual response being received from the server is a bit different:
<script type="text/javascript">try{window.parent.document;}catch(err){document.domain=document.domain;}</script>(function() {
modelErrors('<div class=\'alert alert-danger alert-dismissible\' role=\'alert\'>\n <div aria-label=\'Close\' class=\'close fade in\' data-dismiss=\'alert\'>\n <span aria-hidden>\n ×\n <\/span>\n <\/div>\n Code can\'t be blank\n<\/div>\n');
}).call(this);
This is the actual body of my response (it is not a bad copypaste, but the actual response as wrapped by remotipart).
The modalErrors function is quite dumb:
function modalErrors(html) {
$('#main-modal > .modal-dialog > .modal-content > .modal-body > .errors').html(html);
}
Comparing the jQuery-appended html chunks (I look for them in the browser's DOM inspector), they look like this:
Good:
<div class="alert alert-danger" role="alert">
<ul style="list-style-type: none">
<li>Code can't be blank</li>
</ul>
</div>
Bad:
Code can't be blank
What am I missing here? What I want is to allow my resposes to append html content when needed.
The remotipart lib, which uses something named iframe-transport, unwraps the content later and executes the response as if it was fetched with ajax.
However, the tags are stripped from the response, so the response will be converted to something like this:
try{window.parent.document;}catch(err){document.domain=document.domain;}(function() {
modelErrors('\n \n \n ×\n \n \n Code can\'t be blank\n\n');
}).call(this);
The solution I found to interact with this library in a sane way, is to define another helper helper, similar to j / escape_javascript:
module ApplicationHelper
JS_ESCAPE_MAP = {
'\\' => '\\\\',
'<' => '\\u003c',
'&' => '\\u0026',
'>' => '\\u003e',
"\r\n" => '\n',
"\n" => '\n',
"\r" => '\n',
'"' => '\\u0022',
"'" => "\\u0027"
}
JS_ESCAPE_MAP["\342\200\250".force_encoding(Encoding::UTF_8).encode!] = '
'
JS_ESCAPE_MAP["\342\200\251".force_encoding(Encoding::UTF_8).encode!] = '
'
def escape_javascript_with_inside_html(javascript)
if javascript
result = javascript.gsub(/(\\|\r\n|\342\200\250|\342\200\251|[\n\r<>&"'])/u) {|match| JS_ESCAPE_MAP[match] }
javascript.html_safe? ? result.html_safe : result
else
''
end
end
alias_method :jh, :escape_javascript_with_inside_html
end
In the views which are susceptible of being sent both by regular ajax and remotipart -in different scenarios, I mean- just replace the j calls with jh calls. Example:
modalErrors('<%= j render 'shared/model_errors_alert', instance: #team %>')
was replaced with
modalErrors('<%= jh render 'shared/model_errors_alert', instance: #team %>')

Rails tag syntax with multiple data attribute values quotes excluded

Trying to generate
<img data-interchange="[assets/img/interchange/small.jpg, small], [assets/img/interchange/medium.jpg, medium], [assets/img/interchange/large.jpg, large]">
is challenging.
<%= tag "img", data: { interchange: ["[#{photo.image_url(:base).to_s}, small]", "[#{photo.image_url(:big).to_s}, medium]", "[#{photo.image_url(:desktop).to_s}, large]"] } %>
will generate HTML, but the result is still inoperative
<img data-interchange="["[https://[...]base_20160529_115006.jpg, small]","[https://[...]big_20160529_115006.jpg, medium]","[https://[...]desktop_20160529_115006.jpg, large]"]" />
as " gets generated.
What is the proper syntax to get the proper HTML string
In rails you can use ActiveSupport's to_json to encode things into json.
<%= tag "img", data: { interchange: [[photo.image_url(:base), 'small'], [photo.image_url(:big), 'medium'], [photo.image_url(:desktop), 'large']].to_json } %>
Which produces
<img data-interchange="[[\"assets/images/interchange/base.jpg\",\"small\"],[\"assets/images/interchange/big.jpg\",\"medium\"],[\"assets/images/interchange/desktop.jpg\",\"large\"]]" />
Then on the front-end you can use JSON.parse once you retrieve the value via getAttribute or with jQuery data, if you need to use the data on the front-end.
var text = JSON.parse(element.getAttribute('data-interchange'));

How should I update the pagination links in an AJAX call?

So I've implemented AJAX pagination. The problem is that since the <%= paginate #videos %> code is not inside the partial that I render, the pagination links are not updated. What jQuery code should I use to update the pagination links?
Btw I tried $(".pagination").replaceWith('escape_javascript(<%= paginate #videos %>)');;
but i get this error: Uncaught SyntaxError: Unexpected token ILLEGAL
$(".pagination").replaceWith("escape_javascript(<%= paginate #videos %>)");; throws this error: Uncaught SyntaxError: Unexpected identifier
Here is the JS code the browser sees:
$(".pagination").replaceWith(" <nav class="pagination">
<span class="prev">
« Prev
</span>
<span class="page first">
1
</span>
<span class="page current">2</span>
<span class="page last">
3
</span>
<span class="next">
Next »
</span>
</nav>
");
Ideally, the new pagination links should be included in the HTML response of the ajax call. If that is not possible - presumably because the links reside elsewhere in the document, then I would suggest creating a context/link/URI/action/whatever (disclaimer: I'm not a ROR guy) which returns a JSON string, structured something like:
[{"data": "The HTML output"}, {"pageLinks": "pagination HTML"}]
and replace your ajax call with one which expects JSON as the return dataType. Then it should be easy, e.g.:
$.ajax({
url: 'theURL',
dataType: 'json',
success: function(json) {
$('.pagination').html(json.pageLinks);
$('#someDiv').html(json.data);
}
});
The problem looks to be the quotes in your use of replaceWith. You need to escape the characters of that string before trying to use it.
You have double quotes starting and ending your string argument in the replaceWith function but the string you are feeding it also has double quotes throughout that don't look to be escaped. Every time a double quote is encountered it is terminating the string and trying to parse the rest as javascript statements and not a string.
I know this is an old question, but I faced a simmilar problem using will_paginate gem, and I tryed a lot of complicated stuffs to update the pagination. However, I did it with a simple solution, that maybe can help someone else.
In summary, create a partial where you put the call to will_paginate helper inside a div, and after your ajax request, just render this partial again. For instance:
The _pagination.html.erb:
<div id="paginate">
<%= will_paginate #results %>
<div>
The your_template.js.erb (where #results should be available):
$('#paginate').html('j(render "pagination.html.erb")');
That should be enough.

Resources