In my application, I need to provide an API (something like the Google Maps javascript API), through which I can send some custom javascript (with some session and request related information) as the response. The javascript is then used to plot some graphs on the UI. I'm using Express with Jade as my templating engine. The code that I'm currently using is:
app.use('/graph',function(req, res){
//send out graph data
var var_name = req.session.var_name //fetch something from session
var graphData = fetchGraphData(req.query.graph); //function that fetches graph data
res.contentType("text/javascript");
res.render(__dirname + '/views/graph.jade', {
title: "Title", queryStr: JSON.stringify({var_name: var_name, graphData: graphData })
});
});
And the jade file:
| some_var_name = {
| initGraph : function(divId){
| //some code here
| var graphData = !{graphData}
| // do something
As a workaround, I have started each line of the jade file with |, so that jade parses the text as plain text, and doesn't add any html tags! It works fine, but is there a cleaner way to do this? The solution may or may not use Jade!
You should look into underscore templates. I think that for generating arbitrary text output it would be somewhat cleaner. Jade is purpose-built for rendering HTML.
You could also try Mustache or Handlebars.
Based on your comment, I see you'd like to keep using res.render for rendering the template. consolodate.js adds support for all major template engines to Express. Including Underscore templates, Handlebars, Mustache and Dust, mentioned by #TheHippo.
You may try to define JavaScript functions you need to send to the browser in a separate module, outside of the template, which is probably more correct way from the "concerns separation" point of view. Also if functions are defined in a separate module they can be used both in the server and in the browser.
Then you can convert the functions to strings using its toString() method either in a function that invokes the template or right inside the template, if it supports plain JavaScript which is the case with underscore, EJS and doT templates (I tried both underscore and EJS and ended up using doT which is not only the fastest but very versatile - check it out):
JS code:
// if you send the same functions you may want to convert them to strings in advance
var data = {
funcStr: func.toString();
};
res.render(view, data);
Template (doT):
<script type="text/javascript">
func = {{= it.funcStr }};
// now you can call it here if you want but I would use
// separate JavaScript files
func();
</script>
I use it to send pre-compliled templates to the browser together with the page on the first page load, but I think it can be used in your case too.
As a side question, why can't you just bundle all these functions in a separate JavaScript module and load them as normal script file?
You can use https://www.npmjs.com/package/rendercustomjs package, it works fine but in ejs templating
Related
I have a C# file that pulls various config settings from different config files. A JavaScript application I'm writing needs some of those settings to run. I'm having trouble bringing the C# variables into the js file. Not sure what is the best approach. They need to end up as a JS object on the page. Would adding them to a JSon object in the C# file & calling that from the JS file work? Not even sure how to do that to be honest. Any help appreciated.
You can just declare a global variable in one of your root pages (say, _layout.cshtml):
<script>
var settings = {
foo: #(IsFoo ? "true", "false"),
bar: #SomeNumber,
baz: "#ImportantString"
}
</script>
Or, if you're writing a Web API, you can just add a /settings endpoint you can query like so (Assuming you're using jQuery):
$.get("/settings", response => {
// Store the `response` in a global variable.
});
If it's an independent javascript project and .net is more of an API, you need to make an API call which will send you those config settings.
If your javascript is part of .net MVC application, i.e., you are adding your javascript through an tag at then end of a .cshtml/.aspx file, you can easily pass it through a global variable, but even then the C# code need to pass those values through Modal to the .cshtml/aspx file.
what you can do is:
var pageConfig = pageConfig || {};
pageconfig.settings = #Html.Raw(Model.Settings); // This model object is part of the C# code and my assumption is that Settings will have array of configurations.
This can also be done globally, depending upon how the C# code is written.
Assuming that when you say 'various config settings' you're referring to .NET's ApplicationSettings (defined in Visual Studio's Properties > Settings), we've done something similar, in a generic manner, as follows:
public void WriteSettings(TextWriter writer)
{
// Declare the nameSpace for the DLL you want to pull settings from
var nameSpace = "foo.Bar"
ApplicationSettingsBase properties = (System.Configuration.ApplicationSettingsBase)Activator.CreateInstance(nameSpace, string.Format("{0}.Properties.Settings", nameSpace)).Unwrap();
foreach (SettingsProperty property in properties.Properties)
{
writer.Write(string.Format("{0}=\"{1}\", property.Name, properties[property.Name]);
}
}
I've ignored a few issues in your case:
I've not bothered trying to deal with non-strings; consider looking at property.PropertyType and casting your values appropriately
I've wrapped this in a function that accepts a TextWriter; you can pass this method Response.Output
I am trying to find the way to expand a JavaScript variable value in HTML.
I know that it is possible to do it in PHP, like this:
<?php
$myString = "Hello World";
?>
<p><?=$myString?></p>
Is it possible to do likewise in JavaScript with a similar native inline tag?
Note
I am aware of other solutions such as calling other functions, which is exactly what I want to avoid.
There is no native way for injecting JavaScript values into HTML by just using a tag like the PHP <=? tag. What comes closest might be ES6 template literals.
It can look like this:
var mystring = 'Hello World';
document.write(`
<p>${mystring}</p>
<div>
some other stuff
</div>
`);
This version of JavaScript is available in most browsers today, but will of course not work in older browser versions, nor for current Internet Explorer versions (are we surprised?) -- but it works in Edge.
There are no native capabilities in HTML that allow injection of JavaScript values following the PHP-like syntax. In my opinion, the above comes as close as you can get. The only way to access to JavaScript variables from within HTML is with specific attributes (like "onclick") -- which serve another purpose --, and with script tags, which do not work like the <?= PHP tag either, but more like the standard <?php tag.
Using templating libraries might be an option (e.g. mustache, underscore, EJS, handlerbars, pug, plates, dust.js, hogan.js, jsrender, markupjs, nunjucks...).
A simple, poor man's template library - class/content based
The above listed templating engines offer advanced features, but here is a very basic implementation that understands this kind of HTML:
<span class="template">`I want to say "${mystring}"`</span>
When the page loads, the "poor man's library" should render that as:
<span>I want to say "Hello World"</span>
Here is the code for doing just that:
/* my simple template library: you would include this from another JS file */
document.addEventListener("DOMContentLoaded", function(event) {
var templates = document.getElementsByClassName('template');
[].forEach.call(templates, function (template) {
template.textContent = eval(template.textContent);
template.setAttribute('class', '');
});
});
/* my set of variables */
var mystring = 'Hello World';
# my simple template CSS
.template {display: none};
<span class="template">`I want to say "${mystring}"`</span>
A simple, poor man's template library - attribute based
Here is variation on the same concept. Now the syntax is a custom tag inject of which the value attribute has the value to inject. Here it is the "library" that injects the template literal backticks. This could also have been done in the first version.
/* my simple template library: you would include this from another JS file */
document.addEventListener("DOMContentLoaded", function(event) {
var templates = document.getElementsByTagName('inject');
[].forEach.call(templates, function (template) {
template.textContent = eval('`' + template.getAttribute('value') + '`');
template.removeAttribute('value');
});
});
/* my set of variables */
var mystring = 'Hello World';
<inject value='I want to say "${mystring}"' />
I don't see how it's possible to achieve in JavaScript what you're trying to achieve.
The closest thing I can think of, is something like this :
<script>var message = "Hello World";</script>
<div>Before message</div>
<div>
<script>document.write(message);</script>
</div>
<div>After message</div>
It is, however, recommended to avoid using document.write!
Note
Based on the info you provided in the comments, I think you're looking for one of the following approaches :
Replace your Twig templates with Mustache templates, for which both an official PHP implementation and an official JavaScript implementation exist.
Use an (unofficial) port of Twig to JavaScript to process your Twig templates in JavaScript.
Essentially I'm trying to do the opposite of what django-ds-utils does, which is get URL argument out of a resolved URL, for instance, take the following URL definition:
url(r'^reset_pwd/(?P<code>[A-Za-z0-9]+)/$', ResetPasswordView.as_view(), name='my.registration.views.reset_pwd'),
On that page, within JS, I would like to retrieve <code> into a kwargs array. Is this something that exists, or is there a standard approach to this?
AFAIK there is no standard approach. You can:
put JS into template and render view variable
pass variable in JS globals, setting it's value in template text
parse window.location
...etc.
I personally prefer the second way, e.g. put this code in template and then use _reset_pw_code global in javascript file:
<script> var _reset_pw_code = "{{ reset_code|escapejs }}" </script>
Recently JavaScript added a new API to do this it is currently still experimental.
const pattern = new URLPattern('reset_pwd/:code/', 'https://example.com');
console.log(pattern.exec('https://example.com/reset_pwd/thECode/').pathname.groups); // { code: 'thECode' }
https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API
I am working with a website built with Jade/Express for a few weeks now. I recently organized the image folder for the website so all the images were disbursed between several folders to make it easier to use and sort through.
To make it easier to make changes to the hierarchy of images (and other such files) I wrote a script that contains some globals for file paths. Now I have been trying to get the script to run so that I can call functions inside the jade template to automatically use these globals.
For example. Images are now sorted into several folders:
File Hierarchy
img/
glyphs/
interactivity/
buttons/
...
In my path manager script, I created several functions, including the following:
In: path-manager.js
images_root_path = "/img/";
glyph_path = images_root_path + "glyphs/";
function getGlyph(color, name) {
return glyph_path + color + "/" + name;
}
I tried several methods to get the script to execute before the template. Here is one of the attempts:
In page.jade
include ../../../public/js/lib/path-manager.js
=NamespacePathManager();
The above is, in theory, supposed to include the js and then I execute the namespace below to make the functions available, but that isn't working.
This is a portion of the Jade template that I want to use the function in:
In page.jade after the script include
span.challenge-time
img(src=getGlyph("black","stopwatch.png"), style="margin-right:5px;")
The above example should return: "/img/glyphs/black/stopwatch.png"
The problem is, I believe, that the scripts I am trying to make available server-side to the jade template are not being executed before the jade template is rendered. Everything I have tried doing to get this to work always results in an error saying that the server doesn't recognize the function getGlyph or when I started using the namespace function, NamespacePathManager
Summary: I want a javascript file to execute before a jade template is rendered into a webpage so that I can call functions and variables from that javascript on the server to use while rendering the jade template. My problem is that all the methods I have tried are unable to execute the javascript before the Jade is rendered.
Update
One work around I found was to put the javascript into unbuffered code directly on the page including a jade. This isn't quite the elegant solution I was looking for, but it works for now
- some code
- more code
This code is executed inline. The downside is that I have to include it on every page manually - instead of just including it once and having the functions available everywhere.
You can register helper methods in Express that will then be accessible in the views.
So in your case, the path-manager.js can be the helper file that you register, and contains:
var images_root_path = "/img/";
var glyph_path = images_root_path + "glyphs/";
exports.helpers = {
getGlyph: function (color, name) {
return glyph_path + color + "/" + name;
}
// Other helper methods here..
};
Then when setting up the express server, you register the helper
var app = express.createServer();
// app.configure here...
// app.use ...
app.helpers(require('./path-manager.js').helpers);
// Routes set up here ..
Finally, you can call the helper method from Jade view like this:
span.challenge-time
img(src='#{getGlyph("black","stopwatch.png")}', style='margin-right:5px;')
There's a good write up on this topic at DailyJS http://dailyjs.com/2011/01/03/node-tutorial-8/
We are building large ASP.NET applications for the intranet use in multiple languages/cultures. We utilize the Globalization with RESX files and use GetResourceText on the server side to get the localized texts.
Lately we are doing more and more client side logic with JQuery.
How do I get the RESX texts to be used in Javascript?
e.g. texts used for validation, dynamic messages etc.
All our Javascripts are in .JS files, we do not want to mix HTML in the ASPX page and Javascript blocks.
Thanks for your help.
Unfortunately, in an external JS file the server side code is not being processed by the server. However I have seen a workaround where you can set your translated values in hidden fields on the page - this way your javascript will be able to read the values in.
For example:
<%-- This goes into your page --%>
<input type="hidden" id="translatedField" name="translatedField" value="<%=Resources.Resources.translatedText %>" />
and use this inside your javascript file:
// This is the js file
$(document).ready(function() {
alert($("#translatedField").attr("value"));
});
You will be able to separate the values and still see it in your external JS file.
There is also another workaround that creates a .aspx file that only outputs Javascript instead of HTML. Check out the link below:
Using server side method in an external JavaScript file
Always separate functionality from human readable strings.
If you're creating jQuery-plugins you should be able to pass an array of localized strings as parameter when you call your different jQuery functions. The array could be defined as inline javascript directly on the page calling the different jQuery plugins or you could load the from external resource in the format /scripts/localization/strings.js?ci=en-US and register a Generic ASP.Net Handler in web.config that would respond to scripts/localization/strings.js
The DatePicker control is a fine example of how to localize text for the jQuery datepick control - this js file is dynamically created from resource files (resx) and when included on a page it will make sure the calendar control will have danish text.
Create a HttpHandler (.ashx file), and return JSON with your text resource strings.
You may also "publish" it to global namespace, i.e.
Response.Write("window.Resources=");
Response.Write((new JavaScriptSerializer()).Serialize(strings));
set up HTML like:
<script src="Resx.ashx?lang=en-US" />
<button class="LogoutButtonResourceId OtherButtonClasses">(generic logout text)</button>
<a href="#"><span class="SomeLinkTextResourceId OtherClasses">
(generic link text)
</span></a>
and apply texts like this:
$(document).ready(function() {
for(var resId in Resources){
$("."+resId).html(Resources[resId]);
}
});
If you don't want to use ASP.NET to generate your main JavaScript, here are two other options:
Use ASP.NET to generate a script file that contains variable-to-string assignments, such as var mystring = 'my value';. Your main script would then reference the localized text with variables names rather than as embedded values. If that's still too "dirty" for you, you could encode the strings as JSON rather than as variable assignments, using an HttpHandler rather than straight .aspx.
Have your JavaScript code issue an Ajax call to retrieve an array or list of localized strings from the server. The server-side part of the call would retrieve the text from your resx files.
Have you considered using $.ajax in combination with ASP.NET WebMethods? It's hard to suggest a more concrete solution to this problem without understanding how your JavaScript/jQuery would consume/process the resources. I assume that they're organized into logical groups (or could be) where you could return several resource strings that belong on a single page.
Assuming that, you could write a very simple C# class -- or use a Dictionary<string, string> -- to return data from your ASP.NET WebMethod. The results would look something like:
[WebMethod]
public Dictionary<string, string> GetPageResources(string currentPage)
{
// ... Organizational stuff goes here.
}
I always separate out my AJAX calls into separate .js files/objects; that would look like:
function GetPageResources (page, callback)
$.ajax({ // Setup the AJAX call to your WebMethod
data: "{ 'currentPage':'" + page + "' }",
url: /Ajax/Resources.asmx/GetPageResources, // Or similar.
success: function (result) { // To be replaced with .done in jQuery 1.8
callback(result.d);
}
});
Then, in the .js executed on the page, you should be able to consume that data like:
// Whatever first executes when you load a page and its JS files
// -- I assume that you aren't using something like $(document).ready(function () {});
GetPageResources(document.location, SetPageResources);
function SetPageResources(resources) {
for (currentResource in resources) {
$("#" + currentResource.Key).html(currentResource.Value);
}
}
I know it's to late but want share my experience in this task)
I use AjaxMin. It can insert resx key values into js file on build event.
It's not common way but it keeps html without unneeded script blocks and can be done during minification process if you have it.
It works like this:
ajaxmin.exe test.js -RES:Strings resource.resx -o test.min.js
Also you need to do the same for ech locale if you have many.
Syntax to write resource keys in js (and also css) is written here:
Js localization
Css localization
How about injecting it as part of a javascript control initialization? what i do is as follows:
I have a self-contained javascript control - call it CRMControl, which has an init method called setupCRMControl, to which i pass a settings object. When i initialize it, i pass an object containing all the resources i need inside javascript as follows:
CRMControl.setupCRMControl({
numOfCRMs: 3,
maxNumOfItems: 10,
// then i pass a resources object with the strings i need inside
Resources: {
Cancel: '#Resources.Cancel',
Done: '#Resources.Done',
Title: '#Resources.Title'
}
});
Then, inside this javascript control:
var crmSettings = {};
this.setupCRMControl(settings) {
crmSettings = settings;
};
and whenever i want to show a resource, i say (for example, show an alert saying 'Done'):
alert(crmSettings.Resources.Done);
You can call it "R" to make it shorter or something, but this is my approach. Maybe this may not work if you have a whole bunch of strings, but for manageable cases, this may work.