Referencing javascript global inside ng-init call using Angular and Django - javascript

I've got a javascript global that is available in my Angular partial:
<script>
console.log(tm.staticUrl);
</script>
I don't know how to reference it in the below call:
<div ng-init="templateUrl = 'partials/essay.html'">
I need to adjust the url based on if we're on a remote server or developing locally, but have no idea how to do this. I've tried variations of this:
<div ng-init="templateUrl = tm.staticUrl + 'partials/essay.html'">
But feel like I'm misunderstanding how these strings are parsed.

Related

Need to render variable from route to use in client-side javascript

I am currently able to use variables in the view that I render from the route but only in the HTML markup. How can I use these same variables in the client-side javascript?
I have this code:
<script>
var socket = io();
if ({{highestBidder}} === {{sessionID}}) {
socket.on('outbid', function () {
console.log('You have been outbid');
});
}
</script>
However, the variables are not being passed in correctly because I'm just getting an undefined.
As far as I know you can't ! Since most of the data is compiled in the server and rendered as HTML page. But there is work around for this :
Create AJAX call. Get whatever data you like with it.
Store the variables as hidden field and grab then using JS or jQuery [I don't suggest doing this.]

Calling controller function from gsp

I need to call a controller function from javascript on my gsp.
I have read different solutions from hundreds of places but none worked.
The problem which I found closest to mine was this.
But I am not repeating the same mistake as this and thus the solution didn't help.
I have a tag like this which calls the javascript function
<g:select name="poNumber" noSelection="['':'Select PO Number']" from="${com.rerq.PurchaseOrder.list()}"
onchange="getProject(this.value)" />
And the javascript function looks like this
function getProject(poNumber){
var projectName = document.getElementById("projectName");
var newData = ${remoteFunction(controller: 'sow', action: 'getProject', params: ['poNumber':poNumber])};
}
And the function I need to call is
def getProject(String poNumber) {
String projectName = Sow.find("from Sow as s where s.poNumber=?", [poNumber])
return projectName
}
The controller function might have mistakes as I am completely new to groovy and grails. But my understanding is that the control isn't reaching here so this should not be the cause of any problem.
I am getting below exception
No signature of method: remoteFunction() is applicable for argument types: (java.util.LinkedHashMap) values: [[controller:sow, action:getProject, params:[poNumber:null]]]
I tried using remoteFunction() in g:select itself but it threw another exception which said
Attribute value quotes not closed ...
even though they were.
Any help is greatly appreciated.
To use remoteFunction with Grails 3 you need to add the ajax-tags plugin: org.grails.plugins:ajax-tags:1.0.0
Actually you can have your gsp recognize some Grails functions inside your js if the script is inside the gsp and anything you need for your js is created on the server side. In your case it seems you want to do an ajax call so you could have the following.
project.gsp (Consider that you already loaded jQuery)
<g:select name="poNumber" noSelection="['':'Select PO Number']" from="${com.impetus.rerq.PurchaseOrder.list()}"
onchange="getProject(this.value)" />
And in the same file you have
<script type="text/javascript">
function getProject(poNumber){
jQuery("#yourTarget").load("${createLink(action: 'getProject')}",{poNumber: poNUmber},function(response, status, xhr ){
if ( status == "error" ) {
alert("No data loaded.")
}
});
}
</script>
As you see a gstring in load("${}",... is used because it will be parsed in the server and at client side your actual js it will parse to load("yourcontrollerName/getProject",..... Why not code the url directly in the js? Because by using createLink() it is less likely to make reference mistakes.
EDIT
If you want to do this but using an external js file, you would need a way to pass the url, to the js, and use a simple load function. So something like this will be helpful
<g:select name="poNumber" noSelection="['':'Select PO Number']" from="${com.impetus.rerq.PurchaseOrder.list()}"
onchange="getProject(this.value, \'${createLink(action:'getProject')}\')" />
Once on the server onchange="getProject(this.value,\'${createLink(action:'getProject')}\')"would be parsed to onchange="getProject(this.value,'yourController/getProject')". Be wary that I might have messed up the ""s and ''s so verify your html output.
And you would need a js function that accepts the uri
function getProject(value, targetUri){
....
}
What you need to review is when is your function needed, on the server o in the client;if the functions are inside a gsp or not; And if not available, how could you pass data to them.
You cannot access grails's controller from javascript. I haven't tested it but this might work.
<g:createLink controller="sow" action="getProject", params="['poNumber':poNumber]"/>
Also, if you use Google Chrome's developer's tool, you will see how your javascript code is displayed. Make sure it is in right syntax.

Injecting data in html with javascript

Using server side scripting it's as easy as pie to inject data in HTML like this (ASP.NET):
//Assuming theTime is a variable
<h1>the time is, #theTime</h1>
But in JavaScript one basically needs to:
Create an element:
<h1></h1>
Give it an ID:
<h1 id="whatever"></h1>
Create a script tag:
<script></script>
Locate the element by it's ID:
document.getElementById("whatever")
Then use innerHTML to modify it's content:
document.getElementById("whatever").innerHTML = "Hi, " + TheTIme;
Final code:
<h1 id="whatever"></h1>
<script>
document.getElementById("whatever").innerHTML = "Hi, " + TheTime;
</script>
Is it possible to inject values/data in JavaScript as one would do in ASP.NET / PHP?
EDIT: The variable is a JS variable and getting it from the server is under control.
Well you could use some template library like handlebars and use jquery to facilitate the element selection, example:
<div id="target"></div>
<script id="hi-template" type="text/x-handlebars-template">
Hi {{userName}}
</script>
<script type='text/javascript'>
var template = Handlebars.compile($("#hi-template").html());
$('#target').html(template({userName: "bob"}));
</script>
Javascript Templating solves exactly this problem of binding data to HTML elements.
Below are few of the common templating engines used these days:
Underscore.js
Handlebars.js
Mustache.js
If you are looking for something simple, try Micro Templating engine from John Resig
<h1>Hi, #theUsersName</h1>
I've never worked with ASP.NET, but I'm assuming #theUserName is a variable. If that's the case, then a 1 to 1 replacement for that is not possible. However, it's still possible.
I'm not sure how you're getting the username, but I would assume you have some way to get it into a JavaScript variable. In that case, I would suggest something like this:
function changeName(username) {
document.getElementById("username").innerHTML = username;
}
<h1>Hi, <span id="username">StackOverflow</span>!</h1>
<button onclick="changeName('user3088260')">Click to Change the Name</button>
Now, getting the data is a different story, I would assume an AJAX call, in which case you could do something like this
if(xmlhttp.responseText !== ""){
changeName("user3088260");
}
All that other stuff you mentioned in unnecessary.
I will also say the entire idea seems like a poor design choice. If you have a username, I would assume you have a login system. If you have a login system, then you have to validate the user before outputting the page. If you have to validate the user before outputting the page, then you have their username. If you have their username, then put it in the pre-rendered page. No need to use JS after you've outputted the page.
Hopefully that is what you're looking for. If not, I'm sure somebody else will be along shortly with something that does.
One of the easiest javascript template engines to get started with is Underscore. Here is a protected answer from SO explaining how to do it:
How to use underscore.js as a template engine?
As someone says, there are a lot of Javascript templating frameworks. Here you have a few of them:
Handlebars.js
mustache.js
Hogan.js
doT.js
nunjucks
jade
After picking one, you can (for example) do something like this:
<h1>Hi, {{userName}}</h1>
You can see an example of client-side templating working with Angular on this link.

Express/Node.js : Render custom javascript as response

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

using jasmine to test javascript that expects a jquery template to be available?

I typically set up jquery templates in my html files like this:
<script id="some-template" type="text/x-jquery-tmpl">
my template contents go here... with some data: {data}
</script>
then my javascript that needs to use this template would look for it by the id and pass in the needed data:
var template = $("#some-template");
var html = template.tmpl({data: "data goes here..."});
// do something with the 'html' var, like attach it to the DOM
now i'm trying to write jasmine-bdd specs for my javascript. i don't see anything particularly wrong with the way i set up my templates and have my javascript find / expand the template... but i'm not sure how to get jasmine to play nice with this... so...
how can i use jasmine to test my javascript, when my javascript relies on a jquery-template, and the template is defined in my html page directly?
do i have to duplicate my template in a jasmine-jquery fixture? or is there a way to make a jasmine-jquery fixture use my existing html / template definition?
in case anyone is interested, here's how i solved this: http://lostechies.com/derickbailey/2011/09/06/test-driving-backbone-views-with-jquery-templates-the-jasmine-gem-and-jasmine-jquery/

Categories