I am working on a project on Google Apps Script. I have a JS function that returns a date (as a text). I also have an HTML document to display a form with several inputs. I would like to prefill one input with the date returned by the JS funtion. It almost works, except it displays "undefined" instead of the date, even though I know the js funtion is working fine.
Here are some code to better understand :
The input where I call the script (don't mind the onmousemove, i just didn"t find anotherway to call the script).
<input type="text" id="deliveryDate" name="deliveryDate" onmousemove="displayActiveDate()">
So it calls the folowing script.
<script>
function displayActiveDate(){
var activeDate = google.script.run.getActiveDate();
document.getElementById("deliveryDate").value = activeDate;
}
</script>
Which in turn calls getActiveDate() which is the separate JS function that returns the date.
If you have any idea on how to solve this, I will be very thankful.
google.script.run.serverSideFunction() returns undefined. In order to get the actual response value from your serverSideFunction() you need to use the withSuccessHandler() method with a callback like so:
google.script.run.withSuccessHandler(onSuccess).serverSideFunction();
function onSuccess(data) {
// do something with the data returned by the serverSideFunction()
}
Also note that you also have withFailureHandler(err) to handle any errors you server-side functions may return.
Here is the full reference
Instead of writing document.getElementById("deliveryDate").value = activeDate; type document.getElementById("deliveryDate").innerHTML= activeDate; in your script
Related
I actually work on a tool named jedox. With this tool I can make macro(like excel) but in PHP. Jedox provide some example of macro and in one of these example there is this code:
function test()
{
return array(array('eval', "(function(){
console.log('salut')
}())"));
}
It's a PHP code that run JS code. But the problem is I don't know how this code work, the only thing I know about it is that it execute JS code but can't return anything, so if you put return in the code it will not return any value. I have no way to retrieve the value returned.
So my question is how should I supposed to retrieve a value from this ?
PS: if I try to investigate about the value returned by test() I get an array nested with another array with those 2 values 'eval' and the function.
PS2: Apparently you can't run this code correctly with traditional tool. So to help me you should have jedox, I guess :/ ...
On the client side, someone must be getting those two strings and executing them. The PHP code ("host side") is not actually doing that.
You may could put the Javascript code into a file. Then execute the file using NodeJS and get the value.
For example:
function test() {
file_put_contents('test.js', <<< TEXT
(function(){
console.log('salut')
}())
TEXT);
return shell_exec('node test.js');
}
echo test(); // Return: sault
Also notice that in most shared hosts and servers shell_exec function is disabled by default. You can enable it through you php.ini.
This Javascript Function..
function ClearTotals() {
document.getElementById("total1").value = "";
document.getElementById("total2").value = "";
}
sets resets the values in two form fields. However when I move this function, unchanged, to an external Javascript and reference it in the HTML page as below:
<script src="http://xxxxxxx.org/pkjs/js1.js/"></script>
it doesn't work.
Do I need to pass some reference to the document which is used in the function, or is there some other reason why this doesn't work. Thanks
The problem is js1.js - as the error message made clear ! For some reason only the first function was being read even though I can see no problems with the structure of the file. If I delete all the other functions, and test the function by typing the url in the browser, I see the javascript code for ClearTotals().
And when I submit the HTML form, the field values clear as they should. That's really good - there are no issues with putting internal js code into an external file. Thanks again to everyone for their input and apologies that the problem seems down to me !
Mid development I decided to switch to server-side rendering for a better control amongst other benefits. My web application is completely AJAX based, no url redirecting, so the idea here is a website that builds itself up
I just couldn't figure out the proper way to send javascript events/functions along with the html string, or should all the necessary javascript always be preloaded in the static files?
Let's say client clicks a pre-rendered button 'open table'
The server will make a query, build the html table and send it back, but this table also needs javascript triggers and functions to work properly, how are these sent, received and executed?
There are a couple of articles that mention to not use eval() in Javascript, is there any way around this? I don't want to have to preload unnecessary events for elements that don't yet exist
The server is Python and the Client is Javascript/JQuery
Theoretical example :
Client Base Javascript :
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
eval(response.javascript()); //??
}
});
Python Server(views.py) :
def get_table(request):
data = {}
#String containing rendered html
data['html'] = get_render_table()
#String containing Javascript code?
data['javascript'] = TABLE_EVENTS_JAVASCRIPT
return HttpResponse(json.dumps(data),content_type='json')
Worth noting my question comes from an experimental/learning perspective
Update:
You can use jQuery.getScript() to lazy load JS. I think this solution is as close as you can get to run JS without using eval().
See this example:
jQuery.getScript("/path/to/script.js", function(data, textStatus, jqxhr) {
/* Code has been loaded and executed. */
console.log( data ); // Data returned
console.log( textStatus ); // Success
console.log( jqxhr.status ); // 200
console.log( "Load was performed." );
});
and "/path/to/script.js" could be a string returned from $.getJOSN response.
Also, the documentation for getScrippt() has examples on how to handle errors and cache files.
Old Answer:
Using .on() attaches events to current and future DOM elements.
You can either attache events prior to DOM insertion or attache event after DOM insertion.
So in your example you can do something like:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
var code = $(response.html);
code.find(".elementToFind").on("click", function (){
// Code to be executed on click event
});
$("#table_div").append(code);
}
});
I did not test the code but I think it should work.
Assuming you can't just set up an event-binding function and then call it from the main script (the JavaScript you need can't be guessed ahead of time, for example) then one really easy way is just to append the JavaScript to the bottom of the returned HTML content within script tags. When it's appended along with the HTML, the script should simply execute, with no eval() required.
I can't swear that this would work in old browsers, but it's a trick I've used a couple of times, and I've had no problems with it in Firefox, Chrome, or any of the later IE versions.
I think I see what you're asking here, from my understanding you want to send the new "page" asynchorously, and render the new javascript and html. It looks like you already got your request/response down, so i'm not gonna go and talk about sending JSON objects, and the whole "how-to" of sending html and javascript because it looks like you got that part. To do what you want and to dynamically add your javascript in, this stackoverflow question looks like it has what you need
Is there a way to create a function from a string with javascript?
So pertaining to your example, here is how it would look when you recieve the JSON string from your python script:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
/* Create function from string */
var newFunction = Function(response.javascript['param_1'], response.javascript['param_2'], response.javascript['function']);
/* Execute our new function to test it */
newFunction();
}
});
*Your actual function contents would be the string: response.javascript['function']
*Your parameter names if any would be in separate strings ex: response.javascript['param_1']
That is almost a direct copy of the "String to function" code that you can see in the linked question, just replaced it with your relevant code. This code is also assuming that your object is sent with the response.javascript object containing an array with your actual function content and parameter names. I'm sure you could change the actual name of the var too, or maybe put it in an associative array or something that you can keep track of and rename. All just suggestions, but hopefully this works for you, and helps you with your problem.
I am also doing similar work in my project where I had to load partial html using ajax calls and then this partial HTML has elements which requires events to be attached. So my solution is to create a common method to make ajax calls and keep a js method name to be executed post ajax call in html response itself. For example my server returns below html
<input type="hidden" data-act="onPartialLoad" value="createTableEvents" />
<div>.........rest of html response.....<div>
Now in common method, look for input[type='hidden'][data-act='onPartialLoad'] and for each run the method name provided in value attribute (value="createTableEvents")
Dont Use Eval() method as it is not recommended due to security
issues. Check here.
you can run js method using window["method name"]...so here is a part of code that I use.
$.ajax(options).done(function (data) {
var $target = $("#table_div");
$target.fadeOut(function () {
$target.html(data);
$target.fadeIn(function () {
try {
$('input[data-act="onPartialLoad"]', $target).each(function () {
try {
//you can pass parameters in json format from server to be passed into your js method
var params = $(this).attr('params');
if (params == undefined) {
window[$(this).val()]();
}
else {
window[$(this).val()]($.parseJSON(htmlutil.htmlDecode(params)));
}
} catch (e) {
if (console && console.log) {
console.log(e.stack);
console.log($(this).val());
}
}
});
}
catch (e) {
console.log(e.stack);
}
});
});
});
use jQuery.getScript() (as suggested by Kalimah Apps) to load the required js files first.
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.
I am currently trying to convert a lot of backend code to front end (to lighten the load on a small system).
The code at the moment calls a PHP function to return specific information. (e.g. image locations, strings, styling)
I am converting this code to its js equivalent, the content from Mysql was converted to JSON and stored in a read only file and I am accessing that file using this code:
<script>
function jsread(tag) {
$.getJSON("/strings.json", function(result){
document.write(result[tag]['value']);
});
}
</script>
I want the function to "print" where ever it is invoked. document write writes the value to the page but stops all other loading and write only the value.
Let me be very clear on this: I DO NOT want to use anything that needs extra calls or references out side of this function, that will take months of work so no getting elements by their IDs I have already view many questions on this subject and none are what I can work with. I need something that can be applied to every situation. Other wise I will just have to read the JSON using PHP as a middle compromise.
The problem here is, document.write()'s behaviour is crazy across all the browsers, because, it directly modifies the document object and messes up with the events attached. So it is always better to avoid this function as each browser defines it differently and has a different effect on the same code, with different browsers.
Is there a way to use them without a direct reference?
Solution
The wise thing is, as I said in the comments, it is better to use one of the jQuery functions safely, which create a textNode and insert it the right way, without affecting the others:
<script>
function jsread(tag) {
$.getJSON("/strings.json", function(result){
$("body").append(result[tag]['value']);
});
}
</script>
In case, if you wanna do something like having a placeholder and doing stuff, then you can try giving something like this:
$(function () {
var data = "Dummy Data, that would probably get returned from the getJSON";
// Inside the Success function, do this:
$("span.placeholder-of-the-json").replaceWith(data);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="placeholder-of-the-json">This gets replaced</span>