Nodejs EJS partials with scripts in the head - html

I'm working with EJS to render and server HTML pages from a Nodejs server. Some of the partials I include have scripts and stylesheets referenced in the head, but this causes the client to make multiple requests for the same file (for example if the parent view also includes that file)
For example:
<!-- file: parent.ejs -->
<html>
<head>
<link rel="stylesheet" href="public/mystylesheet.css">
<script src="public/myscript.js">
</head>
<body>
<%- partial("partial.ejs") %>
</body>
</html>
And in the partial:
<!-- file: partial.ejs -->
<html>
<head>
<link rel="stylesheet" href="public/mystylesheet.css">
<script src="public/myscript.js">
</head>
<body>
This is an EJS partial!
</body>
</html>
In this case, "mystylesheet.css" is loaded by the client twice (unnecessarily), and so is "myscript.js"
Is there an easy way (preferably using EJS) to make sure that a stylesheet or script is included when a partial requires it, but not if the parent view already has included the resource?

I found a fairly good solution to this problem, which basically boils down to using an EJS variable to keep track of resources included as the EJS document is rendered. Here's a shortened example below, that only works for script tags (but can easily be extended to stylesheets or anything else)
A partial that helps with the inclusion of resources:
//file: "include.ejs"
<% for (var i in scripts) { %> //scripts an arr of js files to (maybe) include
<% if (!resources[scripts[i]]) { %>
<script src="<%= scripts[i] %>"></script>
<% resources[scripts[i]] = true %>
<% } %>
<% } %> <!-- end for -->
And a file that uses this partial to include scripts
//file: "somepartial.ejs"
<html>
<head>
<%- partial("include.ejs", {
scripts: ["lib/jquery.js", "lib/bootstrap-tabs.js"]
}) %>
</head>
<body>
<!-- MY EJS PARTIAL! -->
</body>
</html>
And when rendering the partial:
response.render('somepartial.ejs', {
resources: {},
/* some other variables */
});
This way, you can be sure that a script is included by a partial, but not unless it was already included somewhere in the rendered HTML page
A limitation
There is one limitation that I came across: If you load part of your page with an AJAX request like
$("#someDiv").load("/another/part/of/the/page.html");
Then the resources included with the AJAX-loaded portion of the page won't be aware of the scripts already loaded (unless you pass that information in a REST argument, like I'm doing):
$("#someDiv").load("/another/part/of/the/page.html?resources={...}");
Of course, with this little fix, any two parts of the page that are loaded with an AJAX call may request the same resource, and there's no way for them to know that since they are only aware of what the parent document has had loaded (hope that makes sense)

Related

Is there a way to insert HTML code into a document that is comparable to the simplicity of inserting css/js code?

I know that it is best practice to have separate files for CSS and JS so that this:
<head>
<style>
<!--CSS code -->
<!--CSS code -->
</style>
</head>
<body>
<!--HTML code -->
<!--HTML code -->
<script>
<!--JS code -->
<!--JS code -->
</script>
</body>
becomes this:
<head>
<link rel="stylesheet" type="text/css" href="my-blackjack-file.css">
</head>
<body>
<!--HTML code -->
<!--HTML code -->
<script src="my-javascript-file.js"></script>
</body>
But is there an equally simple way to do this for the html portion of the code for the sake of better organization? I have seen some suggestions online for including html pages, but they seem to be talking about iframes and use some fairly complex (for me) javascript. Is there something more akin to
<body>
<link rel="stylesheet" type="html" href="my-html-file.html">
</body>
in order to separate a long document into several files that run as if they were on the same page?
This is work in progress and may (or may not) be supported in the next version.
Until then, unless you output the HTML through some server-side technology such as JSPs or Velocity, which support templating, you can only use iframes or AJAX as a workaround for including HTML.
Depending on the development environment you can use partial views.
<body>
#Html.RenderPartial("descriptiveNameHere.html");
<script src="my-javascript-file.js"></script>
</body>
Or something to that effect. There is additional syntax of course, but maybe this will put you on the track you're looking for.
Ultimately you will still have an html file with your "HTML Code". But if you're looking to reduce the complexity of a large file by moving chunks into external files, partial views are a way to do so.

How to load external JS libraries for the whole project

How do you load an external library so that it is available all over the project?Say for example I have the below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Starter Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="../public/css/bootstrap.css" rel="stylesheet">
<!-- Font Awesome core CSS -->
<link href="../public/css/font-awesome.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="../public/css/style.css" rel="stylesheet">
</head>
<body>
<p>This is a test</p>
<!-- Bootstrap core JavaScript-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
<script src="../jsLib/bootstrap.js"></script>
</body>
</html>
So this includes the jQuery, Bootstrap, font-awesome and my personal stylesheet as you can see.
Question: What if someone goes to another page in my site for instance: /profileSettings.html
Will I have to load all the libraries again?
Sorry if this is a simple question but I am completely new to front-end development.
Thanks in advance
As your code grows in size, you'll start using more sophisticated frameworks that may use something along the line of an MVC setup. Some of these frameworks allow you to define multiple "views"(think of them as HTML files for now) that are called from a single HTML file(say the index file).
For those aware of AngularJS, i'm referring to writing Angular UI views and the <ui-view> tag.
This will allow you to have your dependencies in a single file, and the other pages just load from this page.
More importantly.
I'm surprised noone has mentioned the use of require-js or other loaders.
It's particularly useful in cases where you have multiple JS dependencies, and multiple controllers in javascript.
Definitely check out loaders such as require-js
Each page is completely independant of every other page.
If you want a script to run on any given page, it has to be explicitly loaded into that page.
Yes. U have to include the required lib in each file if it is normal file without any framework.
You have to include the scriipt in every page because even thought it is a website, every page works seperately from another. All you need is a <script></script> tag.
Yes, if you look each page as separate page. You need to include it in every page.
But if you have a master page, then we can inherit the same from master page so, no need to add the Codes/Script again.
A cool option.
Load one JavaScript file (JS File) for every page. Then load all the JS File using that JS File as you like.
Example
var Device = {
Device_Type: 'Desktop',
//Scripts to be loaded in master page
Common_Scripts: [
'/SiteAssets/Bar.js',
],
//CSS to be loaded in master page
Common_CSS: [
'/SiteAssets/nav.css',
],
//to get device type
Get_Device_Type: function () {
var Getdevice = detect.parse(navigator.userAgent);
if (Getdevice.device.type != null) {
Device.Device_Type = Getdevice.device.type;
Device.Process_Device_Files(Device.Device_Type);
Device.Process_Common_Files();
Device.Process_Common_Scripts();
} else {
console.log("Detected Device type :" + Device.Device_Type)
}
},
//to load device based css files
Process_Device_Files: function (File_Type) {
File_Type = File_Type.toLowerCase();
$('head').append(
'<link rel="stylesheet" title="' + File_Type + '" href="announcement.css">'
);
},
//To load css files to be loaded in master page
Process_Common_Files: function () {
_.each(Device.Common_CSS, function (eachfile) {
Common.appendfile("css", eachfile);
});
},
//To remove previously loaded device files
Remove_Device_Files: function () {
$('link[title="tab"]').remove();
$('link[title="Mobile"]').remove();
$('link[title="desktop"]').remove();
},
//To load scripts to be loaded in master page
Process_Common_Scripts: function () {
_.each(Device.Common_Scripts, function (eachfile) {
Common.appendfile("script", eachfile);
});
},
}
$(document).ready(function () {
console.log('Render device based files')
Device.Remove_Device_Files();
Device.Get_Device_Type();
});
Usage
(Copy the Above code after Example until usage and paste it into a notepad and save it as device.js. Then include to the page. Then add the necessary JS to this codes. Sample files are already in the codes)
// Dependencies
https://github.com/darcyclarke/Detect.js?files=1

How to have a common header shared by all webpages in AngularJS?

I would like to have a header.html which defines how the header for all my web pages will look like. How can I insert this header.html into the other web pages at the top?
There may be better methods around to achieve a common header to be shared around. As I still consider myself a newbie to html (but not to programming), I am open to better suggestions.
Thank you.
EDIT: Helpful replies have mentioned using PHP. However, I am using AngularJS as front-end and my PHP backend is simply a pure REST server. My preference is to do it the AngularJS way and not the PHP way.
An AngularJS solution would look like this:
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<script src='angular.js'></script>
<script src='main.js'></script>
</head>
<body>
<div ng-controller="HeaderCtrl">
<div ng-include src="header.url"></div>
<script type="text/ng-template" id="header.html"></script>
</div>
</body>
</html>
main.js:
var myApp = angular.module('myApp', []);
function HeaderCtrl($scope) {
$scope.header = {name: "header.html", url: "header.html"};
}
header.html:
<p> Header content goes here </p>
The reason I did not simply advise a solution such as: <div ng-include="'header.html'"> is to avoid any delay in loading the header. For more information have a look at angularjs - Point ng-include to a partial that contains a script directive.
Alternatively a jQuery would like this.
<html>
<head>
<script src="jquery.js"></script>
<script>
$(function(){
$("#headerContent").load("header.html");
});
</script>
</head>
<body>
<div id="headerContent"></div>
</body>
</html>
Finally a PHP solution would look like this:
<html>
<head>
</head>
<body>
<?php include('header.html'); ?>
</body>
</html>
Best of luck learning!
The way I typically handle this, and it allows for more than a header, is to have a shell.html
It might look like this:
<div ng-controller="ShellController">
<div ng-include="'app/shell/header/header.html'"></div>
<div ng-view></div>
<div ng-include="'app/shell/footer/footer.html'"></div?>
</div>
Where you're ng-including the static bits, and you're using Angulars ngRoute (or ui-router)
The other answers provided miss the point here of the client using Angular.js. Angular is actually designed for this concept. There are a couple different ways to achieve client templates with Angular.js.
Using Angular as a Single Page Application (SPA) where you dynamically change the content on a single HTML document rather than redirecting to different pages.
Using Angular Directives to encapsulate common page features.
You can use a combination of the 2 to achieve almost any combination of page layout.
using the angular route provider or a plugin like Angular UI-Router you can define a common HTML page, and within the HTML page use the ng-view directive to denote a section of your page to be dynamically replaced at runtime. you can then define html templates which populate the dynamic section.
Using Directives, you can create new HTML elements to design a more expressive page layout. For example, you could define a my-menubar directive containing HTML templates, javascript elements, even business logic, and then include the menubar on any page simply by using a syntax like <div my-menubar /> Directives are very powerful, and I highly recommend reading about them in the Angular Developer Guide.
An example of a simple page that might use these features:
<div ng-controller=MainController>
<div main-menu />
<div ng-view> </div>
<div page-footer />
</div>
Bottom line, you do not need a server to perform logic for reproducible code, as Angular.js is designed for exactly this purpose.

Rails reading in and rendering seperate html doc, need <base> to only apply to the read in html

I am writing a mobile web application using Rails and jQuery mobile. I am reading all of my data at runtime from Amazon AWS S3 using HTTParty.
One of the screens that I need to render is just straight html, which can and usually does have images embedded into it which are hosted in the same folder on S3. This is where my problem is. I can easily pull in the html with HTTParty and use the html_safe option to render it, but the images don't render as they are relative path names. So I have been trying to find a way around this.
I have tried multiple things, but I have mainly been looking into using an html tag to get the images to point to the right location. The problem is that I cant specify a base tag and then have other links on the page, because they then use that same base and the links are not pointing atand the correct location. So I looked into framesets and frame and pointing the base tag only at the frame, which I believe I used correctly, but to no avail. I tried using but to no avail.
So basically I am looking for a way that I can set the base for relative path names in an html string that I read in from S3, if that wasn't clear. I am open to any suggestions! And thanks in advance for even reading and try to solve this very specific problem!
Oh and one more thing, when I look at the page with Firebug, the first line in the header is a base tag with href set to the current page. I can't find out where it is coming from but I am guessing rails is throwing it in there? I don't know if this matters since I then put another base tag below it with the yield :intro_base? Or is that one of my problems since there is a conflict there?
And then there was code:
My 'intro' method:
def intro
#intros = []
#app_config.intro_screens.each do |intro_screen|
intro_screen_response =
ApplicationController.get("#{#diandr_url}/#{intro_screen['filename']}.html")
#intros << intro_screen_response.body
end
#intros.reverse!
#intros_length = #intros.length
respond_to do |format|
format.html
end
end
My 'intro.html.erb' file:
<% page_num = params[:id].to_i %>
<% content_for :intro_base do %>
<base href="https://s3.amazonaws.com/our_bucket_name<%=#dir_url%>/" target="intro" />
<% end %>
<% content_for :mobile_header do %>
*some jQuery mobile paging and header stuff is in here, shouldn't matter*
<% end %>
<% content_for :mobile_content do %>
<!-- <iframe src=<%= #intros[page_num] %> height="100%" width="100%"> -->
<!-- <p> This browser does not support iframes </p> -->
<!-- </iframe> -->
<frameset cols="100%">
<frame name="intro" <%= #intros[page_num].html_safe %>
</frameset>
<% end %>
My layout's header:
<head>
<title> our Mobile App </title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- These are the jQuery Mobile scripts -->
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js">
</script>
<%= yield :intro_base %>
<%= stylesheet_link_tag "master" %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>

Aptana studio 3 automatically includes html markup in rhtml files

I am learning ruby on rails using aptana studio 3. I created a view hello.rhtml. When i run the view and see the source i get to see js files automatically included. Even if my rhtml file is empty for eg
hello world
Without the html markup, and if i see the source, i can see the entire markup from html doctype etc already present. How do i stop the inclusion of automatic markup?
Thanks
EDIT :
OK i create a hello.html.erb file. And put this code inside it
Hello
When i save and run the file, i get the output, but when i view source i get the following result.
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<script src="/javascripts/prototype.js?1312799421" type="text/javascript"></script>
<script src="/javascripts/effects.js?1312799421" type="text/javascript"></script>
<script src="/javascripts/dragdrop.js?1312799421" type="text/javascript"></script>
<script src="/javascripts/controls.js?1312799421" type="text/javascript"></script>
<script src="/javascripts/rails.js?1312799421" type="text/javascript"></script>
<script src="/javascripts/application.js?1312799421" type="text/javascript"></script>
<meta name="csrf-param" content="authenticity_token"/>
<meta name="csrf-token" content="82LBP1pI5h0QzNW54PYSq/zdkS8kF4Z/nKSUHgKvv1g="/>
</head>
<body>
<html>
<head><title>Hello</title></head>
<body>
</body>
</html>
</body>
</html>
SO if you see, i get html inside html and when in browser my title shows "Demo" instead of "Hello"
UPdate :
Here is the content of application layout. And i now understand that, the code is coming from this layout.
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
</head>
<body>
<%= yield %>
</body>
</html>
I am new to this, so what is the best practice and what code should be present in application_layout.html.erb. I would like all my view files to have its own html code.
Thanks a lot
Your view should have .html.erb extension not rhtml (That's a hang over from Rails 1.x).
Check out your application layout file. in the head section you'll see an entry for including javascript. Just comment that out and you js will not be included.
Which just leaves me with a question. What's the actual problem with what you have? Why does it bother you? Perhaps the answer to this will get you to the right question in order to find a more appropriate solution.
UPDATE
Have a close look at your application_layout.html.erb.
Can you post the contents of that?
This is not an error, this is the way Rails works!
Rails will generate views/layouts/application.html.erb for you, this is the basic template of the website. With this template, you don't have to copy and paste the same html declarations on each page you make.
Rails uses a convention called MVC which stands for Model, View, Controller. I suggest you read a bit more on how this works. Basically, <%= yield %> will insert the contents of your view, but you must tell Rails which url points to which view. Now you can have views/pages/home.html.erb, the contents of which might be..
<h1>Home Page</h1>
<p>Congratulations, you made a web page with Rails!</p>
And then in routes.rb
YourApp::Application.routes.draw do
match 'home' => 'pages#home'
end
When you go to http://localhost:3000/home, you should see your web page. If you look at the source code, you will see the output generated by Rails.
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
</head>
<body>
<h1>Home Page</h1>
<p>Congratulations, you made a web page with Rails!</p>
</body>
</html>
This is definitely the proper way to use Rails. The goal is DRY (Don't Repeat Yourself). Michael Hartl has a wonderful tutorial and introduction to using Ruby on Rails. I would suggest anyone new to Ruby on Rails to start here: http://ruby.railstutorial.org/. If you have any questions about using Ruby on Rails or web design in general, I'd be happy to help. You can email me at draco#dragonstarwebdesign.com. Cheers and good luck to you!