I will be developing a large, AMD-based javascript application, structured with backbone.js and potentially require.js. I am doing research on the best way to go, and one thing I would like to get into using is a template library, particularly handlebars.js.
My problem here is that I want to make javascript-only modules that can be loaded and implemented on the fly, well after the application is loaded. Templates are based on HTML tags, but I don't want to include html pages after the fact.
My question is: Is it stupid, or valid practice to mock up HTML templates as strings in your javascript, and then render them? I feel like it would kill the entire point in performance alone, but I really don't know.
This is an example of what I am talking about:
var render = function(html, model) {
var tmpl = Handlebars.compile(html);
return tmpl(model);
}
$(document).ready(function() {
var template = '<div class="entry">' +
'<h1>{{title}}</h1>' +
'<div class="body">{{body}}</div>' +
'</div>';
var model = {
title: 'I love templating,',
body: 'And so do you!'
}
template = render(template, model);
$(document.body).append(template);
});
Is this terrible practice, or is there a better way to implement this in a javascript-only application?
Template are used to separate html from javascript code.
I suggest you to look at requireJS text plugin to load your template code in an AMD environment.
Related
Is there a standard workaround for something like this in ASP.NET:
//myinclude.js
$(document).ready(function() {
for(recs=0; recs < {{server-side-value}}; recs++) {
// process records
}
});
Note this is a js file. I know about WinForms ability to insert dynamic quoted scripts into the page. But how about a page's js file that is dependent on server-side values? I know you can use something like:
//myview.cshtml
var instance = new MyObject(<%= ServerSideValue =%>);
and include it on the page to pass it to the js file, but I'm wondering about the architecture of keeping js separate from html code so that an html/css designer can work with the template free of javascript; keeping everything separate. I primarily use MVC now.
What are some of the patterns to deal with this? Is the only solution dynamically inserting js into the actual page or having partial views included separately into the page.? Or is there a way to sprinkle server-side values in separated js? In short, no dynamic js files?
I'm not trying to fix an exact project at this time, I have just been curious about this on past projects.
Thanks...
There are multiple ways to achieve this. One of the ways would be populating your data into a Javascript objects on the HTML page directly.
//myview.cshtml
<script>
var pageData = {
name : '#variable1',
value1: #value1
};
</script>
And, in the javascript file:
//pageUI.js
if (pageData) {
$('#page_tile').html(pageData.name);
}
I am sure you can optimize a whole lot (for example, having a single communication between the server side data and the client side code). At the end of the day, you want to make sure that your javascript code can be resusable.
for example one can do this:
A. have the main .js code read any context-specific parameters from the current window like this (page.js):
!function(window){
var configData = window.MyAppNameConfigData;
// rest app code here..
}(window);
B. the server side script can inject these context-specific data in the page's html like this:
<script>
window.MyAppNameConfigData = {
param1: //..
param2: //..
// etc..
};
</script>
Note if needed make sure that the page.js is enqueued/loaded after the data have been injected/inserted (using a script dependency chain for example)
If it's not "inline" (on the View/Page itself), you could do a Partial View/Page:
Trivial example: _PartialJs.cshtml
$(document).ready(function() {
var foo = "#DateTime.Now.Year";
});
Then in your view:
<script>
#Html.Partial("_PartialJs")
</script>
Renders:
<script>
$(document).ready(function() {
var foo = "2015";
});
</script>
Hth...
I know how to precompile my Handlebar templates when I externalize them by having them in a separate file. Lately, I have been shortening my templates and using them inline. For example I have the following Backbone View.
var ChosenVehicle = Backbone.View.extend({
className: "car selection",
initialize: function(options) {
this.data = options.chosenData;
},
template: Handlebars.compile(
'<h4 class="number">01</h4>' +
'<img src="assets/img/cars/{{vehicleSlug}}.jpg" alt="{{vehicle}}">' +
'<p class="flush">' +
'<small class="text--center caps">' +
'{{vehicle}}' +
'</small>' +
'</p>'
),
render: function() {
var chosenCar = _.find(this.model.get("cars"), function(car) {
return car.id.toString() === this.data.vehicleId;
}, this);
this.$el.html(this.template(chosenCar));
return this;
}
});
What are the performance ramifications using the above and not precompiling the templates? I prefer to have my templates setup above as I find it much easier to read and maintain. Now obviously I am unable to precompile my template, or is there another solution?
Thanks
Tyrone
Well, you may think this is easier to read and maintain, but it's not. You don't want to open a javascript file to edit your templates/markup; just as you don't want to open CSS to debug Javascript (remember expression()?).
The idea is to precompile your template through your build system. This can be easy if you load your template via a requireJs loader plugin; e.g.:
template: require("hbs!templates/listItem")
You can also checkout how Backbone Boilerplate does it right now: https://github.com/tbranyen/backbone-boilerplate (Although, we spoke about going the requireJs plugin road in the near future)
Checkout Github-Viewer for a working example of Backbone Boilerplate templates loading/precompiling: https://github.com/tbranyen/github-viewer
I am new to Node.js and EJS. "Static Caching of Intermediate JavaScript" is mentioned as one of the features of EJS.Can anybody explain what it exactly means.
Regards,
Kar
Let's say you have a template, like so:
<h1><%= name %></h1>
Internally, this will compile to something along these lines (very simplified):
function(params) {
return '<h1>' + params.name + '</h1>';
}
That javascript function is really fast to execute, compared to parsing the template over and over again. EJS will cache the function internally, if you call it with the cache option. Thus, it will not have to compile the template each time it is rendered.
I have created a sizable application javascript and jQuery. However my file structure is getting a bit messy!
At the moment I have one large JS file with a if ($('#myDiv').length > 0) { test at the top to only execute the code on the correct page, is this good practice?
There is also a mixture of plain JS functions and jQuery extensions in the same file e.g $.fn.myFunction = function(e) {.
I also have a few bits of code that look like this:
function Product() {
this.sku = '';
this.name = '';
this.price = '';
}
var myProduct = new Product;
Basket = new Object;
My question is for pointers on good practice regarding javascript and jQuery projects.
The code if ($('#myDiv').length > 0) { is not good practice. Instead, make your page specific JS as functions and execute them in the corresponding page . Like this:
var T01 = function(){
// JS specific to Template 01
};
var T02 = function(){
// JS specific to Template 02
};
HTML head of Template 01:
<script type="text/javascript"> $(T01); </script>
Consistency is the golden rule.
You can discuss design patterns back and forth, but if you want to have easily maintainable code where new people can come in and get an overview fairly quickly, the most important part, whatever design patterns you chose, is to have a consistent code base.
It is also the hardest thing to do - keeping your codebase clean and consistent is probably the hardest thing you can do as a programmer, and especially as a team.
Of course the first tip I can give you is to separate the jQuery extensions in their own source files. You can always serve everything together with a minification tool, so you should not worry about performance.
About the code youo mention, it could be simplified to
var Product = {
sku: '',
name: '',
price: ''
}
var myProduct = objectCopy(Product);
var Basket = {};
provided you write a simple objectCopy function which loops through the object own properties and just copies them to a new object (you can make a shallow or a deep copy, according to your needs).
Finally, if you think your code is starting to get messy, you may want to learn some patterns to organize JS code, like the module pattern. Alternatively, if you are familiar with doing this on the backend, you may want to organize your application following the MVC pattern. personal advertisement - I have written myself a tiny library which helps organize your code in this fashion. There are also many other libraries for the same task, often adding other functionality as well.
If you follow the MVC pattern, your page will actually correspond to some action in some controller, and you could just start it with a call like
<script>someController.someAction()</script>
in the head of your document, hence removing the need for the manual check for #myDiv. If you use my library MCV, it will be enough to declare your body like
<body class="mcv:controller/action">
and start the application with
$(document).ready(function() {
mcv.autostart();
});
Yes it's good practice to put as much of your code into a seperate JS file as this could then be compressed before transmission and hence speed up download time. However no you should not have code that looks like
if ($('#myDiv').length > 0) {
on every page. Split your JS code up into manageable functions and call those as-and-when you need to.
I don't see a problem with mixing JS and jQuery functions up in the same file.
i've been playing with MVC for a while now, but since the project i'm on is starting to get wind in its sails more and more people are added to it. Since i'm in charge of hacking around to find out some "best practice", i'm especially wary about the possible misuses of javascript and would like to find out what would be the best way to have our views and partial views play nicely with javascript.
For the moment, we're having code that looks like this (only simplified for example's sake)
<script type="text/javascript">
function DisableInputsForSubmit() {
if ($('#IsDisabled').is(':checked')) {
$('#Parameters :input').attr('disabled', true);
} else {
$('#Parameters :input').removeAttr('disabled');
}
}
</script>
<%=Html.SubmitButton("submit", Html.ResourceText("submit"), New With {.class = "button", .onclick = "DisableInputsForSubmit(); if ($('#EditParameters').validate().form()) {SetContentArea(GetHtmlDisplay('SaveParameters', 'Area', 'Controller'), $('#Parameters').serialize());} return false;"})%><%=Html.ResourceIcon("Save")%>
Here, we're saving a form and posting it to the server, but we disable inputs we don't want to validate if a checkbox is checked.
a bit of context
Please ignore the Html.Resource* bits, it's the resource management
helpers
The SetContentArea method wraps ajax calls, and GetHtmlDisplay
resolves url regarding an area,
controller and action
We've got combres installed that takes care of compressing, minifying
and serving third-parties libraries and what i've clearly identified as reusable javascript
My problem is that if somebody else defines a function DisableInputsForSubmit at another level (let's say the master page, or in another javascript file), problems may arise.
Lots of videos on the web (Resig on the design of jQuery, or Douglas Crockford for his talk at Google about the good parts of javascript) talk about using the namespaces in your libraries/frameworks.
So far so good, but in this case, it looks a bit overkill. What is the recommended way to go? Should i:
Create a whole framework inside a namespace, and reference it globally in the application? Looks like a lot of work for something so tiny as this method
Create a skeleton framework, and use local javascript in my views/partials, eventually promoting parts of the inline javascript to framework status, depending on the usage we have? In this case, how can i cleanly isolate the inline javascript from other views/partials?
Don't worry and rely on UI testing to catch the problem if it ever happens?
As a matter of fact, i think that even the JS code i've written that is in a separate file will benefit from your answers :)
As a matter of safety/best practice, you should always use the module pattern. If you also use event handlers rather than shoving javascript into the onclick attribute, you don't have to worry about naming conflicts and your js is easier to read:
<script type="text/javascript">
(function() {
// your button selector may be different
$("input[type='submit'].button").click(function(ev) {
DisableInputsForSubmit();
if ($('#EditParameters').validate().form()) {
SetContentArea(GetHtmlDisplay('SaveParameters', 'Area','Controller'), $('#Parameters').serialize());
}
ev.preventDefault();
});
function DisableInputsForSubmit() {
if ($('#IsDisabled').is(':checked')) {
$('#Parameters :input').attr('disabled', true);
} else {
$('#Parameters :input').removeAttr('disabled');
}
}
})();
</script>
This is trivially easy to extract into an external file if you decide to.
Edit in response to comment:
To make a function re-usable, I would just use a namespace, yes. Something like this:
(function() {
MyNS = MyNS || {};
MyNS.DisableInputsForSubmit = function() {
//yada yada
}
})();