node.js express rendering inside included js files - javascript

Lets say I have a simple view
<html>
<head>
<title>something</title>
</head>
<body>
<%= param %>
</body>
<script type="text/javascript" src="myscript.js"></script>
</html>
And here's myscript.js
$(function() {
var p = <%= param %>
}
Can I make express rendering engine (in this case ejs) render inside myscript.js ?

I don't believe express will touch your static files. You could make this a view that gets rendered and served from a route, as in:
app.get('/js/myscript.js', function(req, res) {
res.render('myscript');
});
With regex routes, you could do this with anything ending in .js. (Before anyone downvotes, note that I said could, not should.)
You probably would be better off with static javascript being served to the browser that uses JSON data served from Express, though.

Related

How to use external javascript file into an ejs file

I'm working in a new web portal. So far using the express and node.js i have a server and some ejs files.
The body structure of my site is like this:
- node modules
- public
--javascript
---myScript.js
-views
--pages
---index.ejs
---about.ejs
--partials
---footer.ejs
---head.ejs
---header.ejs
package.json
server.js
server.js
var express = require('express');
var app = express();
app.set('view engine', 'ejs'); // set the view engine to ejs
app.get('/', function(req, res) {res.render('pages/index');}); // index page
app.get('/about', function(req, res) { res.render('pages/about');}); // about page
app.listen(8080);
console.log('Portal is listening to port 8080 ');
and the index.ejs
<html lang="en">
<head>
<% include ../partials/head %>
</head>
<body class="container">
<header>
<% include ../partials/header %>
</header>
<main>
<div class="jumbotron">
<h1>MyPortal</h1>
<button>Press</button>
<% var test = 101; %>
</div>
</main>
<footer>
<% include ../partials/footer %>
</footer>
</body>
</html>
In the partials i want to call and use an external .js file /public/javascript/myScript.js so i can use variable from it in my ejs page or send a variable.
my js file have a simple function (just to see if it's working) that print in console if the button (in index.ejs) is pressed.
myScript.js
$(function() {
$("button").on("click", function () {
console.log("button pressed");
});
});
I'm trying to call the external js in head.ejs (or in index.ejs)...
<!-- views/partials/head.ejs -->
<meta charset="UTF-8">
<title>MyPortal</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<style>body { padding-top:50px; } </style>
<script type="text/javascript" src="/pubic/javascript/myScript.js"></script>
but i'm getting this error (in console)
Loading failed for the <script> with source “http://localhost:8080/pubic/javascript/myScript.js”.
Any idea why this happens and how to solve it?
Since you are trying to load client-side JavaScript, the fact you are using EJS is irrelevent. A standard HTML script element is all you need in the template, and you have that.
You do, however, need to provide a URL (with the src attribute) that the web browser can use to fetch the script … and your script has no URL.
You are getting the message Loading failed for the with source “http://localhost:8080/pubic/javascript/myScript.js”. because it is a 404 Error.
You should use the static module to provide the JS file with a URL.
app.use("/public", express.static('public'))
Add this to your server.js file,
app.use(express.static(__dirname + "/public");
And to link the js file with your ejs file,

How to access external javascript files through jinja[Flask]?

I wanna know whether i can access external javascript files through jinja?
It's working well with html files or with js embedded in html files but not when javascript file is external.
code:
#app.route('/')
def default():
return render_template('main.html', var1 = 1, var2 = 2)
main.html code:
<html>
<body>
<p>The first value is {{var1}}</p>
<script src="main.js"></script>
</body>
</html>
main.js file:
window.onload=function(){
console.log('{{var2}}');
};
now the jinja code in main.js is not working
Maybe it's not possible to use it in external js?
If someone can help, please reply to this thread.
You need to understand how Jinja works. When you run the commmand
return render_template('main.html', var1 = 1, var2 = 2), it gets processed in the following way:
The Flask server opens the main.html template
Renders/replaces all the defined Jinja variables i.e. the context into the template
Sends the rendered HTML to the client.
Hence the variables are not loaded into the {{ var }} place-holders on the client side but at the server side.
Therefore to achieve what you are trying to do you could do something as follows:
In main.html code:
<html>
<body>
<p>The first value is {{var1}}</p>
<script>var var2 = {{var2}};
<script src="main.js"></script>
</body>
</html>
In main.js code:
window.onload=function(){
console.log(var2);
};
Note: We have added the script inside HTML code before calling main.js which the dependent script.
Let me know if this solves your issue and you have understood the explanation.
TLDR; Pass your flask variable to a global JS variable from your HTML file.
I don't think that it's possible to access external JavaScript files directly from Flask. But you can use this hack, it works with many templating languages (Jinja, EJS...)
main.py:
#app.route('/')
def default():
return render_template('main.html', var1 = 1, var2 = 2)
main.html
<html>
<body>
<p>The first value is {{var1}}</p>
<!-- Insert this <script/> tag before loading you main.js -->
<script type="text/javascript"> window.myVar1 = "{{var1}}" </script>
<script src="main.js"></script>
</body>
</html>
main.js
window.onload=function(){
// Now you can access to myVar1 directly
console.log(myVar1);
};

External files not loading into HTML

I have a problem loading external files into my index.html. My stylesheet as well as my JS files do not show up at all (Error 404 - Not Found). My directory structure is as follows.
My index.html is:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>Orders and Customers</title>
<link rel="stylesheet" type="text/css" href="./assets/css/stylesheet.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular-route.min.js"></script>
<script src="./../app/app.js" type="text/javascript"></script>
<script src="./../app/controllers/customer/CustomerController.js"></script>
<script src="./../app/controllers/order/OrderController.js"></script>
<script src="./../app/services/customer/CustomerService.js"></script>
<script src="./../app/services/order/OrderService.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
This is what Chrome shows:
My server.js is:
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
require('./server/config/mongoose.js');
require('./server/config/routes.js')(app);
app.use(express.static(path.join(__dirname, './views')));
app.listen(8000, function() {
console.log('Listening on Port 8000');
})
Any help is greatly appreciated!
Try this
in server.js
var router = express.Router();
router.use(express.static(path.resolve(__dirname, "../app")));
in index.html
<script src="/app.js" type="text/javascript"></script>
<script src="/controllers/customer/CustomerController.js"></script>
<script src="/controllers/order/OrderController.js"></script>
<script src="/services/customer/CustomerService.js"></script>
<script src="/services/order/OrderService.js"></script>
Router is middle-ware for capture * path.
For example, /service/* matches all requests under service path.
so I changed your code as to handle all resources under "/app" folder. (eg: /app/app.js, etc)
path.resolve changes path from relative to absolute.
it means that you can add another current working directory.
path.resolve(__dirname, "../app") add "/app" from current working directory (views). it parsed from "views/../app" to "/app"
(Reference) Path.resolve
The relative paths
<script src="./../app/app.js" type="text/javascript"></script>
etc, are pointing to the wrong directory.
Use the Network tab in your browser developer tools, to check what exact requests are going out.
If the whole app directory is public (Which, in my opinion, should not be the case), "./../" will refer to the views directory.
Single . refers to the current directory, which in this case is, the one containing your index.html. Double .. refers to the directory above it, which here is views.
Rather than
<script src="./../app/app.js" type="text/javascript"></script>
Try using the full path:
<script src="/app/app.js" type="text/javascript"></script>
<script src="/app/controllers/order/OrderController.js"></script>
Try this
app.use(express.static(path.join(__dirname, 'views')));
and just use
<link rel="stylesheet" type="text/css" href="assets/css/stylesheet.css">
Thanks to SeongHyeon, I was able to figure out the solution to my problem. I really appreciate your guys' help. I'd like to elaborate more on this just for my own reference.
When declaring your static path in express, you don't need to reference anything relative to the file that you're trying to import from. Instead, you simply reference the file from the static path that you've declared.

href and src attributes in .ejs template cannot be found

When I render my .ejs file the href and the src attributes are not referencing my local files. I am using node.js and express.
Here is the relevant part of the .ejs template.
<head>
<title></title>
<link rel='stylesheet' href='../public/stylesheets/styles.css' />
<script src="../us-map-1.0.1/lib/raphael.js"></script>
<!-- <script src="scale.raphael.js"></script> -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js"></script>
<script src="../us-map-1.0.1/color.jquery.js"></script>
<script src="../us-map-1.0.1/jquery.usmap.js"></script>
<script>
</head>
This is router that renders the template
router.get('/submit', function(req, res, next) {...});
And this is what a typical query looks like
http://localhost:3000/submit?leftHashtag=dog&rightHashtag=cat
Any help on why this is happening would be greatly appreciated.
The problem was that I wasn't defining my static content serving.
To fix this I added an app.use statement to my app.js file
app.use('/submit', express.static(__dirname + '/public'));
So now any routes that begin with /submit will use this directory local to the app
__dirname/public
With __dirname being the current directory the app.js file is located in
If you would like to know more this blog goes into more detail about what is happening
http://blog.modulus.io/nodejs-and-express-static-content

Sails.js - How to inject a js file to a specific route?

For example, I have a page /locations/map which I need to include Google Map library, and include a .js file (e.g. location.js) specifically for this page only.
I want to inject these 2 files to after <!--SCRIPTS END--> this line
Is it possible to do this?
NOTE: I was using Sails.js v0.10
Sails uses ejs-locals in its view rendering, so you can accomplish what you want with blocks.
In your layout.ejs file, underneath the <!--SCRIPTS END-->, add (for example):
<%- blocks.localScripts %>
Then in the view you're serving at /locations/map, call the block with your script tag, for example:
<% block('localScripts', '<script src="https://maps.googleapis.com/maps/api/js"></script>') %>
As an alternative, you could put the <!--SCRIPTS--> and <!--SCRIPTS END--> tags in the <head> of your layout, and then add your view-specific scripts directly into your view rather than using blocks. This is a fine option if you don't mind waiting for those linked scripts to load before your page content is displayed.
Scott's answer is the proper way to insert non-global JS into a specific view. Just a little comment, though: the block call from the view should not have the dash. It should be as follows:
<% block('localScripts', '<script src="https://maps.googleapis.com/maps/api/js"></script>') %>
Both calls will work, but using the dash makes the insertion twice; once the view is loaded and previous to the layout render, and then once again when the view is inserted in the rendered base layout. This leads not only to inserting/running unnecessarily twice the same code but also to errors that break your JS code if the inserted script depends on libraries that you have in your base layout (e.g. jQuery, Backbone).
EJS interprets the magic <%- as "insert unescaped". So, -I guess- what this is doing is calling the block() function, which returns our HTML <script> tag. This is replaced where the magic was called but also is executing the block() function inside of it, which is executing the layout block localScripts replacement.
On the other hand, <% means "instruction". I.e., just run this JS piece of code, which is not echoed to the view where is called.
I discover other way to do that
In MapController.js
// you can add as many as you like
res.locals.scripts = [
'//maps.googleapis.com/maps/api/js',
];
return res.view();
In layout.ejs
<!--SCRIPTS-->
<!--SCRIPTS END-->
<!-- Loop through all scripts that passed from controller -->
<% if (scripts) { %>
<% for (i = 0; i < scripts.length; i++) { %>
<script src="<%- scripts[i] %>"></script>
<% } %>
<% } %>
This method allows flexibility to locally serve js files from any page and also prevent any reference errors caused by dependencies.
In pipeline.js insert '!js/local/*.js at the bottom of jsFilesToInject like so:
var jsFilesToInject = [
// Load sails.io before everything else
'js/dependencies/sails.io.js',
// Dependencies like jQuery, or Angular are brought in here
'js/dependencies/jquery-3.3.1.min.js',
'js/dependencies/**/*.js',
// All of the rest of your client-side js files
// will be injected here in no particular order.
'js/**/*.js',
//Ignore local injected scripts
'!js/local/*.js'
];
Create a local folder inside the /assets/js folder ie /assets/js/local/. Place any locally injected scripts in here.
In your master view ejs ie layout.ejs insert <%- blocks.localScripts %> below the SCRIPTS block like this:
<!--SCRIPTS-->
<script src="/js/dependencies/sails.io.js"></script>
<script src="/js/dependencies/jquery-3.3.1.min.js"></script>
<script src="/js/dependencies/bootstrap.min.js"></script>
<script src="/js/dependencies/popper.min.js"></script>
<!--SCRIPTS END-->
<%- blocks.localScripts %>
In your local ejs view (eg. homepage.ejs) insert your localScripts block like this:
<% block('localScripts', '<script src="/js/local/homepage.js"></script>') %>
sails v0.12.14
EDIT
Is this still relevant for Sails v1.0?
My answer is a resounding YES and in my earlier answer I lacked explaining how to get the most out of the Grunt pipeline like clean, coffee, concat, uglify etc... when going into production.
The trick here is to make a local file (there should only be one per page) as small as possible.
Group and name specific your function calls
Save functions as separate files for easy maintenance and group them into folders.
Group bindings and any initialising of global variables into a couple of functions like initThisPageVariables() and initThisPageBindings() so that Grunt can crunch these later.
Set a master function call to run your app startThisPageApp()
Then simply calling the few functions from your local (master) file to get things rolling.
$(window).on('load', function(){
initThisPageVariables();
initThisPageBindings();
$(window).on("resize", function(){
initThisPageVariables();
}).resize();
startThisPageApp();
});
I know this is an old question by I discovered another option.
File:
config\routes.js
Code:
'/': 'HomeController.StartHome'
I set StartHome function in HomeController responsible for managing '/' route.
File:
api\controllers\HomeController.js
Code:
StartHome: function(req, res) {
var template_data = {
"data" : {
"view_name" : "home_view"
}
}
res.view('home_view', template_data)
}
Here, I created an object with some data which is passed to EJS template(to client).
File:
views\layout.ejs
Code:
<% if (data["view_name"] === "home_view") { %>
<script src="script_for_home_view.js"></script>
<% } %>
In my layouts.ejs I created if statement which "enables" script tag depending on on the view I am currently on.
This is how I handle this. I hope it's clear for you.
Sails 0.12.4

Categories

Resources