why handlebars compile the script template as CDATA - javascript

I write a function which compile a handlebars template and append to the html.
I use thousands times of handlebars template in my project and all things go well.
I have to mention it'll be rendered properly in localhost, but in the server it returns me with CDATA.
but in this case handlebars outputs like this and causes lots of problems.below is template html which is inside template.php file
<script id="w-l-template" type="text/x-handlebars-template">
<div data-name="name{{ID}}"></div>
.....
</script>
here is function inside a js file called my.js
var num = 2;
function add_name(){
var out = $('#w-l-template').html();
var template = Handlebars.compile(out);
var data={
ID:num
}
var res=template(data);
$('[data-main-content="main"]').append(res);
num = num+1;
}
$(document).on('click', '#add', function(){
add_name();
});
but after being rendered by handlebars, I'll get CDATA at the first line like this
<!--[CDATA[*/<div class="col-lg-12 "data-name="2"-->

I know this answer is kind of late, but I had a similar issue today. I found out that Handlebars isn't adding the CDATA into my HTML, it's actually Drupal. We sometimes create pages with Drupal's inline editor, and so I'll drop in HTML via the Full HTML editor.
Unfortunately, if you don't configure the HTML editor in Drupal to NOT rewrite broken HTML -- it considers Handlebar script syntax as broken, then Drupal will attempt to fix the tag and add in CDATA which makes your tag get commented out. Handlebars will then try to template that new commented tag and also output a commented out tag. Frustrating! But hope my answer somewhat helps you with yours (or if you run into this situation again in the future).
Basically TL:DR, it's not Handlebars -- it's probably some setting in your PHP (or CMS that uses PHP) that is probably trying to "fix" the Handlebars template because it thinks the HTML is broken.

Related

why the generated function throws out the not defined error

I'm trying to generate a JS script using JS sounds tricky. But the function inside the generated script comes to form and I try to call, it says undefined I'm giving a minimalistic example of my code. I don't know why it's happening maybe function defining on appending or changing the inner html does not work. If you can figure it out that how I can solve this problem, please tell me it'll help out a lot. Thanks! here is the example code.
<body>
<script>
let b = '<script>function amb(){console.log("hello")}' + '<' + '/' + 'script>'
document.body.innerHTML = b
</script>
<div id="a">
<button onclick="amb()"> amb</button>
</div>
</body>
That is probably because it is not loaded if you just add it afterwards. Nevertheless generating code with code should be avoided! If anywhere input data is used it is that vulnerability. Also it is bad code and hard to understand.
You should overthink your concept and maybe try to explain what you want to achieve and search for in the internet. Or maybe we can here give you a suggestion.
With the suggestion from #Lk77
A solution I would NOT recommend! could look like:
<div>
<button> amb</button>
</div>
let s = document.createElement('script');
s.text = 'function amb(){ console.log("hello"); }'
document.body.appendChild(s);
document
.querySelector('button')
.addEventListener('click', amb);
regarding your answer in the comments
I'm making a website which is used to generate tables it requires a form but I'm too lazy to write hundreds lines of html so i used js but someone has told me that the code generated afterwards is not loaded. I don't know how can i load the generated code
try to think simple... instead of generating code to generate you sth. use js to generate html that's the purpose of js. 100% sure you don't need to code code that generates code. You can create a website that is 99% powered by javascript that kind is called webapp. https://angular.io/start is one of many frameworks to achieve that. And none of them generates code by code.
You can't use innerHTML, you will need to append to the body :
var s = document.createElement( 'script' );
s.text = 'alert("test")'
document.body.appendChild( s );
but the real question is why you want to do that

ClientDependency Framework & Razor, add custom JS

I'm trying to get the hang of ClientDependency Framework.
https://github.com/Shazwazza/ClientDependency
I use it in an Umbraco website.
I'm having a problem with some custom javascript (not in a file) that I want to run.
I want to run a function (which is in "functions.js"), but with a different parameter per page.
So, I add the following to my template:
Html.RequireJs("~/scripts/functions.js", 1);
And on my masterpage before the -tag I've added:
#Html.RenderJsHere()
But where do I place my function-call? I can't just add it to my template, because "functions.js" isn't loaded yet (it's at the bottom of my masterpage).
I've thought about creating a js-file for each call and add them to the Html.RequireJs(...) but that isn't a great solution.
Is there a way to add inline-script to the list of "JS-to-render" ?
edit:
I was just trying to get it to work using RenderSection(), but that doesn't seem to work when the section is defined on a macro?
edit:
I don't have the code here at the moment I'm typing this, but the idea is like this:
functions.js
function WriteToConsole(input) {
console.log('Log', input);
}
template1.cshtml
#{Html.RequireJs("functions.js");}
<script>
WriteToConsole("This is from template 1");
</script>
template2.cshtml
#{Html.RequireJs("functions.js");}
<script>
WriteToConsole("This is from template 2");
</script>
master.cshtml
<body>
#RenderBody()
#Html.RenderJsHere()
</body>
Just to give an idea of what I'm trying to do.
As you can imagine, the <script> part on my template is now being called before functions.js is included. And this results in an error.
Or am I handling this whole thing wrong?
Are you trying to alter the script call in: Html.RequireJs("~/scripts/functions.js", 1); ?
So something like Html.RequireJs("~/scripts/functions.js?myparam=xyz", 1); Is this what you are trying to achieve but having the url be dynamic?
If so you could do something like this :
//perhaps have some logic above to determine what the query should be and concatenate it to the string like so.
string query = "?myparam=xyz";
string scriptcall = "~/scripts/functions.js"+query ;
Html.RequireJs(scriptcall, 1);
Could you provide more code so we can see what you are trying to do? Maybe list in steps on how it should work?

HTML with commented JavaScript code

I am trying to parse a HTML code in order to extract all links in it. To avoid unavailable links I remove the commented code that begins with <!-- and ends with --> .Here comes the problem: In the HTML code I may find some JavaScript code, for example:
<html>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!-- Begin
if (document.images) {
var pic2 = new Image(); // for the inactive image
pic2.src = "pic2.jpg";
var title2 = new Image();
title2.src = "title2.jpg";
}
...
-->
and the weird thing is that the js code is commented but it still works. So, if I remove that code, the result won't be as expected. What should I do in order to identify when I'm facing with unused commented code and when that commented code is functional?
the weird thing is that the js code is commented but it still works
Those aren't comments. Is is just syntax allowed inside script (and style) elements that follows the comment syntax so that browsers which predate script and style don't render the code as text.
What should I do in order to identify when I'm facing with unused commented code and when that commented code is functional?
Write a real HTML parser, following the parsing specification, and then remove any comment nodes from the generated DOM.
As a dirty (but possibly quick) solution, you could just ignore comments inside elements marked as containing CDATA in the HTML 4.01 DTD.
the weird thing is that the js code is commented but it still works
There is nothing weird about it. The comments <!-- --> only work in HTML, not JavaScript. Your above code will still work since you've put these comments within the <script> tags.
The only difference it makes is that if the user has disabled JavaScript on his/her browser, he won't see the code printed on the browser (since HTML will parse those comments in the absence of JavaScript).
You need to comment out the whole <script> block. e.g.
<!-- <script>
...some javascript code...
</script> -->

AngularJS - inject trusted code from loaded content

I've hooked up a lazy loader in Angular. It pulls in full templates and extracts key information from that full template in order to populate a partial. This full page template has script tags which load in and then register with the existing app. All of this works fine. My problem is that I'd like to remove the only use of jQuery in this approach.
The root issue is that the JS inside of something.js doesn't execute when using $element.html(), but it does execute when using $.html(), despite the script tag being placed in the DOM in both approaches.
Working code, including lazy loader and post-bootstrap registration of lazy-loaded JS:
$http.get("/path/to/file.html").success(function(response) {
// response is a full HTML page including <doctype>
var partial = getOnlyWhatWeNeed(response);
// partial is now something like: '<script type="text/javascript" src="/path/to/something.js"></script><div ng-controller="somethingCtrl">{{something}}</div>'
// i'd like the following to not rely on full jQuery.
$("#stage").html(partial);
$("#stage").html($compile(partial)($scope)); // it is necessary to do it once before compile so that the <script> tags get dropped in and executed prior to compilation.
});
I've tried what seems like the logical translation:
$element.html($compile(partial)($scope));
and the DOM is created properly, but the JS inside of the loaded <script> tag doesn't actually execute. My research suggested this was an $sce issue, so I tried:
$element.html($compile($sce.trustAsHtml(partial)($scope));
but i get the same result. the DOM is fine, but the JS doesn't actually execute and so I get undefined controller issues.
I've tried playing with $sce.JS and $sce.RESOURCE_URL but the docs didnt elaborate much so I'm not sure I know whether or not what I'm trying is even right.
I've also tried $element[0].innerHTML but I get the same result as $element.html().
Preemptive disclaimer: I can trust the incoming HTML/JS. I know it's inadvisable. This isn't my baby and it is much more complicated than I explained so please try to stay on topic so other people in this position may not have as hard of a time as I am :)
The $http.get happens in a provider, and the $element.html happens in a directive. I consolidated them to remove noise from the problem.
Jquery will find any script tags and evaluate them (either a direct eval or appending them to the head for linked scripts) when calling html(), see this answer. I'm assuming angular's jquery lite doesn't do this. You would need to effectively replicate what jquery is doing and look for script tags in the html you are appending.
Something like this (although I haven't tested it):
$http.get("/path/to/file.html").success(function(response) {
// response is a full HTML page including <doctype>
var partial = getOnlyWhatWeNeed(response);
// partial is now something like: '<script type="text/javascript" src="/path/to/something.js"></script><div ng-controller="somethingCtrl">{{something}}</div>'
var d = document.createElement('div');
d.innerHTML = partial;
var scripts = d.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
document.head.appendChild(scripts[0]);
}
$("#stage").html($compile(partial)($scope)); // it is necessary to do it once before compile so that the <script> tags get dropped in and executed prior to compilation.
});
This is far from an ideal solution as it gives you no guarantee of when things are loaded and doesn't really handle dependencies across scripts. If you can control the templates it would be simpler to remove the scripts from them and load them independently.

Getting content of a script file using Javascript

I have the following script element in my web page:
<script src="default.js" type="text/javascript"></script>
Using JavaScript, I want to be able to retrieve the content of the script file. I know I could use an ajax request to get the data but then I am getting something from the server that I already have locally.
So what I would prefer to do is retrieve the content from the DOM (if that's possible) or something that has the same result.
Cheers
Anthony
UPDATE
I was trying to simplify the question, maybe a bad a idea, I thought this way would cause less questions.
The real situation I have is as follows, I actually have
<script type="text/html" class="jq-ItemTemplate_Approval">
...
html template that is going to be consumed by jQuery and jTemplate
...
</script>
Now this works fine but it means each time the page loads I have to send down the template as part of the HTML of the main page. So my plan was to do the following:
<script src="template.html" type="text/html"></script>
This would mean that the browser would cache the content of template.html and I would not have to send it down each time. But to do this I need to be able to get the content from the file.
Also in this case, as far as I know, requesting the content via ajax isn't going to help all that much because it has to go back to the server to get the content anyway.
If I understand you correctly, you don't want to use Ajax to load an html template text, but rather have it loaded with the rest of the page. If you control the server side, you can always include the template text in an invisible div tag that you then reference from Javascript:
<div id="template" style="display:none;">
...template text...
</div>
<script>
// pops up the template text.
alert(document.getElementById("template").innerHTML);
</script>
If you are just looking for to load the template so that you can have it cached, you can put the contents in a variable like this:
<script>
var template = "template text..";
</script>
or you can load it using ajax and store the template in a variable so it is accessible. It's pretty trivial in jquery:
var template;
$.get("template.html", function(data){
template = data;
});
unless you load a script as literal text in the page, it does not exist as text. It is interpreted by the browser and melded into the runtime, with any other scripts.
If you want the source you have to fetch it again,if with Ajax get the responseText.
It will come from the browser cache, and doesn't have to be downloaded again.
I think what you want to do is to assign a variable inside template.js. Then you have the variable available for use wherever you want in jquery. Something like:
var tpl = "<div> ... </div>"
Wouldn't this be a simpler solution to your problem? We do this in Ext JS. I think this will work for you in jQuery.
You could get the attribute of the src of the script and then use XHR to get the contents of the JS file. It's a much cleaner way of doing it IMO. e.g.:-
if(window.XMLHttpRequest) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.status == 200 && xhr.readyState == 4) {
var sourceCode = xhr.responseText;
alert('The source code is:-\n'+sourceCode);
}
}
xhr.open("GET",document.getElementById('scriptID').src,true);
xhr.send(null);
}
Using an iFrame & HTML5 Local Storage
Save the templates for rendering later...
not stoked about the iFrame, but it seems to be working pretty good (haven't ran performance tests yet)
Put the iFrame on the page you want the template on (index.html)
<html>
<head>
<iframe src="mustache.Users.html" onload="this.remove();" class="hidden" id="users_template"></iframe>
</head>
</html>
Make sure the src attribute is set
hide the element until you can get rid of it after it loads
Put this body wrapper around your template (mustache.Users.html)
(don't worry it won't show up in the template)
<body onload="localStorage.setItem('users_template',this.document.body.innerHTML);">
<ul class="list-group" id="users" >
{{#users}}<li>{{name}}</li>{{/users}}
</ul>
</body>
replace 'users_template' with whatever name for your variable
the 'onload' attribute saves the template into localStorage during load
Now You can access your templates from anywhere
localStorage.getItem('users_template')
OR
window.localStorage.getItem('users_template')
What is in the JavaScript file? If it's actual code, you can run functions and reference variables in there just like you had cut and paste them into the webpage. You'll want to put the include line above any script blocks that reference it.
Is this what your looking to accomplish?
Why not use Ajax (well Ajah because its html :-))?
when the server is set up correctly and no no-cache or past expires headers are sent, the browser will cache it.
The way that most JavaScript import files work is they include a script, that immediately calls a function with a parameter of certain text, or of another function. To better illustrate, say you have your main index.html file, set it up like this:
<html>
<head>
</head>
<body>
<script>
let modules = {};
function started(moduleName, srcTxt) {
modules[moduleName] = (srcTxt) //or something similar
}
</script>
<!--now you can include other script tags, and any script tags that will be included, their source can be gotten (if set up right, see later)-->
<script src="someOtherFile.js"></script>
</body>
</html>
now make that other file, someOtherFile.js, and right away when its loaded, simply call that "started" function which should already be declared in the scope, and when thats done, then whatever text is passed, from the file, is stored in the main index.html file. You can even stringify an entire function and put it in, for example:
started("superModule", (function() {
/*
<?myCustomTemplateLanguage
<div>
{something}Entire Javascript / html template file goes here!!{/something}
</div>
?>
*/
}).toString());
now you can access the inner content of the function, and get all the text in between the comments, or better yet, then do other parsing etc, or make some other kind of parsing identifiers at the beginning and end of the comments, as shown above, and get all text in between those

Categories

Resources