Basic Grails question: How does the following Grails code define personInstance? - grails

This is the GSP code generated by Grails for the view of the edit action for a Person domain object which is part of my model, and also happens to be the primary class for authentication by the ACEGI security plug-in. I have snipped out a bunch of properties to keep it short. The file resides in the standard location, grails-app/views/person/edit.gsp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'person.label', default: 'Person')}" />
<title><g:message code="default.edit.label" args="[entityName]" /></title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLink(uri: '/')}">Home</a></span>
<span class="menuButton"><g:link class="list" action="list"><g:message code="default.list.label" args="[entityName]" /></g:link></span>
<span class="menuButton"><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></span>
</div>
<div class="body">
<h1><g:message code="default.edit.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:hasErrors bean="${personInstance}">
<div class="errors">
<g:renderErrors bean="${personInstance}" as="list" />
</div>
</g:hasErrors>
<g:form method="post" >
<g:hiddenField name="id" value="${personInstance?.id}" />
<g:hiddenField name="version" value="${personInstance?.version}" />
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="username"><g:message code="person.username.label" default="Username" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: personInstance, field: 'username', 'errors')}">
<g:textField name="username" value="${personInstance?.username}" />
</td>
</tr>
...SNIP...
a bunch of props
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><g:actionSubmit class="save" action="update" value="${message(code: 'default.button.update.label', default: 'Update')}" /></span>
<span class="button"><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?')}');" /></span>
</div>
</g:form>
</div>
</body>
</html>
My question is, how does the field personInstance get set up and populated?
I suspect this is a basic question which belies a fundamental lack of understanding on my part about how Grails works, but I need to know nonetheless.
This stems from the desire to create my own composite pages which access a Person object and its associated data, which is the heart of my app. I was expecting to be able to create a new page alongside this one, let's call it map.gsp, and get at the personInstance in some magic way. I can't figure out how to do that in spite of trying the obvious, and I think I have a gap right at the centre of my understanding.

PersonInstance will be populated on the controller.
When you submit your form, the associated controller will receive a map containing the fields present on your form.
So, in your controller you'll find a command like
personInstance.properties = params
where params is a map containing the fields submited for the controller, which the keys are the names of the input elements you defined on your gsp file.

Related

Why "href" and "th:href" exist at the same time?

I am reading a page using Thymeleaf.
In "Edit page", there is a "Back" button for going back to "User List Page". The strange thing for me is this button has "href" and "th:href" at the same time.
image detail of the button
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>user</title>
<link rel="stylesheet" th:href="#{/css/bootstrap.css}"></link>
</head>
<body class="container">
<br/>
<h1>修改用户</h1>
<br/><br/>
<div class="with:80%">
<form class="form-horizontal" th:action="#{/edit}" th:object="${user}" method="post">
<input type="hidden" name="id" th:value="*{id}" />
<div class="form-group">
<label for="userName" class="col-sm-2 control-label">userName</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="userName" id="userName" th:value="*{userName}" placeholder="userName"/>
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-2 control-label" >Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password" id="password" th:value="*{password}" placeholder="Password"/>
</div>
</div>
<div class="form-group">
<label for="age" class="col-sm-2 control-label">age</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="age" id="age" th:value="*{age}" placeholder="age"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="submit" value="Submit" class="btn btn-info" />
Back
</div>
</div>
</form>
</div>
</body>
</html>
It is obvious that "th:href" is for going back. Is there any opition on what is the function of the atrribute "href"?
ThymeLeaf is designed to use the same file for both as prototype you can view in your browser as well as a working template file. What this means in practice is that if you want, you can open the template file in a browser without actually running it and it still looks okay. For example, in this code:
Back
If you open the file directly in a browser, the browser will ignore the th:href (because it doesn't know what to do with it) and instead use href="/toAdd". However, when you run it through the templating engine on a server, href="/toAdd" is replaced with the result of the dynamic expression th:href="#{/list}".
This is more easily shown with a table. Like this:
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
</tr>
<tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
</table>
When you open that in a browser, you'll see a table with a single row (Onions, 2.41, yes). But when you run it through the server, the actual content of the table is replaced with whatever data exists in the ${prods} variable.

How can I make grails show me all columns/fields from the domain in the list-view

I've search all evening to find a solution but the few I found does not stick with the newer version of grails that I use.
I know that it was limited to 6 fields before but now I can see 7. But I need a lot more columns, no matter that the page will be cluttered.
I have also checked the code that the f:table tag constructs and can not see that there is any limitation there.
I do not know what to do, I need to have this application ready tomorrow morning so I'm desperate finding a solution.
Please help..
I use GRAILS-3.2.3.
I can take any domain just it have more than 7 fields the 8th and upwards will not be displayed.
I use the grails command: ("generate-all" domain) to create controllers and views. And without doing anything more I get this problem.
Therefore I didn't think I needed to bring any code to show - anyone trying to this should get the same problem.
Below is the template for index.gsp -- Can anyone explain where the limitation of number of columns is made here?
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
<g:set var="entityName" value="\${message(code: '${propertyName}.label', default: '${className}')}" />
<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><a class="home" href="\${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
<li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
</ul>
</div>
<div id="list-${propertyName}" class="content scaffold-list" role="main">
<h1><g:message code="default.list.label" args="[entityName]" /></h1>
<g:if test="\${flash.message}">
<div class="message" role="status">\${flash.message}</div>
</g:if>
<f:table collection="\${${propertyName}List}" />
<div class="pagination">
<g:paginate total="\${${propertyName}Count ?: 0}" />
</div>
</div>
</body>
</html>
I've made my last trial tonight, I'll continue tomorrow morning again because I think I need to hard code everything to get ready.
It was a nice advice to have a look at that "Anorak-Girl" report, but the source of the f:table-tag didn't show any limitation - so where can it be?
Thanks a lot but there's still a lot to do....I'll come back and good night.
Below is the code of _table.gsp or f:table-tag.
<table>
<thead>
<tr>
<g:each in="${domainProperties}" var="p" status="i">
<g:set var="propTitle">${domainClass.propertyName}.${p.name}.label</g:set>
<g:sortableColumn property="${p.name}" title="${message(code: propTitle, default: p.naturalName)}" />
</g:each>
</tr>
</thead>
<tbody>
<g:each in="${collection}" var="bean" status="i">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<g:each in="${domainProperties}" var="p" status="j">
<g:if test="${j==0}">
<td><g:link method="GET" resource="${bean}"><f:display bean="${bean}" property="${p.name}" displayStyle="${displayStyle?:'table'}" /></g:link></td>
</g:if>
<g:else>
<td><f:display bean="${bean}" property="${p.name}" displayStyle="${displayStyle?:'table'}" /></td>
</g:else>
</g:each>
</tr>
</g:each>
</tbody>
</table>
possibly a limitation around f:table. Having had a look around:
http://blog.anorakgirl.co.uk/2016/01/what-the-f-is-ftable/
Finally… how to customise the f:table tag:
Place a file called _table.gsp in /grails-app/views/templates/_fields/
To do this manually:
An example and here you can iterate through your own property manually.
so in your case
<g:each in="\${${propertyName}List}" var="myDom">
<tr><td>${myDom.id}</td><td>${myDom.name}</td><td>and so on</td></tr>
</g:each>
In Grails 5, naming the properties explicitly in the f:table in the index.gsp view was the first way I got it to work for me, e.g.:
<f:table collection="${companyList}"
properties="name,url,hqLocation,area,yearFounded,revenue,fundsRaised,founder,product"/>
Alternatively, instead of naming the properties explicitly, you can set the attribute maxProperties (default 7) to a higher number, or to zero to display all properties.
<f:table collection="${companyList}" maxProperties="0"/>
To make this the default when creating future list views, install the templates and edit the index.gsp template file
grails install-templates
vi src/main/templates/scaffolding/index.gsp
and make the same change there.

remoteField not triggering action call

So I am attempting to create a search field that will filter contacts on the fly. So I have the main results being displayed in a template (Contact/list.gsp):
<%# page import="contactmanager.Contact" %>
<!doctype html>
<html>
<head>
<meta name="layout" content="main">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<g:set var="entityName" value="${message(code: 'contact.label', default: 'Contact')}" />
<title><g:message code="default.list.label" args="[entityName]" /></title>
</head>
<body>
<div id="list-contact" class="mainContent-contact" role="main">
<h1><g:message code="default.list.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<div id="searchBox">
Instant Search: <g:remoteField name="q" update="searchResults" paramName="q" url="[controller:'contact', action:'search']"/>
</div>
<g:render template="searchResults"/>
<div class="pagination">
<g:paginate total="${contactInstanceTotal}" />
</div>
</div>
</body>
Here is my template (_searchResults.gsp):
<%# page import="contactmanager.Contact" %>
<div id = "searchResultsDiv">
<table>
<thead>
<tr>
<g:sortableColumn property="firstName" title="${message(code: 'contact.firstName.label', default: 'First Name')}" />
<g:sortableColumn property="lastName" title="${message(code: 'contact.lastName.label', default: 'Last Name')}" />
<g:sortableColumn property="phone" title="${message(code: 'contact.phone.label', default: 'Phone')}" />
<g:sortableColumn property="email" title="${message(code: 'contact.email.label', default: 'Email')}" />
<g:sortableColumn property="title" title="${message(code: 'contact.title.label', default: 'Title')}" />
<g:sortableColumn property="jobFunc" title="${message(code: 'contact.jobFunc.label', default: 'Job Func')}" />
</tr>
</thead>
<tbody>
<g:each in="${contactInstanceList}" status="i" var="contactInstance">
<g:if test="${contactInstance.isActive}">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${contactInstance.id}">${fieldValue(bean: contactInstance, field: "firstName")}</g:link></td>
<td>${fieldValue(bean: contactInstance, field: "lastName")}</td>
<td>${fieldValue(bean: contactInstance, field: "phone")}</td>
<td>${fieldValue(bean: contactInstance, field: "email")}</td>
<td>${fieldValue(bean: contactInstance, field: "title")}</td>
<td>${fieldValue(bean: contactInstance, field: "jobFunc")}</td>
</tr>
</g:if>
</g:each>
</tbody>
</table>
</div>
So currently, when I enter my text, nothing is happening. I added a printout in my search method and that's not being called at all. It's almost as if my remoteField is stagnant and is not active.
Am I missing a pre-requisite to this tag? I looked at the official API online, but didn't see anything at all indicating such. Is there something new to 2.0.0?
I am using the searchable plugin to pull results in the Controller, just FYI.
Thank you all for the help!
Update: So I added the javascript library call explicitly in my main.gsp and I seem to be getting some response back from the server, which is great news (missingPropertyException):
I had to add the plugin definition to the library call of jQuery (library = jquery and plugin= query)
First, thank you to those with the advice. I was able to figure out Firebug was a useful tool and that output pointed me to my library calls.
So I am now seeing action from my server using the correct jQuery library call. My last problem was that I was referencing the template name in the update of the remoteField, not the name of the main div within the template.
Once I fixed those, I am working. Thanks for all advice!

Grails mapping questionnaire data to a bean

This is my first development using Grails. I have a requirement to create a questionnaire. This is my GSP page in which the questions are listed, possible answers for each question is listed and depending upon the type of answer a checkbox or radio button is displayed.It works fine till here
<div class="body">
<h1><g:message code="default.edit.label" args="[entityName]" /></h1>
<g:if test="${message}">
<div class="message">${message}</div>
</g:if>
<g:form action="createDonation" >
<div class="dialog">
<table>
<tbody>
<g:each in="${questionList}" status="i" var="questionInstance">
<tr>
<td>${fieldValue(bean: questionInstance, field: "text")}</td>
</tr>
<tr>
<g:each in="${questionInstance?.answers?}" status="j" var="a">
<td >
<g:if test="${fieldValue(bean: a, field: 'ansType.name') == 'Multiple'}"><g:checkBox name="myGroup" value="${false}" /></g:if>
<g:if test="${fieldValue(bean: a, field: 'ansType.name') == 'Single'}"><g:radio name="myGroup" value="1"/></g:if>
</td>
<td >${fieldValue(bean: a, field: "text")}</td>
</g:each>
</tr>
</g:each>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><g:submitButton name="return" class="save" value="${message(code: 'default.button.backtodonorlogin.label', default: 'Back')}" /></span>
<span class="button"><g:submitButton name="submit" class="save" value="${message(code: 'default.button.saveandcontinue.label', default: 'Create')}" /></span>
</div>
</g:form>
</div>
</body>
Now i want to save the response of the user i.e what is the answer selected by each user for each question. For Multiple choice multiple answers can be selected. I am having a hard time to figure out how to create a model for that.
Help is requested.
Thanks
how about this: you create a QuestionResponse entity with the following properties:
question (linking to the question being answered)
response (answer given by user)
responder (responding user)
You can find out about the current user by using spring security for instance.
You can determine the question being responded from the hidden ID in your form.

how to read selected radio button value in Grails?

I'm having a GSP page like below. The requirement is like a list of reports will be shown - the user has the option to select one report and can export the report to excel.
How to read the selected radio button and pass the selected value as "params" ?
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="layout" content="main" />
</head>
<body>
<div class="nav">
<span class="menuButton"><g:link class="create"
action="excelExport" params="['id':{ radId.value}]">Export To Excel</g:link>
</span>
</div>
<div class="body">
<div class="message">Select the report and click 'Excel Export'</div>
</div>
<g:form method="post">
<g:render template="displayUploadedReportsTemplate"
model="['uploadedReports':uploadedReports]" />
</g:form>
</body>
</html>
where displayUploadedReportsTemplate is:
<tbody>
<g:each in="${uploadedReports}" var="bbkRat">
<tr>
<td valign="top"><g:radio name="radId"
value="${fieldValue(bean:bbkRat,field:'id')}" /></td>
<td valign="top"><label> ${fieldValue(bean:bbkRat,field:'cmpName')}
</label></td>
<td valign="top"><label> ${fieldValue(bean:bbkRat,field:'reportCreationDate')}
</label></td>
<%--<td valign="top">
<label> ${fieldValue(bean:bbkRat,field:'cmpName')}
</label>
</td>
--%>
<tr>
</g:each>
</tbody>
How should the params value be below??
<g:link class="create"
action="excelExport" params="['id':{ radId.value}]">
i would recommand to use a radio button group. instead of using g:readio tag you can replace it with plain html input tag within you each tag, e.g.
<input type="radio" name="myGroup" value="1" checked="checked" />
<input type="radio" name="myGroup" value="2" />
<input type="radio" name="myGroup" value="3" />
you have already defined a form around your displayUploadedReportsTemplate. so you need to add a submit button to this form and a action where the params should be tramsitted, e.g.
<g:form method="post" action="test">
within test action you can print your params.myGroup and you will recieve to selected report.
<g:link is processed on server-side, so you can't use it on client side, you have to use javascript instead.
It would be like:
<a href="#" class="excelExport" onclick="doExport(); return false">
<script type="text/javascript">
function doExport() {
var id= $('input:radio[name=radId]:checked').val();
window.location = '${g.createLink(action:'excelReport')}?id=' + id;
}
</script>
ps I assume that you are using jQuery

Resources