How to apply GString interpolation in a js file in Grails - javascript

My GSP file (in Grails 3.1.10):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<asset:javascript src="jquery-2.2.0.min.js"/>
<asset:javascript src="myfile.js"/>
</head>
<body>
<span id="greeting"></span>
</body>
</html>
myfile.js:
greeting = "${resp}"; // resp is passed from controller
$(document).ready(function(){
$('#greeting').val(greeting);
});
Well, I believe in that every grails developer knows if I move myfile.js into my GSP file, it will work.
However, I hope to know how to let the standalone js file can handle the inline variable of GString correctly.
Thanks.

Below is the approach I followed when ran into same problem like yours.
Pass your GString variable to external JS by following way.
Add the below function in your external JS
function view_handler_function(greetingValue){
//assign the value to your element
$('#greeting').val(greetingValue);
.....
//Your other handling code
}
Call your function from your view
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<asset:javascript src="jquery-2.2.0.min.js"/>
<asset:javascript src="myfile.js"/>
</head>
<body>
<span id="greeting"></span>
<script>
var greeting = "${resp}"; // resp is passed from controller
$(document).ready(function(){
//call to your external function
view_handler_function(greeting);
});
</script>
</body>
</html>
Note: This may or may not be the exact answer you are looking for but just one way around I follow.

this is out of the box simply not possible, and it's not a good idea either (although of course you could use a controller action as javascript src and in that action read in the js file and run it's content through a e.g. simpleTemplateEngine)
having js files be interpreted like gstrings/other templates would mean that any caching (bundle files via asset pipeline, cdn distribution and browser caching) had to be disabled.
however, you can simply serve the js files statically and e.g. provide your dynamic input as global variables in inline javascript (e.g. from your layout):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<span id="greeting"></span>
<g:javascript>
var greeting = "${resp}";
</g:javascript>
<asset:javascript src="jquery-2.2.0.min.js"/>
<asset:javascript src="myfile.js"/>
</body>
</html>

Related

How to import HTML into HTML without duplicate head & body tags? (no frameworks if possible)

I'm playing around with HTML (, JavaScript & CSS) & decided to try to import one HTML from one file into another, the goal is that I can make several modules and just import them into an empty HTML page, so they together create a fully working & content filled HTML page.
I would prefer to use something similar to how scripts or style-sheets are imported:
(ignore the $ signs)
$<script src="file.js"></script>
OR
$<link rel="stylesheet" type="text/css" href="style.css">
The problem is that the $<html>, <head> & <body> tags are inserted again, is there any good way to fix this?
I have tried some methods: $<object> & <embed> &
$<link rel="import" href="file.html">
I don't want to use $<iframe> because I have heard that it's a security problem (yes, it's not relevant right now, but if I'm going to use this method later for real, then it will be important).
I am aware of other similar questions, like this:
Include another HTML file in a HTML file but most of the answers use external frameworks like JQuery or Angular which I don't want to use, I would prefer to use a pure HTML or/and JavaScript solution if possible.
Example code:
File to import:
<p>"The import is working"</p>
Base file to import into:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- Import code here (or in head if it for some reason is required) -->
</body>
</html>
Desired outcome:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>"The import is working"</p>
</body>
</html>
Actual outcome (with $<object> or $<embed>), (at least as the Firefox inspect-element tool shows it):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<embed src="file.html">
#Document <!-- I don't know what this means/function is, can someone explain? -->
<html> <!-- Notice the double: html, head, meta & body -tags -->
<head>
<meta charset="UTF-8">
</head>
<body>
<p>"The import is working"</p>
</body>
</html>
</embed>
</body>
</html>
You can use PHP, by making your file names with a .php extension and use PHP include:
<?php include 'header.php';?>
Read more about it here.
I've been trying to do the same thing for some time and the only solution I've come up with involves some JavaScript. When you import HTML the #document tag means it lives in the shadow DOM which is different than the one rendered (I think, I don't really understand this stuff). In any case, after importing, I ended up having to render the element and append it to the DOM.
<!-- Original HTML file -->
<html>
<head>
<title>Title</title>
</head>
<body>
<p>
Hello from original HTML.
</p>
<link id="importLink" rel="import" href="/path/to/import.html">
</body>
<script src="/path/to/renderImport.js"></script>
</html>
I had the following code in my renderImport.js file:
// renderImport.js
function renderImport() {
let importLink = document.getElementById("importLink");
let importedElement = importLink.import.querySelector('#import');
document.body.appendChild(document.importNode(importedElement, true));
}
renderImport();
And finally, import.html:
<!-- import.html -->
<p id="import">Hello from the imported file</p>
Here it is in Chrome. Though you might have to disable CORS.
Use Angular CDN in Head tag then import html using this code
<body ng-app="">
<ng-include src="'header.html'"></ng-include>
</body>
OR
<body ng-app="">
<header ng-include="'header.html'"></header>
</body>
Use you can change header to footer or content

Obtaining CSV from a static file using tags to avoid cross-domain policy

I'm programming a C++ application which generates the report data in Javascript instead of CSV. I advocate that HTML and Javascript provides a powerful tool to generate and show reports. But generates the Javascript code in C++ it's a bit clunky.
I'm attempting to read a CSV from Javascript but I realise that it isn't possible owing to the cross-domain policy. I'd like to facilitate the client to see the report without obliging to disable the cross-domain security.
Code that works:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta charset="utf-8" />
<title>Read CSV from static file - Avoiding cross origin</title>
<script id="data" type="text/csv">
x, y
0, 0
1, 1
2, 4
</script>
</head>
<body>
<script type="text/javascript">
var data = document.getElementById('data');
alert(data.innerHTML);
</script>
</body>
</html>
Code that does not work:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta charset="utf-8" />
<title>Read CSV from static file - Avoiding cross origin</title>
<script id="data" type="text/csv" src="data.csv"></script>
</head>
<body>
<script type="text/javascript">
var data = document.getElementById('data');
alert(data.text);
</script>
</body>
</html>
Why using only an external plain text data does not show me anything? Can I solve this using <link> or <meta> tags? Thanks for your help!

Why is my GSP pulling in my AngularJS javascript files but not executing my controller function?

I have a simple GSP View which contains a reference to 2 bundles being managed by the Grails Resources plugin.
the reference to the core angularjs libraries are in my layout.
A basic representation of the view is like so:
<html ng-application="myapp">
<head>
<meta name="layout" content="main"/>
<title>a title</title>
<r:require modules="index, widgeta"/>
</head>
<body ng-controller="index">
<div>
<widgeta/>
</div>
</body>
</html>
Grails seems to pull everything in just fine, i can even see the myapp.controller('index', function(){}); line get executed.
However; my controller function itself never gets executed. Why not!?
Silly grails... I took a closer look at what was coming back with the HTML and grails was stripping off the controller and app reference.
Moving both to the first 'div' tag in the body seem to do the trick:
<html>
<head>
<meta name="layout" content="main"/>
<title>a title</title>
<r:require modules="index, widgeta"/>
</head>
<body>
<div ng-application="myapp" ng-controller="index">
<widgeta/>
</div>
</body>
</html>

How to load AngularJS in a div

I have a main page with this structure.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>..:: Test Application ::..</title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.css" />
<link rel="stylesheet" href="../css/main.css" />
<script src="../js/jquery.js"></script>
<script src="../bootstrap/js/bootstrap.min.js"></script>
<script>
function loadOption(idopt){
if(idopt==1){
var curl = '../view/otherpage.php'
}
$("#mainContainer").load(curl);
}
</script>
<body onLoad=loadOption(<?php echo idopt;?>)>
<div id="mainContainer"></div>
</body>
</html>
otherpage.php
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="UTF-8">
<title></title>
<script src="../js/angular.min.js"></script>
</head>
<body>
{{1+1}}
</body>
</html>
But, when i load the main page... the AngularJS doesn't run. What could be wrong?
That's because you're loading otherpage.php after the DOMContentLoaded event has finished.
In other words, you're filling in the space inside the mainContainer div with otherpage.php content after the event DOMContentLoaded. And that is where Angular's Automatic Initialization takes place.
So in order to get it to work, you'll have to manually bootstrap Angular.
Here's Angular's documentation about it:
http://docs.angularjs.org/guide/bootstrap
Other options are available and are much better, such as referencing your Angular related files (angular, your controllers, services, directives and what not) at the main page.
Depending on the browser, pulling the script element in otherpage.php out of the head element and into the body element, should correct this.
We can't see all your code, but it may be better to just load Angular.js in the head of the main page. You could do this using your own a script package manager control flow to avoid this type of failure for other dependencies. That would be good style...
make a common includes page and add angular.js file to it and include it in the header so that it is available through out the site or use it in the main page

Edit serverside files in JS

i am making some script for some personal use. Now i tend to keep my CD collection list in a html file which has some sleek design, but i am tired of editing the list by "hand" and that means that i don't want to edit the code everytime i add new CD. So is there a way that i can use JS or JQuery so i could add/read from a local file(this script is not remote it is local(although i might try to host it remote).
I don't want to use any other language than HTML, CSS and JS/JQuery.
EDIT: Is it possible to add a link that when i click some application on my computer would launch.
Not if you only want to use HTML and javascript. You will need a server side script of some kind to write to a file.
The comments got me thinking, I know this is not really what you were asking but you could play around with server side javascript with node.js
You can do it like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>CD Collection</title>
<script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
var cds = ['cd1', 'cd2', 'cd3'];
$(function() {
$(cds).each(function() {
$('#cd_list').append('<li>' + this + '</li>')
});
});
</script>
</head>
<body>
<p>
<ul id="cd_list"></ul>
</p>
</body>
</html>
The inline js with the cd list can be loaded in as a separate file in the same way jquery was pulled in.

Categories