I'm wondering how I can populate a text box in my view from a list in my controller, I have been searching for examples for awhile, but haven't really found anything. I'm uncertain on how to access the text field from the view exactly, where as in Java you could do something as simple as jTextField.getText(). I'm also wondering on how to grab the text in my text box as well.
Below I'll post some example code of what I'm doing.
Controller:
def loadFile = {
def propFile = "c:/props.txt"
def propMap = [:]
def propList = []
new File(propFile).eachLine { line ->
def (key,value) = line.split(':').collect { it.trim() }
propMap."$key" = "$value"
if(propMap) {
propList << propMap
propMap = [:]
}
}
}
def saveFile = {
//get contents of text box
//over-write props.txt with new information
}
View:
<g:textField name="properties"/>
<span class="menuButton"/><g:link action="loadFile" controller="myController">Load File</g:link>
<span class="menuButton"/><g:link action="saveFile" controller="myController">Save File</g:link>
So, my question seems relatively straight forward, how do I access the text box when I want to populate it and save the data from it?
.
.
.
EDIT
After checking out some of the examples submitted by you guys, I have one last question.
Why does the following code act different when clicking the Load File button?
<g:form controller="drive">
<g:textArea name="properties" value="${params.param1}" rows="50" cols="6"/>
<br/>
<g:submitButton name="loadFile" value="Load File"/>
<g:submitButton name="saveFile" value="Save File"/>
</g:form>
<span class="menuButton"/><g:link action="loadFile" controller="drive">Load File</g:link>
When clicking the g:submitButton dealing with loadFile it redirects me to the list gsp. However, when I click the menuButton it loads the textArea with the text from the file. The reason I ask is because with the second option, the button isn't located where I would like it to be.
Wrap your text field in form tag. This way, when you submit it, you can access your field in controller.
<g:form controller="myController" action="saveFile">
<g:textField name="properties"/>
<g:submitButton name="saveFile" value="Save File" />
</g:form>
Then, you can access your properties field in controller:
def saveFile = {
def properties = params.properties
// do whatever you need
}
EDIT:
To address some of the issues that came up later in comments, I'll try to provide some more insight.
Let's assume that your controller is called Drive and view (the form to submit properties) is drive/properties.gsp. If want your load button to load your properties into the text area, you can do something like this:
def loadFile = {
// your code here
render(view: 'properties.gsp', model=[properties:propList])
}
And in your view:
<g:form controller="drive">
<g:textArea name="properties" value="${properties?.join("\n")}" rows="50" cols="6"/>
<br/>
<g:actionSubmit name="loadFile" action="loadFile" value="Load File"/>
<g:actionSubmit name="saveFile" action="saveFile" value="Save File"/>
</g:form>
This should render your form with values from your file, each property in new line. But I didn't test it.
jjczopek's answer shows how to get access to the data in the controller after it has been submitted from the view.
You can pass a default value through from the controller to the view by setting a parameter in the controller eg...
params.param1 ='value to pass'
render(view:"testView")
Then in your view you can retrieve it again with...
<g:textField name="text1" value="${params.param1}"/>
You may also find this question and these docs useful.
If want to pass domain objects through then one of the following specific render methods might be better...
Grails Controller - Render
Related
In my application, I have search button and based on the search criteria, I have to search data. I have used few hidden variables to store data.
My .gsp page looks like this:
<g:form id="job" name="job" method="POST">
<div>
<input type="hidden" id="country" name="country" value="${country}"/>
<input type="hidden" id="paginationFlag" name="paginationFlag" value="${paginationFlag}"/>
<!-- There are other components like text field, select box etc -->
<g:actionSubmit id="Search" value="Search" formmethod="post" action="findJob"/>
</div>
</g:form>
My respective controller method looks like this:
def findJob(){
def country
def paginationFlag
if(params?.country){
country = params?.country
}else{
country = 'USA'
}
if(params?.paginationFlag){
paginationFlag = params?.paginationFlag
}else{
paginationFlag = 'false'
}
withFormat{
html{
List<Applicant> searchList //get data from database.
// other business logic
render(view : "jobList",model:[paginationFlag: paginationFlag, country:country])
}
json{
// some business logic
def candidateList // value for this candidateList is acquired from database
def json = ['jsn': candidateList]
render json as JSON
}
}
When I click search button and debug the code, first my control goes to controller-> findJob() method and executes the code inside html part.
Secondly, it goes to the gsp page (view page) and sets value.Third, it again goes to the controller and executes the code inside json part.
On the first entry to the controller, the value of paginationFlag and country in param are both null. So it will set the value 'false' and 'USA' respectively. But when control goes to controller again for the second time, again the value of param.paginationFlag and params.country are null. Should not they have the assigned values?
Why is it so? What should I do go get the value of country and paginationFlag in params on the second time? Can any one explain me ? Thank you very much for advance.
The problem is you're using a regular HTML input tag rather than a Grails g:hiddenField tag. Try this:
<g:form id="job" name="job" method="POST">
<div>
<g:hiddenField name="country" value="${country}"/>
<g:hiddenField name="paginationFlag" value="${paginationFlag}"/>
<!-- There are other components like text field, select box etc -->
<g:actionSubmit id="Search" value="Search" formmethod="post" action="findJob"/>
</div>
</g:form>
Tip
You can also simply the params assignment:
def country = params.country ?: 'USA'
def paginationFlag = params.paginationFlag ?: 'false'
I can't tell where the paginationFlag comes from, but know that a boolean is valid.
If I have an action def formPage(), I want to be able to save the form on that page, show the form with the previously entered values if there's an error, and show a blank form if it's a success.
My question is: Is it best practice for formPage to call something like saveFormPage(FormPageCommand fpc)? saveFormPage can then render formPage with or without the previously entered values. The problem with this approach is that the user can click the address bar, press enter, and then get a slew of errors since the form hasn't been filled in, and the command object sees all the null or blank values.
Another approach might be to just have a def formPage(FormPageCommand fpc), and ignore errors and just show a blank form if none of the values are filled in.
One might also call saveFormPage(FormPageCommand fpc) and redirect back to formPage() if none of the values are filled in.
What is the best practice here?
Try this example:
Your controller
class MyFormController {
def formPage() {
[cmd: new FormPageCommand()]
}
def saveFormPage(FormPageCommand cmd) {
if (cmd.hasErrors()) {
render view: "formPage", model: [cmd: cmd]
} else {
// Process form
// ......
// Redirect back formPage() to display a new form
redirect action: "formPage"
}
}
}
Your command object
class FormPageCommand {
String optionalValue
String requiredValue
static constraints = {
optionalValue(nullable: true, blank: true)
requiredValue(nullable: false, blank: false)
}
}
Your formPage.gsp
<g:form controller="myForm" action="saveFormPage" method="POST">
<label>Required value *</label>
<g:textField name="requiredValue" value="${cmd.requiredValue}"/>
<g:if test="${cmd.errors.getFieldError('requiredValue')}">
<g:message error="${cmd.errors.getFieldError('requiredValue')}"/>
</g:if>
<label>Optional value</label>
<g:textField name="optionalValue" value="${cmd.optionalValue}"/>
<g:submitButton name="submit"/>
</g:form>
It should serve your need.
Cheers.
I'm not sure I fully understand your question, but to get you started I recommend the book "Grails in Action". It contains a lot of best practices and chapter 7 on data binding and error handling may give you some good advice and ideas.
I encountered this problem before and solved it this way:
My registration form has a button:
<g:submitButton name="register" value="Register" />
So the incoming params map should have the "register" key with "Register" value.
Then I check the existence of this parameter in my controller:
def register(UserRegisterCommand urc) {
if (params.register) {
//some registration actions
}
}
In other words I check in the controller if the "Register" button was clicked, if yes - then perform registration actions. If no - the "register.gsp" is rendered.
I hope this will help.
I have a form which should print questions dynamically. Foo has a Field object and a Field Definition object. I want the Field to have its fieldDefinition assigned by the form. All of the behind the scenes stuff works fine.
The below code works with assigning Strings and Longs in other scenarios.
Here's the line that's causing trouble:
<input th:type="hidden" th:field="*{fields[__${iterationStatus.index}__].fieldDefinition}" th:value="${fooViewModel.fields[__${iterationStatus.index}__].fieldDefinition}"/>
This is what it looks like when it renders in html:
<input type="hidden" value="com.blah.domain.FieldDefinition#fbb2e392" id="fields0.fieldDefinition" name="fields[0].fieldDefinition">
When I submit the form, no controller action is invoked, and the app simply redirects to the error page.
If it's impossible to actually do the assignment that way, please suggest other methods. The only way I came up with is to have Foo use the FieldDefinitionService to do the assignment after being passed an ID. I don't that Domain class to have access to another Domain object's Service.
Thanks
Just an example: when you need to iterate a form inside an element that has a th:each attribute, you can use the following structure (so far, it's the only way that's working for me).
<tr th:each="rank, stat : ${ranks}">
<td th:text="${rank.name}">This is static</td>
<td th:text="${rank.description}">This is static</td>
<td>
<form th:action="#{/user/ranks/delete}" method="post">
<input type="hidden" id="id" name="id" th:value="${rank.id}"></input>
<button class="btn btn-danger" type="submit">
<span>Delete</span>
</button>
</form>
</td>
</tr>
Here ranks is a list of entities that have to be displayed on a table and, for each entity, there is a delete button associated to a form.
The controller method should be similar to the following fragment, the parameter is availabled with the name id:
#RequestMapping(path = "/delete", method = RequestMethod.POST)
public View deleteRank(Model model, #RequestParam(name = "id") String rankId,
#ModelAttribute("user") User user)
{
Long id = Long.parseLong(rankId);
// delete ...
RedirectView redirectView = new RedirectView("/user/ranks");
return redirectView;
}
Here is my Grails (2.3.6) controller:
class WidgetController {
def index() {
render(
view: "createNew",
model:[
]
)
}
def execute() {
println "Executing form submission!"
redirect(action: "listAll")
}
def listAll() {
// Does some stuff
}
}
The index URL is, say, http://localhost:8080/myapp/widget. The idea is that when someone goes to this URL, they are presented with an HTML form. When they fill out the form, they are sent (on the server side) to the execute() method, which does some heavy duty stuff and then redirects them to the listAll() method which does some final stuff and renders a web page for them to see.
Here is the HTML form on the createNew.gsp (rendered from the index() method:
<g:form name="create-new-form" url="[action:'execute',controller:'widget']">
<table class="pure-table pure-table-bordered">
<tr>
<td class="row-header">Fizz:</td>
<td><g:textField id="app-fizz" name="fizz" /></td>
</tr>
<tr>
<td class="row-header">Buzz:</td>
<td><g:textField id="app-buzz" name="buzz" /></td>
</tr>
</table>
<g:actionSubmit value="Create" />
</g:form>
When I go to this URL and submit the form (clicking the Create button) I get redirected to http://localhost/myapp/widget/execute which displays one of my customized error pages (basically a "Sorry this page is unavailable"-type error.
Additionally, in the log outputs, my println stating "Executing form submission!" is not firing. This tells me that I don't have something wired correctly: Grails is trying to redirect to an /execute URL but somehow isn't linking that URL with my controller's execute() method. Ideas?
Try with:
<g:actionSubmit action="execute" value="Create" />
If you specify only value for g:actionSubmit it creates button with this label and also redirect to action based on this value. If action name is different than button label you should specify action and value attributes. Take a look at documentation.
Note that if you use g:actionSubmit then action attribute of g:form will be ignored (which you specified btw.). You'll find more info where it may be useful in docs linked above.
use plain <input type="submit" value="go"/>. thus the form is submitted to the URI defined in <g:form> tag
g.actionSubmit or g.submitButton are needed, if you want to submit your form somewhere ELSE.
I'm a newbie trying to find uses for Neo4J on Grails.
Basically, I've made 20 grocery item nodes through the Neo4J browser and I want to create a simple Grails site that will let users search a grocery item and visually show the items related to it.
My index.gsp has:
<input id="item" />
My viz.js has:
$('#item').keyup(function() {
var item = $('#item').val();
My Item Domain class has
class Item {
static mapWith = "neo4j"
String name
My ItemController class has:
def index() {
def item = Item.list() [item:item] //No idea, just trying out whatever i find :(
and a query with something like:
def query = Item.cypherStatic ("""start n=node({Item}) match (n)-[r]->(x) where r='partner' return n, x)
Questions:
How can I properly send the JS 'item' variable into the ItemController?
How can I use the 'item' variable to properly query the node names which have a 'partner' relationship with the item?
in addition to Motilals answers, you definetly need a wrapping form with an action that points your controller
like
<g:form controller="itemController" action="index" >
<input type="text" id="item" name="item" value="" />
<input type="submit" value="submit" >
</g:form>
then on clicking submit the for will call your index action and there you could parse the value with
def item = params.item
but it looks more like you want some asynchronous stuff right after keyup-function, therefore you could do sth like this :
$('#item').keyup(function() {
var item = $('#item').val();
$.ajax({
url: "${createLink(controller:'itemController', action:'index')}",
data:"&item="+item
})
.done(function( data ) {
console.log(data)
});
});
in this case, you need to pay attention what your index-action is returning, so you can do in the .done() whatever you want with the response.
also note, that when you name an action "index" it will be available at
.../myproject/item/index
or, and thats important
.../myproject/item/
so if your index method requires the data from the input, it will miss them if a user has gone straight to that url
so your index action would rather render the page with the input
and you define another action for executing your query based on input and returning data
set the item to hidden field and then you can access it directly in your controller using params
here you go:
//in index.gsp add below hidden field and set the hidden filed in your js code
<g:hiddenField name="item" value="" />
$('#item').keyup(function() {
var item = $('#item').val();
//in your controller
def index() {
def item = params.item
print item // you see the value for item
//do your stuff
}
once you have item value you could directly use HQL query or use the domain instance
hope this helps you
Regards
Motilal