.hbs files strips javascript - gruntjs

I am including a script in .hbs file, but every time I assemble grunt assemble this .hbs file, the hbs template inside the script is ignored in the HTML output.
This is my .hbs file
<script id="myTemplate1" type="text/x-handlebars-template">
{{#each}}
<div class="sample">
....
</div>
{{/each}}
</script>
I assembling the above .hbs file using grunt assemble and it just ignores all the content inside the script tag and I could see only the following in the HTML output
<script id="myTemplate1" type="text/x-handlebars-template">
</script>
What's wrong here? I tried to have the script as a separate JS file but didn't work? I also tried to include the script in the HTML output but every time I assemble, it overwrites and I get only the empty tags.

The #each block helper requires an array passed to it to iterate over. It would look something like...
<script id="myTemplate1" type="text/x-handlebars-template">
{{#each templatesArray}}
<div class="sample">
....
</div>
{{/each}}
</script>
See the Handlebars Documetation for more examples.
You should also check out Handlebars-Helpers, made by the creators of Assemble, it contains a whole bunch of useful helpers.

You can use the things that i mention below. I realized that that method would contradict the foundations of Handlebars. Instead, I added the following to my controller:
var scripts = [{ script: '/js/myTestScript.js' }];
res.render('contact', { title: 'Kontakt', scripts: scripts });
And in my layout it looks like this:
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
{{#each scripts}}
<script src="{{script}}"></script>
{{/each}}

Related

Cannot load jquery before other script

I need to load JQuery before anything else, so I created this code inside _Layout:
<!DOCTYPE html>
<html>
<body class="sidebar-enable" data-keep-enlarged="true">
<div class="wrapper">
#RenderBody()
</div>
<script src="~/js/jquery.min.js"></script>
#RenderSection("DataTableScript", required: false)
</body>
</html>
I have a ViewComponent called ProductsViewComponent, I load it inside a View called Home in this way:
#await Component.InvokeAsync("Products", new { date = "2018-09-05" })
Inside the ViewComponent I need to load the DataTableScript (which requires JQuery for works properly), so I created this logic inside the Default.cshtml (which is the html of ProductsViewComponent):
#{
Layout = "/Views/Shared/_LayoutViewComponent.cshtml";
}
#section DataTableScript{
<script src="~/js/vendor/jquery.dataTables.js"></script>
<script src="~/js/vendor/dataTables.bootstrap4.js"></script>
<script src="~/js/vendor/dataTables.responsive.min.js"></script>
<script src="~/js/vendor/responsive.bootstrap4.min.js"></script>
<script src="~/js/vendor/dataTables.buttons.min.js"></script>
<script src="~/js/vendor/buttons.bootstrap4.min.js"></script>
<script src="~/js/vendor/buttons.html5.min.js"></script>
<script src="~/js/vendor/buttons.print.min.js"></script>
<script src="~/js/vendor/dataTables.keyTable.min.js"></script>
<script src="~/js/vendor/dataTables.select.min.js"></script>
<script src="~/js/dataTable.js"></script>
}
I have specified another Layout because the ViewComponent is not able to render a section (see this question for further information)
inside the _LayoutViewComponent I placed this code:
#RenderBody()
#RenderSection("DataTableScript")
Essentially RenderBody calls _Layout and then the DataTableScript are loaded. But when I start the application I get the DataTableScript loaded before of JQuery and this is really weird because in the _Layout I specified to load the DataTableScript after JQuery.
You can use a partial to render your script tags.
Views/Shared/_DataTableScriptsPartial.cshtml
<script src="~/js/vendor/jquery.dataTables.js"></script>
<script src="~/js/vendor/dataTables.bootstrap4.js"></script>
<script src="~/js/vendor/dataTables.responsive.min.js"></script>
<script src="~/js/vendor/responsive.bootstrap4.min.js"></script>
<script src="~/js/vendor/dataTables.buttons.min.js"></script>
<script src="~/js/vendor/buttons.bootstrap4.min.js"></script>
<script src="~/js/vendor/buttons.html5.min.js"></script>
<script src="~/js/vendor/buttons.print.min.js"></script>
<script src="~/js/vendor/dataTables.keyTable.min.js"></script>
<script src="~/js/vendor/dataTables.select.min.js"></script>
<script src="~/js/dataTable.js"></script>
In your _Layout.cshtml declare a scripts section.
<!DOCTYPE html>
<html>
<head>
#RenderSection("head", required: false)
</head>
<body class="sidebar-enable" data-keep-enlarged="true">
<div class="wrapper">
#RenderBody()
</div>
<script src="~/js/jquery.min.js"></script>
#RenderSection("scripts", required: false)
</body>
</html>
In the page that uses your ViewComponent render the partial in the scripts section.
Products.cshtml
#{
Layout = "_Layout";
}
#await Component.InvokeAsync("Products", new { date = "2018-09-05" })
#section scripts {
#await Html.PartialAsync("_DataTableScriptsPartial")
}
You cannot specify a layout for a view component view. It's essentially a partial view. By the time the view component is processed the main layout is already set in stone. You should use a script loading library to conditionally include your additional scripts, and then externalize the JavaScript that serves your view component and have it run after the associated scripts are finished loading.
There's various different libraries/techniques you can use for this: CommonJS, AMD, RequireJS, etc. You'll need to do some research and figure out which is the best fit for you. However, this is a transformative thing. It will change the entire way you handle scripts with your application and might require some major restructuring of anything existing, as a result.
The easier approach is to simply just include the script in your main layout. If your layout includes this view component, then it's always going to need the scripts anyways, so just go ahead make it static. It doesn't have a the warm fuzzies of a completely self-contained unit of functionality that you're wanting your view component to be, but to get there is going to likely require far more effort that is warranted or reasonable for this one particular scenario.
For what it's worth, you can optimize things a bit by front-loading the scripts using the <link rel="preload" href="..." as="script" /> tag. This would go in your head, and prompt supporting browsers to go ahead and load in the script, without actually running it (which is the part that blocks rendering). Then, by the time you actually include the script before the closing body tag, it's likely already good to go, and the script tag will simply prompt the browser to run it.
UPDATE
One further options is to use a client-side library that supports "components". This would be a replacement for your view component, not something you'd add in addition to. However, the benefit of a client-side component is that you can contain all the JavaScript functionality in that and then the library simply runs over your document at the end and wires everything up. I personally like Vue, but there's other choices like React, Ember, Angular, etc. Consult with the documentation for each to evaluate if you might prefer this approach instead and which particular library you prefer. They all essentially do the same thing, but they each have their own unique ways of getting there.
I like Vue personally because it's light-weight and largely unobtrusive. It doesn't necessarily force you to do things in a certain way, so you can have a bit more freedom in that respect. Libraries like React and Angular tend to be more opinionated, and since they're geared more towards creating single page applications, can sometimes make it difficult to split responsibilities with server-side rendering such as Razor views. Just my opinion though.

meteor iron router basic example. Can't make it route

I simply created a meteor project and copy/paste from the example 'basic' files (found at https://github.com/EventedMind/iron-router/tree/devel/examples/basic) replacing Meteor project .html and .js files.
On the HTML, the example failed to include any template inclusion so I added {{> Home}} and run Meteor between the 'body' block.
<body>
{{> Home}}
</body>
The complete HTML code is:
basic
<body>
{{> Home}}
</body>
<template name="Home">
<h1>Home</h1>
{{> Nav}}
<p>
Data Title: {{title}}
</p>
</template>
<template name="One">
<h1>Page One</h1>
{{> Nav}}
</template>
<template name="Two">
{{> Nav}}
<h1>Page Two</h1>
</template>
<template name="Nav">
<ul>
<li>
Home
</li>
<li>
Page One
</li>
<li>
Page Two
</li>
</ul>
</template>
The .js code is exactly as in the example.
When run, however, it failed to change or route to pages One and Two. It simply stays on Home.
I am learning to work with it but I don't seem to get it right even on the simplest of examples. What I am doing wrong?
Router.map is now deprecated and replaced by Router.route, however, there seem to be a few bugs they're still ironing out. First of all, I've found that their basic routing function rarely works at the moment, so don't use it for now, i.e.:
Router.route('/path', function() {
this.render('pathName');
});
Whether this is due to compatibility issues or something else, I have no idea. I have found a very standard formula that seems to work quite nicely however, and that is to replace the function with the built in "Route Specific Options", and specify exactly what you want, like so using basic JSON:
Router.route('/path', {
name: 'pathName',
path: '/path',
template: 'templateName',
data: function () {
title: 'My Title'
}
});
Notice the path: option. This should not be necessary, as the path is defined as the first parameter of your Router function, but they specifically state in the documentation that you may need to include a path: in your routes for backwards compatibility. I'm sure once they get everything operating smoothly you'll be able to delete this entirely.
Also, the template: option should not be necessary if the templateName is the same as your /path (and for that matter, the pathName: option should not be necessary if it is also the same as your /path), but I've found including them just makes life easier as sometimes they will not function properly otherwise.
In short, when the bugs are gone, simple templates like yours will be called with one line:
Router.route('/one');
The end result is that they have simplified how routes are called and defined, but unfortunately, it just doesn't seem to working as planned at the moment. I hope this helps you with understanding the difference between Router.map and Router.route now.
Plus, the main problem with your code before was that you inserted the partial {{> Home}} between your body tag, which isn't necessary and messes things up, as that partial will always remain even as meteor attempts to route between and load other templates. In essence, when Meteor went to load template "One" it had to do so on top of template "Home", meaning you had, among other things, two {{> Nav}} partials loading at once.
When using iron router package you must leave body tag as it is or don't include it at all, i'm using a layout template but its not necessary:
basic.html:
<head>
<title>basic</title>
</head>
<body>
</body>
<template name="layout">
{{> yield}}
</template>
<template name="Home">
{{> Nav}}
<h1>Home</h1>
<p>
Data Title: {{title}}
</p>
</template>
<template name="One">
{{> Nav}}
<h1>Page One</h1>
</template>
<template name="Two">
{{> Nav}}
<h1>Page Two</h1>
</template>
<template name="Nav">
<ul>
<li>
Home
</li>
<li>
Page One
</li>
<li>
Page Two
</li>
</ul>
</template>
basic.js:
Router.configure({
layoutTemplate: 'layout'
});
Router.map(function(){
this.route('Home', {path: '/', data: {title: 'My title'}});
this.route('One');
this.route('Two');
});
and now works properly.

MVC5: Cannot Reference Scripts folder from within EditorTemplate

I have an editor template which cannot reference anything from the scripts folder. If I place the same reference in my layout page it works perfectly:
<script src="#Url.Content("~/Scripts/tinymce/jquery.tinymce.min.js")"></script>
This works in my layout page but does not load in my Editor Template page.
Edit: Google Developer tools show 404 (Not Found). The file is in the correct location as it can be referenced from my layout Page.
In the body element of your layout page you need to have this code somewhere like this below:
<body> ... #Html.RenderScripts() </body>
and reference your script in your editor template like below:
#Html.Script(
<script src="#Url.Content("~/Scripts/tinymce/jquery.tinymce.min.js")"></script>
)
here is the alternative:
<body> ... #RenderSection("scripts", required: false) </body>
and on your template :
#section scripts {
<script src="#Url.Content("~/Scripts/tinymce/jquery.tinymce.min.js")"></script>
}

Asp.net inline expression wasn't outputed in the js file

All, If I add an inline expression in the aspx page like below.
<script type="text/javascript">
var notAcceptError='<%= lblMessage%>';//the actually value is "test message"
</script>
As we know. There should exist a variable named lblMessage is defined in the code-behind file of aspx.
in this way , everything is fine.
But If I move the above code into a js file which is linked by the same page.
the output of expression failed. seems the asp.net can't recognize this expression.
I can't understand why this doesn't work in the linked external js file. In my understanding. writing in the aspx or an external js is the same. thanks.
The asp.net inline expression only work in .aspx files. It will not work in .js file because .js files served as static files and are not parsed at runtime.
If you really want to use a variable value in code-bind file into the js you can do like this.
In your aspx file do this.
<script type="text/javascript">
var notAcceptError = '<%= lblMessage%>'; //the actually value is "test message"
</script>
<%-- please note the external file is referenced after the javascript variable --%>
<script type="text/javascript" src="myjsfile.js">
</script>
And inside your myjsfile.js use the variable like this
alert(notAcceptError);
Your understanding is wrong. ASPX files are parsed and evaluated, whereas JS files are served from the server without any parsing or evaluation.

Meteor Template Inside Script Tag

I want to fill a script type="text/html tag with a Meteor template.
So, this is an odd thing to do, I know. Half the reason I want to do this is because Cloud9 can't tell the difference between JS script tags and HTML script tags, and its syntax highlighting and tag-completion breaks when you try to write HTML in script tags. The other half of me is just curious to see if this is possible, because an ugly-as-sin workaround exists.
So this:
<body>
<script type="text/html" id="test">
{{> test}}
</script>
</body>
<template name="test">
<span>Test</span>
</template>
Produces this:
<script type="text/html" id="test">
<!--label:YRgyaMH8-->
</script>
Anyone have a way to force it to render the template, instead of what looks like evaluate the name as a comment?
Submitting another answer b/c I'd like to keep my previous one just for the records. I think this approach will work better though.
Inside your html, you're going to define two sections. The first is where you're going to place your template code. It will go inside a comment inside a plain div tag. The second is where the template will be placed for Knockout to consume. It looks like this:
<template name="koTemplate">
<div id="myTemplate">
<span>Here is my template with children</span>
</div>
<script type="text/html" id="test"></script>
</template>
Then in your client JS code, you're going to add a callback to run when the template is rendered
Template.koTemplate.rendered = function () {
// Get the first node, then get the content inside of it
var templateHtml = this.firstNode.innerHTML;
// Remove the element so it doesn't get rendered
this.firstNode.parentNode.removeChild(this.firstNode);
// another option is to surround the contents inside the template w/comments, but that loses syntax highlighting
// Get the target node for placing the template in
var templateNode = this.lastNode;
// place the content from the original node to the target node
templateNode.innerHTML = templateHtml;
};
This will basically get the content of the template, remove the template, then place it inside the script tags. The result will look like:
<script type="text/html" id="test">
<span>Here is my template with children</span>
</script>
I would suggest moving away from using the script tag and instead use some other generic tag that Cloud9 won't treat as JS and Meteor won't fudge with. Using the example in my comment on the question, it would look something like this:
<div id="template">
<!--<span>test</span>-->
</div>
And in your JS you would parse that:
var template = document.getElementById('template').firstChild.nodeValue,
result = parseTemplate(template, values);
That's the basic idea. You'd have to convert it over to Knockout's template parsing after getting the result.

Resources