I have a list with two buttons and I want that everytime that I press a button, work the code that I have associated to this button. This code is in a service, and the gsp file is a default list.gsp
To call the service from the gsp. I took this post:(How do I call a Grails service from a gsp?) to do it.
The problem is that I have two methods in the service and I don't know why, but always that I enter in the list.gsp and always that I press the button I can see display in the console of grails that the two methods are working at the same time.
This is that I can see in the console everytime I push button A or B:
2015-12-01 12:51:47,565 [http-bio-8090-exec-5]
hello
world
That I want is that if I press button A show this:
2015-12-01 12:51:47,565 [http-bio-8090-exec-5]
hello
and if I press button B show this:
2015-12-01 12:51:47,565 [http-bio-8090-exec-5]
world
And this is that I can see in the console everytime that I run and enter in the gsp.file and I want that don't run the code unless I press the button:
2015-12-01 12:51:47,565 [http-bio-8090-exec-5]
hello
world
Thanks in advance
This is my code in gsp:
<%# page import="com.app.test" %>
<%# page import="mypackage.myService" %>
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main">
<g:set var="entityName" value="${message(code: 'licenseType.label', default: 'LicenceType')}" />
<title><g:message code="default.list.label" args="[entityName]" /></title>
</head>
<body>
<g:message code="default.link.skip.label" default="Skip to content…"/>
<div class="nav" role="navigation">
<ul>
<li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
<% def LicenceTypeService =
grailsApplication.classLoader.loadClass('mypackage.myService').newInstance()%>
<li><g:link action="list"><g:message code="Calculate Licence Type" args="[entityName]" /><span>${myService.calculate()}</span></g:link></li>
<li><g:link action="list"><g:message code="Re-Calculate Licence Type" args="[entityName]" /><span>${myService.recalculate()}</span></g:link></li>
</ul>
</div>
In the service:
class MyService {
def calculate(){
println "hello"
}
def recalculate(VoiceUser vUser){
println "world"
}
}
I'm fairly certain this is impossible; what you are asking is to send an Ajax call directly to a grails service. If you think about it, once the generated HTML has been received by the client, there is not a direct connection between the browser and back-end (grails application) so there can't be any grails magic that allows this to happen.
There is a grails tag g:remoteLink that will allow Ajax calls to a controller action, the controller is necessary at this point because all new interactions once the generated html is in place must be through standard HTTP requests and requests are handled through grails controllers.
Your best bet would be to create a controller that wraps the 2 service methods and use the actions with g:remoteLink or another Ajax request.
As to using a service within a gsp, instead of instantiating a new service, I would argue in favor of using the existing spring bean.
Replace:
<%# page import="mypackage.myService" %>
...
<% def LicenceTypeService = grailsApplication.classLoader.loadClass('mypackage.myService').newInstance()%>
With:
<g:set var="myService" bean="myService"/>
Related
I am new to grails and groovy.
I am trying to find out how to render a response from an action in a grails controller IN THE SAME gsp - but in a DIFFERENT SECTION OF THE gsp - as the gsp that takes the request (in this case a web form gsp page)?
any links or turorials or just straight to the point "do this" kind of replies are welcomed.
I tried to google search for it, but I was not sure what to use as a search term and I could not find a concise answer.
========= UPDATE TO QUESTION (INCLUDING SOME CODE) =========
Here is the code I am working with. It is a Grails application in which I am using a bootstrap template (available for free on the internet of course).
Now the actual code itself for functionality works. What I am having an issue with is this:
I have a gsp page that uses a css template and another gsp temlate for layout. I can start the page as inside the gsp+css tempate using this code (snippet) in my gsp page:
<g:layoutBody/>
This allows me to call my calling controller code in this gsp file for the request:
<body>
<g:form name="form" controller="apiStart" id="form">
<div><g:select name="protocolType" value="restCall" from="${["-select-", "GET", "POST", "PUT", "DELETE"]}"/>   <label>URL: </label><g:textField name="url" value="${url}" />
  <label>username: </label><g:textField name="userName" value="${userName}" />   <label>password: </label><g:textField name="passWord" value="${passWord}" /></div>
%{--<div class="text-field"><label>URL: </label><g:textField name="url" value="${url}" /></div>--}%
%{--<div class="text-field"><label>username: </label><g:textField name="userName" value="${userName}" /></div>
<div class="text-field"><label>password: </label><g:textField name="passWord" value="${passWord}" /></div>--}%
<br>
<div><label>Use Advanced Parameters?</label><g:checkBox name="useAdvParms" value="${false}" /></div>
<div class="text-field"><label>Header1: </label><g:textField name="header1" value="${header1}" />   <label>Value1: </label><g:textField name="value1" value="${header2}" /></div>
%{--<div class="text-field"><label>Value1: </label><g:textField name="value1" value="${header2}" /></div>--}%
<div class="text-field"><label>Header2: </label><g:textField name="header2" value="${header3}" />   <label>Value2: </label><g:textField name="value2" value="${header4}" /></div>
%{--<div class="text-field"><label>Value2: </label><g:textField name="value2" value="${header4}" /></div>--}%
<br>
<div class="submit"><g:actionSubmit value="Submit" action="save"/></div>
</g:form>
</body>
And then this gsp code for the response:
<body>
<h3>API Test Results</h3>
API Tested: ${apiStart.url}, Response: ${apiStart.response3}
<br>
%{--<g:textArea name="myField" value="myValue" rows="20" cols="100"/>--}%
<div class="textarea"><label>Output</label><br><g:textArea name="myField" value="${apiStart.result3}" />
</div>
%{--Responce Code: ${apiStart.response3}<br>--}%
%{--Response: <br> ${apiStart.result3} <br>--}%
</body>
My issue: it works fine as separate pages. I want to render the results of the request on the same page as the calling request.
in the screen shot attached: I want to put the results in the text box where it says "Output Displayed here...."
I assumed templates in grails is the way to go about it. but I get a Java Null pointer exception when I try to insert the template into that part of the code.
Can someone advise and show me the best way to do this?
==================== END of Updated question ===================
thanks.
ironmantis7x
You can try using Grails templates.
Basically Template is a (reusable) part of a View.
Info:
So you create template file bookTemplate.gsp, put all the gsp/html code in there as usual (but just the part, if it will be used in the body, then don't add html, body, head tags etc.
Example:
<div class="book" id="${book?.id}">
<div>Title: ${book?.title}</div>
<div>Author: ${book?.author?.name}</div>
</div>
Then you render that template into the gsp page in places where you want them to be (with a simple grails render tag. And it will simply get compiled (as the code from template would be pasted into gsp view).
Render:
<g:render template="bookTemplate" model="[book: myBook]" />
I don't know your grails version, but on 2.4.5, and maybe on your version, you can use :
http://docs.grails.org/2.4.x/ref/Tags/submitToRemote.html
And have a look to the attribute update :
update (optional) - Either a Map containing the elements to update for
'success' or 'failure' states, or a string with the element id to
update, in which case failure events would be ignored
And you also can trigger javascript on some events, ...
In your action called in the submitToRemote button, you can render a template (but do not put your layout in this template if you render a template, otherwise you will have all you website structure rendered...) and it will be displayed in the HTML element with the ID that you have put in "update" property.
The example given in the link is interesting.
I have a domain class TmMessage for which I use generate-all to create the scaffolded controller and views. The auto-generated show() method looks like:
def show(TmMessage tmMessage) {
respond tmMessage
}
Scaffolding is defined in my BuildConfig.groovy:
plugins {
compile ":scaffolding:2.1.2"
}
The list of TmMessage objects is given by controller's method:
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond TmMessage.list(params), model:[tmMessageCount: TmMessage.count()]
}
The TmMessages are stored in a hasMany List of a parent object, TmBulkMessage, and I can see the TmMessages listed ok in when inspecting a TmBulkMessage. However, the list of TmMessage objects displays nothing (I can see a number of pages of TmMessage objects, but the details for them don't display). When I click on one of the links from the TmBulkMessage to look at a specific TmMessage object, nothing displays. I believe that's because the tmMessage being displayed is null.
The show() method is very different to what I've seen elsewhere, where it looks like (taken straight from Grails docs):
def show() {
def book = Book.get(params.id)
log.error(book)
[bookInstance : book]
}
The auto-generated unit tests all use the first method, so what's going on here please? Is there something missing from the scaffolded code?
EDIT:
From the Grails docs, what's new in 2.3 (I'm using 2.4):
Domain Classes As Command Objects
When a domain class is used as a
command object and there is an id request parameter, the framework
will retrieve the instance of the domain class from the database using
the id request parameter.
So it would appear that the domain class / command object interface provided by Grails is returning null.
FURTHER EDIT:
Thanks to Gregor's help, it would appear that the domain object binding is working ok, but that the respond isn't working as advertised.
The show.gsp is below:
<%# page import="com.example.TmMessage" %>
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main">
<g:set var="entityName" value="${message(code: 'tmMessage.label', default: 'TmMessage')}" />
<title><g:message code="default.show.label" args="[entityName]" /></title>
</head>
<body>
<g:message code="default.link.skip.label" default="Skip to content…"/>
<div class="nav" role="navigation">
<ul>
<li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
<li><g:link class="list" action="index"><g:message code="default.list.label" args="[entityName]" /></g:link></li>
<li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
</ul>
</div>
<div id="show-tmMessage" class="content scaffold-show" role="main">
<h1><g:message code="default.show.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<ol class="property-list tmMessage">
<g:if test="${tmMessage?.bulkMessage}">
<li class="fieldcontain">
<span id="bulkMessage-label" class="property-label"><g:message code="tmMessage.bulkMessage.label" default="Bulk Message" /></span>
<span class="property-value" aria-labelledby="bulkMessage-label"><g:link controller="tmBulkMessage" action="show" id="${tmMessage?.bulkMessage?.id}">${tmMessage?.bulkMessage?.encodeAsHTML()}</g:link></span>
</li>
</g:if>
<g:if test="${tmMessage?.message}">
<li class="fieldcontain">
<span id="message-label" class="property-label"><g:message code="tmMessage.message.label" default="Message" /></span>
<span class="property-value" aria-labelledby="message-label"><g:fieldValue bean="${tmMessage}" field="message"/></span>
</li>
</g:if>
</ol>
<g:form url="[resource:tmMessage, action:'delete']" method="DELETE">
<fieldset class="buttons">
<g:link class="edit" action="edit" resource="${tmMessage}"><g:message code="default.button.edit.label" default="Edit" /></g:link>
<g:actionSubmit class="delete" action="delete" value="${message(code: 'default.button.delete.label', default: 'Delete')}" onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" />
</fieldset>
</g:form>
</div>
</body>
</html>
The output of tmMessage?.dump() within show() is:
<com.example.TmMessage#6d6cf0a5 message=abc errors=grails.validation.ValidationErrors: 0 errors $changedProperties=null id=1 version=0 bulkMessage=com.example.TmBulkMessage : 1>
If I amend the gsp to read:
<ol class="property-list tmMessage">
<% System.out.println "tmMessage : " + tmMessage %>
Then I get "tmMessage : null" written to the console when I view the page.
I have changed show() to read:
def show(TmMessage tmMessage) {
respond tmMessage, [model: [tmMessage : tmMessage]]
}
Which appears to fix the rendering issue for show. I don't know what needs to be changed for index(). When I select "edit" from the show page, I get a blank textfield for the message field and I don't know if this is expected behaviour or not, but it would be much preferred if the field was preloaded with the existing value.
I think I know now what the problem is: respond has a really weird variable naming convention. If you respond with a single TmMessage instance, the variable will be called tmMessageInstance in the view. If you respond with a list of them, the variable will be called tmMessageInstanceList. If you return a set... well, you know what I mean.
So in the GSP code above you can probably replace all tmMessage with tmMessageInstance and get rid of [model: [tmMessage : tmMessage]] in the controller. A habit of mine is to explicitly test for the presence and type of every expected model variable in every single GSP I write, like so: <% assert tmModelInstance instanceof com.package.TmModel %>. Those lines then serve as documentation and if the controller passes something unexpected into your GSP (can happen frequently during active development, especially when filling the data model from services), your code fails quite obviously with a nice diagnostic message.
In my opinion a better option for Grails would be to stick to a single variable for respond renderers (e.g. model), document it in several places just so nobody misses this, and then people can detect what was in there when necessary (how often does it happen anyway that you don't know if you will have a list or a single instance for a single view/template?).
EDIT: Apparently you can use the Map syntax with respond and have it be used as the model to get fixed variable names, it was just poorly documented: https://github.com/grails/grails-doc/commit/13cacbdce73ca431619362634321ba5f0be570a1
With thanks to Gregor, whose help put me on the right track, the issue is with the generated code. It would appear that there is not a model being passed to the view, hence it's rendering nothing. Below are the changes to index(), show() edit()
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond TmMessage.list(params), model:[tmMessageCount: TmMessage.count(), tmMessageList : TmMessage.list(params)]
}
def show(TmMessage tmMessage) {
respond tmMessage, [model: [tmMessage: tmMessage]]
}
def edit(TmMessage tmMessage) {
respond tmMessage, [model: [tmMessage: tmMessage]]
}
This preloaded the text fields with the correct values.
I also had to amend the parameters sent when there was an error when creating by passing the model along with the desired view. Below is the example for save():
#Transactional
def save(TmMessage tmMessage) {
if (tmMessage == null) {
notFound()
return
}
if (tmMessage.hasErrors()) {
respond tmMessage.errors, [view:'create', model: [tmMessage: tmMessage]]
return
}
tmMessage.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'tmMessage.label', default: 'TmMessage'), tmMessage.id])
redirect tmMessage
}
'*' { respond tmMessage, [status: CREATED] }
}
}
This was happening me for when I had inheritance in my domain model.
For instance, if we have
class Vehicle {}
and
class Car extends Vehicle {}
The scaffolded controller action was passing carInstanceList into the view when the view was trying to render vehicleInstanceList.
As stated in previous answers, the respond method creates variable names by convention, the convention seems to fail here
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond Vehicle.list(params), model:[vehicleInstanceCount: Vehicle.count()] //actually injecting carInstanceList
}
Had to be changed to :
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
def vehicles = Vehicle.list(params)
respond vehicles, model:[vehicleInstanceCount: Vehicle.count(), vehicleInstanceList:vehicles]
}
I think it is to do with checking the class of the first element in the list maybe and if that is a car, naming it carInstanceList, if the first was a vehicle, the issue probably wouldn't present itself
I am new to Grails and I am trying to get a very simple example to work. I should just submit a form and display "Hello World" on the screen. It consists of the following controller:
package surface
class SearchController {
def index() {
render(view: "search")
}
def result() {
render "Hello World"
}
}
and a view, with the form:
<%# page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<g:form name="searchform" url="result">
<g:textArea cols="80" rows="30" name="searchfield"/>
<g:actionSubmit value="Ask"/>
</g:form>
</body>
</html>
When I click on "Ask" I get a 404 error but the browser correctly accesses "/surface/search/result". When I enter that address directly without using the form the "Hello World" appears correctly. This is probably a no-brainer but I seem to be unable to find out why this does not work from the documentation.
Complementing the #Tom Metz answer, what you need to keep in mind in the Grails controller structure is that every public method is considered an action. This action is mapped to a url. In your example will exists /search/index and /search/result (controller + action).
The documentation of the g.form is corret, since this says that;
url (optional) - A map containing the action,controller,id etc.
So to correct your view you can set the action as commented or you can adjust the way you use url:
<g:form name="myForm" url="[action:'result',controller:'search']">
I want to trigger the same dialog on different ids in my gsp.
So here is the code:
<div class="yui3-widget-bd">
<g:each in="deployments" status="index" var="workflow">
<% def id = "reloadFile"+index %>
<gui:dialog title="Reload File" form="true" modal="true"
controller="admin" action="reloadFile"
triggers="[show:[id:'${id}', on:'click']]">
<p>To reload the file, please...</p><br />
<input type="file" id="deploymentFile" name="deploymentFile" />
</gui:dialog>
</g:each>
</div>
The problem is that the scriptlet code :
triggers="[show:[id:'<%=id %>', on:'click']]"
is not getting evaluated.
The Javascript part that listens for events in the source of the generated html looks like this:
YAHOO.util.Event.addListener("${id}", "click", GRAILSUI.gui_e0100d149e0a7b531017e0decaee9fce.show, GRAILSUI.gui_e0100d149e0a7b531017e0decaee9fce, true);
So how can i manage that the source looks like this ? :
YAHOO.util.Event.addListener("reloadFile1", "click", GRAILSUI.gui_e0100d149e0a7b531017e0decaee9fce.show, GRAILSUI.gui_e0100d149e0a7b531017e0decaee9fce, true);
Thank you.
Same as jsps:
If you want to execute some code
<% def something = true %>
If you want to use the return of the execution
<%= something ? "This is a truth statement" : "This is false" %>
Beware that this is probably code smell and the code should be in a domain, controller or taglib 99.9% of cases.
Here's the reference documentation for more info.
I'm learning to use Grails and have run into a situation I don't understand when handing what should be a simple form submission.
I have created a controller called 'add' (there is an AddController.groovy source file and an appropriate add/index.gsp view) and have defined a very sparse 'process' action which currently renders a small amount of HTML to verify that the action is being called.
The URL for the process action on the add controller is (not surprisingly) http://localhost:8080/frontend/add/process/.
I would like to submit a very simple form to the process action as a first step towards integrating with some existing Java libraries.
Sending a GET request to http://localhost:8080/frontend/add/process/ causes the process action to be called and the browser to display the relevant simple HTML content.
Sending a POST request to http://localhost:8080/frontend/add/process/ returns a HTTP 404 error.
I appreciate I'm missing some fundamental addition to my application such that the above action works with both GET and POST requests. I had assumed by default the request type would not matter.
I'd be very happy at this stage if I can send a POST request to the appropriate action and have some markup rendered just to demonstrate that things are working.
What fundamentally essentials piece of the puzzle am I missing?
controllers/frontend/AddController.groovy:
package frontend
class AddController {
def index = { }
def process = {
render "<h1>process action being performed</h1>"
}
}
views/add/index.gsp
<html>
<head>
<title>Test View for index action</title>
<meta name="layout" content="main" />
</head>
<body>
<g:form controller="add" action="process">
<label for="title">Title:</label>
<g:textField name="title" id="title" />
<label for="content">Content:</label>
<g:textArea name="content" id="content" />
<g:actionSubmit value="Add" />
</g:form>
</body>
</html>
The <g:actionSubmit /> directive needs an action attribute to indicate the action to be handled. I had assumed the form action would have been sufficient.
I needed to change:
<g:actionSubmit value="Add" />
to:
<g:actionSubmit value="Add" action="process" />