Grails - render Map from controller via Ajax using JSON - javascript

I know this is a recurrent/classical topic but I did not found anything that helped me so far.
I am trying to render a Map from my controller. This results from an Ajax request and is supposed to be "eaten" by a Javascript function 'onSuccess'.
Here is my Javascript and .gsp view:
<g:javascript>
function updateVideoLoad(e) {
var map = eval("("+e.responseText+")") // evaluate the JSON
$('#resultsChecker').html(map.urlAccepted + ' - ' + map.provider + ' - ' + map.videoId + ' - ' + map.videoTag)
}
</g:javascript>
<g:formRemote name="myForm" update="" url="[controller: 'project', action:'addVideo']" onSuccess="updateVideoLoad(e)">
...
</g:formRemote>
Here is my controller:
import grails.converters.JSON
class ProjectController {
def addVideo() {
...
def videoMap = [urlAccepted: videoList[0], provider: videoList[1], videoId: videoList[2], videoTag: videoList[3]]
render videoMap as JSON
}
It looks to me exactly as the example provided in the Grails documentation.
However it does not work. On the browser console, I get:
Uncaught ReferenceError: e is not defined
from my g:remoteForm.
Any suggestion is most welcome.
Thank you for your help.

I'm guessing here, but it looks like a mistake in the documentation. I would expect that this part:
onSuccess="updateVideoLoad(e)"
^^^
Should really be:
onSuccess="updateVideoLoad(data,textStatus)"
^^^^^^^^^^^^^^^^^
Looking at the generated code (under Grails 2.0), these are the variables used in the returned:
<form onsubmit="jQuery.ajax({type:'POST',data:jQuery(this).serialize(), url:'/project/addVideo',success:function(data,textStatus){updateVideoLoad(e);},error:function(XMLHttpRequest,textStatus,errorThrown){}});return false"
method="post" action="/project/addVideo" id="myForm">
Look at the success property in the generated code.

This seems to be working:
<g:formRemote name="myForm" update="" url="[controller: 'project', action:'addVideo']" onComplete="updateVideoLoad(XMLHttpRequest)">
Is there a place where to get documentation on those javascript events (onComplete, onSuccess, ...) ?

This appears to be a documentation bug. If using JQuery (the default as of Grails 2.0) The variable should be 'data' not 'e' and it will contain your JSON object that you returned from your controller, and there is no need to eval or parse it like in the docs.

I had the same problem, but I'm using Dojo.
If you use dojo, you shoud use the variable name 'response':
onComplete="updateVideoLoad(response)"
It works fine for Dojo.

Related

How to pass JavaScript variable to Symfony route using Twig path function

I have a small problem with a Javascript variable in a Twig template,
what I want is to pass a variable as a parameter (in a url) to a function. All I have found on StackOverflow is how to pass a string 'blablabla' to the URL like:
url/{param}, {'param' : 'blablabla'}
but I want something like :
$var =...;
url/{param}, {'param': $var}
this photo should make it clear to you , thanks for reading
photo
I advise you to use the FOS JsRouting bundle. It is totally suited to what you want to do.
Here is the official documentation : https://symfony.com/doc/current/bundles/FOSJsRoutingBundle/usage.html
Example in Twig :
Routing.generate('your_route_with_params', { param: varJavascript });
Enjoy

Dynamic use of g:message in Javascript

is there an easy way to use the g:message functionality in a dynamic way in Javascript, e.g.
function get_i18n( myAttr ) {
return "${message(code:'" + myAttr + "')} ";
}
so that I can perform the function call
pl_get_i18n( "xyz" )
for the predefined i18 attribute xzy ?
Like here, but dynamic: https://stackoverflow.com/a/8296812/1779814
PS: The JS code is included in the GSP file.
The short answer is "no". GSP tags can only be executed on the server-side, not by the browser (i.e. JavaScript).
However, I would expect there is at least one Grails plugin that does the following:
creates a JavaScript object containing the messages defined in your messages*.properties file(s)
provides a JavaScript function that enables you to resolve messages from this object
So although it's not possible to execute GSP tags in the browser, it doesn't seem terribly difficult to provide equivalent functionality in JavaScript. I would be amazed if there isn't already a Grails plugin that does this.
Here is a very simplistic example of how you can use AJAX to fetch a message code from the server.
// AjaxMessageController.groovy
package example
import grails.converters.JSON
class AjaxMessageController {
def index() {
render [message: message(code: param.code)] as JSON
}
}
Then within your page you can just use an ajax call (jQuery based) in this example to look up a message code:
var someMessageCode = 'something.you.want';
$.ajax({
dataType: 'json',
url: '${createLinK(controller: "ajaxMessage", action: "index"}',
data: {code: someMessageCode},
success: function(data) {
window.alert(data.message);
}
});

JQuery Unable to get property 'json' of undefined or null reference

Im building a windows 8 app (html)
And have a api im fetching data from.
I keep getting this error however
0x800a138f - JavaScript runtime error: Unable to get property 'json' of undefined or null reference
in my scripts1.js file. then my program crashes -_-.
Here is the the code i use
$(function () {
startRefresh();
});
function startRefresh() {
setTimeout(startRefresh, 10000);
var url = 'http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=132';
$.getJSON('http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20json%20where%20url%3D%22' + encodeURIComponent(url) + '%22&format=json', function (data) {
jQuery('#ticker').html(data['query'].results.json.return.markets.DOGE.lasttradeprice);
jQuery('#ticker').append(' ' + data['query'].results.json.return.markets.DOGE.secondarycode);
jQuery('#ticker2').html(data['query'].results.json.return.markets.DOGE.lasttradetime);
jQuery('#ticker3').html(data['query'].results.json.return.markets.DOGE.volume);
});
}
This is located in scripts1.js Then i use ect.
It works everything comes and displays just get that error. Not sure what to do.
Seems like data['query'].results is undefined. Pasting the JSON you get will help.
Also, one small piece of advice: If you are going to access an in-depth attribute and, specially, a DOM node several times, you might want to recycle a reference to it rather than travelling again and again to fetch it for performance reasons. Something like this:
var ticker = jQuery('#ticker');
var DOGE = data['query'].results.json.return.markets.DOGE;
ticker.html(DOGE.lasttradeprice);
...
It looks like, occasionally, the API will send back some JSON that, when parsed, doesn't contain a results object. To mitigate this you should put a condition in to catch this eventuality.
if (data.query.results) {
jQuery('#ticker').html(data['query'].results.json.return.markets.DOGE.lasttradeprice);
// rest of DOM update code
}
Demo.

How to access an HTML template argument passed from controller in a Javascript function

My app is using the play framework mvc setup. In the controller I am passing a parameter while rendering the template, like this:
public static void scenario(){
...
render(active_brands);
}
Now in my HTML page "scenario.html", I can access the parameter using the play framework tags like this:
#{list items:active_brands, as:'c'}
...
#{\list}
Or using JQuery inside an HTML table like this:
<td>${active_brands.get(1)}</td>
Just for reference, the passed in parameter is a List.
However, I am trying to access the parameter "active_brands" from a javascript function and I am not sure how to do that.
I thought using Jquery to access the variable would work and I tried to access the variable like this:
function update_brands(active_scenario_ids){
...
alert('Reached: '+ ${active_brands});
}
but that does not work. It seems to me that the HTML attribute is out of scope for the javascript function. Is that true?
It would be great if someone can help me with this. Thanks.
This works for me using Play 2.2.0:
Application.scala (controller):
def index = Action { implicit request =>
val message = "This is a test."
Ok(views.html.test(message))
}
test.scala.html (view template):
#(message: String)
<script type="text/javascript">
$(document).ready(function(){
console.log("#message");
});
</script>
Console output:
This is a test.
The root of the problem was that my template variable, which is accessible in client side HTML, was of type java.util.List, which is not accessible by client side code ie. javascript. However, it is recognized in the play tags because play tags are server side code written in client side. So the only solution I could find for reading Objects inside java collections is returning a JSON object.
Therefore I had to change my code such that instead of returning a Java List as a template variable, I retrieve the data as a JSON object through an ajax call.
$.ajax({
url: '/getBrands/',
type: 'POST',
data: {active_scenario_ids: active_scenario_ids},
dataType: "json",
success: function(data){
console.log(data);
},
error: function(req, status, error){
alert("R:"+req+"S:"+status+"E:"+error);
}
});
}

Dynamically writing Javascript code?

I am creating dynamic sites with the same code base, where I will need to display the appropriate Google ads Javascript code, based on some logic.
In my .Net 4, MVC3 environment, I have setup the following scenario:
Navigating to www.mysite.com/script_processor/ returns the following text:
function doAlert(v1, v2){alert('Called alert()' + v1 + ' : ' + v2);}
This text come out of my model as such:
page.stringResponse = "function doAlert(v1, v2){alert('Called alert()' + v1+ ' : ' + v2);}";
I can then do something like this from a separate site/page:
<script type="text/javascript" src="http://mysite.com/script_processor/">
</script>
<script type="text/javascript">
doAlert('string 1', 'string 2');
</script>
As you would expect, I get an alert box with "Called alert() string 1 : string 2", so the function on mysite.com is accessible from site 2.
Obviously when I do a view source form the page, I only see the doAlert() call, and not the content of the function that sits on mysite.com.
Now, instead of doAlert() on mysite.com, I want to have a function that dynamically writes out javascript that can will be seen on site 2 when it's called.
I created a model method:
public GetResponsePage GetPageResponse(string V1, string V2)
{
var page = new GetResponsePage();
page.stringResponse = "<script type=\"text/javascript\">document.write('testing injected Javascript.');alert('value of v1: " + V1 + "value of v2: " + V2 + "');</script>";
return page;
}
When navigating to the route, I see the popup, and the "testing injected Javascript." on the page.
When I reference this from site 2, I don't see the popup, nor do I see "testing injected Javascript" in the page source.
As I mentioned I will later replace this with the JS code for the appropriate Google Ads js code.
I don't think this is working quite right... what am I missing?
Thanks.
You can use the ever evil eval to dynamically execute JavaScript. The JavaScript you pass in can also declare functions.
eval("function doAlert(v1, v2){alert('Called alert()' + v1 + ' : ' + v2);}");
I'm not sure exactly what you're trying to accomplish, but you could put an eval call like this wherever you want:
function createDoAlertFunction(){
eval("function doAlert(v1, v2){alert('Called alert()' + v1 + ' : ' + v2);}");
}
Just note though, that this should be avoided. Stick to declaring your functions the old fashioned way, like you already are.
EDIT
Oh, you want MVC to to inject JavaScript dynamically. MVC has a JavaScriptResult, but it looks like its use is strongly, strongly discouraged.
Nonetheless, here's a link that shows its use
public ActionResult DoSomething() {
string s = "$('#some-div').html('Updated!');";
return JavaScript(s);
}
and why it's not a good idea
I know it is very late. But there is very easy way to send JavaScript from controller.
#Html.Raw("<script>" + #ViewBag.DynamicScripts + "</script>")
In controller send JavaScript as follows:
ViewBag.DynamicScripts = "alert('test');";

Categories