Strategy for combining Angular templates to reduce requests? - javascript

Background: We're in the process of porting an ASP.NET application from traditional WebForms to Web API + Angular. The app is primarily used in countries with poor internet connections, and we've found in practice that latency is a bigger issue than bandwidth. So our priority is to reduce the overall number of requests to the server, even if that means pre-loading scripts or other resources that the user might not ending up needing.
The problem: As we replace WebForms user controls (*.ascx) with Angular directives and templates, the number of little HTML template files is proliferating; so you have to make a lot of server requests for any given view, which is a big problem in a high-latency environment.
One possible approach: I'm thinking of using T4 to combine all templates used by the app into a single file that would look something like this:
myApp.templates = {};
myApp.templates.myFirstDirective = "<div> ... lots of markup here ... </div>"
myApp.templates.mySecondDirective = "<table> ... more markup ... </table>"
This file would then be requested once and cached by the browser, so subsequent page loads wouldn't require any further round trips to the server. The templates would then be available to all directives so that instead of referencing a templateUrl they just pull up the required template like this
return {
link: link,
template: myApp.templates.myFirstDirective,
... etc
}
Question: Is this a good idea? Is there a better or more Angular-native way of combining Angular templates into a single file?

Maybe using the $templateCache-Service is a possibility. Read about it here.
If I understand it right, it's basically what you were already planning, with the difference that you don't need HTML strings in your JavaScript but you can write HTML in .html files (or one big HTML file containing all Templates embedded via an ng-include in your index.html).

You could put them in the page kinda like Ember
<script type="text/ng-template" id="/template.html">
content
</script>

We are leaving those html files as they are during development, but combine them into single .js file (which we then add to our main bundle .js file), when we need an optimized build.
We use https://www.npmjs.com/package/gulp-angular-templatecache - it's literally just a few minutes setup if you already have gulp build.

What I do is define all my templates after my main html body.
Doing this also provides a way to automate the process of building a single file from different directive files
for example:
<!DOCTYPE HTML>
<html>
<head>
<script src="bower_components/angular/angular.js"></script>
</head>
<body ng-app="MyApp">
<my-directive></my-directive>
<script src="app.js"></script>
</body>
</html>
<content>
<script type="text/ng-template" id="template1.html">
<h1>Hello</h1>
</script>
</content>
My app.js:
angular.module('MyApp',[])
.directive('myDirective', function() {
return {
scope:{
},
restrict:'AE',
templateUrl:'template1.html',
replace:false
}
})
This way we can easily keep all the javascript for directive in there own files and html for these directives in there own file
And during build time we can easily merge these files so that we have only two files: index.html and app.js which means only two requests to server.

Related

Angular ng-include issues

So what am I doing wrong? I included the ng-include and tried every variation and it is not including the file(it keeps returning a 404 in the console), the directory location is as follows:
-App
--Layout
---Partials
----Navigation.tpl.html(File)
--Layout.tpl.html(File)
And the ng-include is located in the layout.tpl.html file:
<div data-ng-include="'layout/partials/Navigation.tpl.html'"></div>
Please note that I am using webpack for this project(that shouldn't matter). I am calling the layout.tpl.html file as the base layout, and the partials are included inside the layout.tpl.html file. Also, I am using vs having a ng-app on the DOM:
angular.element(document).ready(() => {
angular.bootstrap(document, ["app"]);
});
I have worked with angular in the past, and I am at a loss when such a simple task is taking so long time. Also note, when I use the
$templateCache.put('..','..')
and put in html minified string from the navigation.tpl.html with the same directory, it works just fine (but if I use $templateCache.get() or require() from the template location, it doesn't work), but the HTML string is pulling from the cache and I want to be able to update one file vs having to use minified code.
Sorry in advance if I missed something, I am in a rush to get this done, and it should be the simplest thing that is just not working.
Take a look at https://github.com/WearyMonkey/ngtemplate-loader
You should preload your template with the correct key in the $templateCache by requiring it in your bundle.
require('ngtemplate?module=[xx]&relativeTo=/layout/partials/!./layout/partials/Navigation.tpl.html');
That way you can ask for 'Navigation.tpl.html' in ng-include or with templateUrl

How I can modularize static HTML file?

I'm a front-end developer. When I write a html code I repeat my self a lot by copy and paste (header section, footer section, etc).
How I can write modularize my html files? Like separate header.html and footer.html, and after that call both in index.html... same as erb in Ruby on rails? (I don't like jade lang)
In PHP we would do something like this:
index.php
<?php
include 'inc/head.inc.php'; //DOCTYPE and <head> stuff
include 'inc/header.inc.php'; //NAV or other top-of-page boilerplate
?>
<div id="uniqueDIV">
//Your unique page-specific divs can go here
</div>
<?php include 'inc/footer.inc.php'; ?>
So, in your head.inc.php file, you just have the usual DOCTYPE and <head> portion of your page file.
In Ruby, it appears the equivalent instruction is something like:
load "inc/head_inc.rb" -- OR --
require_relative "inc/head_inc.rb"
https://practicingruby.com/articles/ways-to-load-code
Another option is to use a bit of js/jQuery to populate parts of the document. If you don't have PHP, this is 2nd best option. It's less optimal than PHP because the js/jQ code will run after the page is fully rendered, which may cause a minuscule (but noticeable) lag before the code appears.
For example:
html
<div id="navbarDIV"></div>
js/jQuery:
<script type="text/javascript">
$(function(){
$('#navbarDIV').load( 'inc/navbar.inc.html' );
});
</script>
Note that you will need jQuery loaded to use the above code. Simple as this line in your <head>:
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
jsFiddle demo
Final note: the script tag can be included in your <head> as an external file, or it can be plopped anywhere in your document with the rest of the html. Whatever works. But <head> as external file, or last element in body (also as an external file) are preferred.
Final final note: the ".inc." naming convention is not required, it's just my own practice. Include file could be named head.html or head.php or etc.
You could consider using something like Swig, which doesn't require a server (you can compile your templates locally).
Swig's syntax is much like Mustache or Handlebars, it uses braces and works inside of normal HTML, so you can retain the HTML syntax you want (unlike Jade).
For separating HTML into files to be reused, you can check out Template Inheritance. You can also see File Inclusion and File Imports.
Here is a small example:
{% include "./header.html" %}
<div id="body">Hello world</div>
{% include "./footer.html" %}
i use gulp, and i want tools for compile file to standard html file. like jade. – Sajad Abedi
For this you can use gulp-swig and build your templates locally in a task.
I have used EJS, which is convenient.
You can have a try.
For HTML files there is no standard way for reusing HTML parts. You have to use into a templating system.
But erb is a templating system and can handle that. See this Stack Overflow answer about "Including one erb file into another".

Using text.js with require.js how can I create one template html file but grab each script template individually?

I'm using require.js and text.js to load a template file that has a bunch of <script> templates in it:
e.g. /scripts/templates/comments.html
<script type="text/template" id="js-comment-reply-tmpl">
// html in here
</script>
<script type="text/template" id="js-comment-edit-tmpl">
// html in here
</script>
And because using underscore's template system (or any similar js micro-templating system), this file itself gets loaded as a string. Is there a smart way to just grab each template from within that file? e.g. $(template).html() wrap it in jQuery and then do a find() or something on it? I'd essentially have to place it into the DOM first though, so that would probably be slow as hell and I might as well just not even load it with text.js and just pluck it out of the DOM initially.
My other thought is to split them each into their own files, but then that would slow down on request time (although I'd probably just end up using r.js with node to minify this all in the end anyway so it wouldn't matter).
e.g. /scripts/templates/comment_reply.html
<script type="text/template" id="js-comment-reply-tmpl">
// html in here
</script>
e.g. /scripts/templates/comment_edit.html
// html in here
What's the best/most efficient way to do this?
I would advise moving each template into it's own file and loading them all separately. Some of the advantages of doing so are:
Easier maintainance - Searching for a template in a project is easier if they all have their own names and it also reduces hassle with source control conflicts if developers aren't all editing the same file.
Portability - If you end up using a templating system that can be used on the server (like Mustache) then the templates are already easy to share between front and back-end.
The main disadvantage that you already highlighted are the extra requests, but you should definitely not be going to production without building your scripts with r.js so this shouldn't be a problem

How to access JavaScript module pattern in my case?

I have defined the following module in MyModule.js:
MyModule.js:
MyModule = {
controller: {
paintCar: function(color){
//PAINTING PROCESS
}
},
tester: {
...
},
};
Then, I have another javascript file, other.js:
other.js:
MyModule.controller.paintCar('red');
My index.html
<body>
<script scr="MyModule.js"></script>
<script src="other.js"></script>
</body>
All these files are put under WebContent directory of Eclipse Dynamic Web Project.
In other.js when I try to run the above code, I got error "MyModule is not defined". Why?
You misspelt src here: <script scr="MyModule.js">. This would have been picked up by basic automated QA testing.
(Original answer before the theory was confirmed) Presumably, because you aren't loading the script files properly. Since you haven't shown us the code that does that (or even told us what environment you are using) it is hard to say exactly how you went wrong.
Assuming you are using client side JS in a webpage, your code should look something like:
<script src="MyModule.js"></script>
<script src="other.js"></script>
Order is significant. End tags are mandatory. Self-closing tag syntax is unacceptable (unless the document is served as application/xhtml+xml)
(This uses HTML 5 syntax. For HTML 4 / XHTML 1, add a type attribute. For HTML 3.2, add a language attribute)
You haven't mentioned your environment, but generally you have to ensure that the JavaScript in MyModule.js is executed before the JavaScript in other.js, because you need MyModule.js to set up the MyModule variable.
How you do it will vary by environment. In a web browser, you'd do that by putting in two script tags, first one for MyModule.js then the one for other.js (although frequently, for use on websites, you want to have a build process that combines your scripts into a single file to minimize HTTP requests). In NodeJS, there's the whole require mechanism.
Update based on your edit:
Looks like a typo:
<body>
<script scr="MyModule.js"></script>
^^-- here, they're transposed
<script src="other.js"></script>
</body>
If that typo isn't really in your file, then look to see that the files are where the web server expects, that the web server isn't being thrown by capitalisation, that sort of thing. Fundamentally, that's correct.

How to encapsulate a reusable "control" for ASP.NET MVC 3 + Razor views

I am looking for best practices on how to create a reusable "control" for use on several MVC 3 views. I could make an Html helper extension method (programmatically or with the declarative helpers in razor) or I could create a partial view.
The trick, in my case is that I need to do more than just dump some HTML in precisely the spot that the view calls the helper/partial. In addition to putting some HTML markup in that spot, I also need to add some javascript code to make it work. Normally, I would put this code elsewhere in the page (e.g. the bottom). This is of course strictly not required. Also, note, the javascript is not control instance specific. In other words, it is possible to write javascript that finds all instances of the control HTMl markup on a page and "activates" it with appropriate events, etc.
I have thought of several possibilities.
Have the helper/partial dump out the HTML and a <script> tag right in the place it is called. This seems like a bad idea since it means the control could only be used once per page.
Have two helpers. One to output the HTML markup, and a second that spits out the javascript. The second would be called only ever once and would be called from the bottom of the page so that the script ends up in the right place. If I invented a second control that was like this, I would have 4 helpers (2 for HTML, 2 for Javascript).
Invent some kind of ScriptManager that controls can register javascript with. The scriptmanager would have some kind of helper that would be added to the bottom of pages and would dump out the javascript for all controls that had registered some snippet of script. The call to the scriptmanager helper could be in the _layout.cshtml so that it automatically happens on any page that needs it. It would do nothing when a page didn't need it. This doesn't seem very MVC-ish, I guess.
Just have a helper that spits out the HTML and then add the javascript to the site.js that is included on every page. The javascript would be smart enough to not do anything if it could not find any relevant markup on the page (markup would have a wrapper element with a particular class). There would be overhead of this search for markup on all pages though, including pages that don't have any of these controls.
Same as #4, but put the javascript in its own .js file and include it only on pages that use the control. This is more efficient for pages that don't use the control, but it is an additional .js file and associated HTTP request for pages that do.
I am leaning towards #4, but is this a solved problem? Is there a better, 6th option?
My company is employing MVCContrib portable areas to package the code into a DLL for reusable "components"
Each of these components can be called via an extension method. For example:
Html.Components().ShowPoll();
Within each of these components, there is a way to register multiple css/js files that are embedded resources. Our main site will extract the resource files and minify + combines them before serving it.
The component will also register any on page event that will be called during the Document.OnReady event of JQuery. This allows each of the components to be mini-sites, standalone functionality with its own routes, models, and views.
Across the entire site, the same zip up JS for all the components are served. One because the file will be cached, and two - removes the complexity of determining what components are on the page and the resources it needs.
Let me know if you want more information regarding this setup.
I managed this issue with a layout page that had a section called jsCode.
#RenderSection("jsCode",false)
Then when I need it, I create in the content page:
#section jsCode
{
<script type="text/JavaScript" src="myJsCode.js"></script>
}
you could also create a helper that spits out the scripts you need for a particular page and encapsulate it that way, like this:
#helper MyJSFunction(string FunctionName){
switch(FunctionName)
{
case "firstFN":
<text>
<script type="text/JavaScript">
function SaySomethingSilly()
{
var sillySaying="We are the knights who say 'ni'!";
alert(sillySaying);
}
</script>
</text>
break;
case "secondFN":
<text>
<script type="text/JavaScript">
function SaySomethingElse()
{ var sillySaying="We are looking for a shrubbery...";
alert(sillySaying);
}
</script>
</text>
break;
}
}
Then my content page (assuming I want both functions) looks like this:
#{
Page.Title="Using helpers to create scripts";}
#section jsCode
{
#JSHelpers.MyJSFunction("firstFN")
#JSHelpers.MyJSFunction("secondFN")
}
<p>It works!</p>
which produced the output:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Using helpers to create scripts</title>
<script type="text/JavaScript">
function SaySomethingSilly()
{
var sillySaying="We are the knights who say 'ni'!";
alert(sillySaying);
}
</script>
<script type="text/JavaScript">
function SaySomethingElse()
{ var sillySaying="We are looking for a shrubbery...";
alert(sillySaying);
}
</script>
</head>
<body>
<p>It works!</p>
</body>
</html>
Now if you wanted to get super-efficient, (though other words come to mind) you could pass the function a JSON array or a dictionary or even a string array with the names of the scripts you wanted to use, or the JavaScript to import, or whatever, and just use a single call to the helper. I think separate calls is easier to maintain, regardless of how you load the return values of the helper function, because you can see cleanly at a glance which scripts you are using on a given page, and to eliminate or add one is a simple one-line change rather than changing one element of an array.
As always, your mileage may vary, but I ran the sample based on this code in WebMatrix Beta 2 without any issues.
Lisa Z. Morgan
http://www.lairhaven.com

Categories