How can I pre-populate a hidden form field in grails? - grails

I have just gotten started with Grails and I have a very basic application running. I want to pre-populate a hidden form field with a random string.
What is the best way to do this? I have looked at the taglib but I am not sure what the best practice is for this sort of thing. Should I create a class in the src/java or src/groovy folder or is there a better way to get this done?
Lastly, and I know this is a very basic question, but if I do create a class or taglib, how exactly is that called from within the .gsp page?
Thanks!

If your action looks like this
def create() { [orgInstance: new Org(params)] }
it means that a new Org object is passed to your view which can be referenced as orgInstance
Since the model [orgInstance: new Org(params)] is a map, you can simply add another parameter:
def create() { [orgInstance: new Org(params), hiddenValue: 'something random'] }
This can be used in your .gsp in the following way:
<input type="hidden" name="test" value="${hiddenValue}" />
Regarding your other question: a custom taglib is used in the same way as the other Grails-Tags: <g:myTag ...>...</g:myTag> . You can change the namespacegto whatever you like -g` is the default. See the documentation for more details: http://grails.org/doc/latest/ref/Tag%20Libraries/Usage.html

Related

How to filter in a g:select?

I am new to Grails and gsp. I tried to find documentation on if this was possible - I found a similar question but was not able to successfully apply it.
I have this g:select statement:
<g:select name="users" multiple="multiple"
optionKey="id"
optionValue="name"
value="${user?.users*.id}"
from="${user.getUsers()}"
/>
I was wondering if it was possible to add a filter to this, or a condition. I can only select users that are in a certain country (users.country).
I was wondering if it was possible to add a filter to this, or a
condition.
It is.
It looks like you have a user property in the model and that object is an instance of some class that has a collection named users.
Something in your app is putting user in the model, likely a controller action. Best practice is to not embed much logic in a GSP so I would recommend either the controller do the filtering and put the qualifying objects in a separate model variable that the GSP can reference instead of user.getUsers(), or you could create a custom GSP tag which accepts a user and generates the select.

Thymeleaf th:field model evaluation

I'm including dynamic content to a view using a custom Thymeleaf attribute processor that simply adds additional nodes while processing the attribute itself.
The code I use is very similar to the one below:
final Template template = arguments.getTemplateRepository().getTemplate(
new TemplateProcessingParameters(arguments.getConfiguration(), "name-of-a-view", arguments.getContext()));
final List<Node> children = template.getDocument().getChildren();
// Add to the tree.
for (final Node node : children) {
element.addChild(node);
}
This works fine, but breaks when the included nodes contains forms that use th:object and th:field.
I put the model I need inside the node variable map and in fact th:object does find and retrieves the object, but th:field does not seems to care and breaks with a
Neither BindingResult nor plain target object for bean name 'model' available as request attribute
From my understanding (step-by-step debugging), it seems to me that th:field only search for the model in the request context.
Am I missing something here?
Thank you in advance.
No, you're spot on. I'm still not sure why the binding is different for th:field than other th: attributes, but it definitely works differently. Essentially, you can't use th:field unless your th:object is on the model. The workaround is to stop using th:field and just specify your input attributes manually, like:
<form action="#" th:action="#{/process}" th:object="${objectFromList}" method="post">
<input type="text" id="fieldName" name="fieldName" th:value="*{fieldName}" />
</form>
I realize this post is old. Hopefully, this will help someone who is running into this quirk.

Grails - How to fine tweak events/actions?

I'm very new to Grails so pardon me, what I want to do may be very obvious to others. It will help me understand Grails and how the underlying magic works (or not work). Answers must be in Groovy/Grails, no javascript since I understand how javascript works.
Say I have the files:
User.groovy
UserController.groovy
I'm using scaffolding to CRUD the records in the USER table. Now I want to tweak it a bit.
in file User.groovy:
class User {
String name
static constraints = {
name blank: false
}
}
I want UserController.groovy(Is this the file I should edit?) to check if the submitted username is Bill, then automatically replace username with William then continue to create record in database.
In the web form I type in the name field: Bill and click SUBMIT
After the database is updated, I check the record and the username should be William in the USER table database.
Question #1 (Basic) How can I do this?
Now for something a bit trickier, what if after the William record is created in db#1, and I want to connect to a different db#2 and insert William in the USER table there?
So when I click SUBMIT once, both records will be inserted in 2 different databases almost simultaneously? What this action would do is insert the record in db#1 then connect to db#2 and then do the same insert in serial.
Question #2 (Intermediate) Where do I look in the Grails folders/files to modify this action behavior?
You have to create view which is associated with your controller. In that view, you have to create form, that will enable users to enter username, something like this:
<g:form controller="user" action="save">
<g:textField name="username"/>
<g:submitButton name="save" value="save"/>
</g:form>
Now when user sumbits the form, save action of user controller is invoked. All parameters that where passed to controller action is being held in params map. So in your save action, you can access username like this:
def save = {
def user = new User(username: params.username)
// OR
def user = new User(params)
// you can change username like so
user.username = "William"
user.save()
}
This is very quick example, I advise you to study documentation and some tutorials maybe which will give you more knowledge of all the concepts and tools that Grails provides for you.
With writing user to two databases there is a slight problem. Grails doesn't provide ability to have multiple databases connected to your app out of the box. There is a plugin, called Datasources which allows you to define multiple data sources in your application, but the drawback is that you have to define which domain classes are connected to which data source. Thus you can't have a user domain class for your primary database and secondary, you have to create two domain classes, one for each data source.
I'll just answer the basic :)
Yup, you can do it in UserController.groovy. Say, you have this form:
<g:form action="someAction" method="post">
<input type="text" name="name" ... />
...
</g:form>
In the controller, you can have an action like this (there are multiple possible approaches):
def someAction = {
def nameVar = params.name // get the text this way
// process nameVar here
}
As for the database access... depends how you want to approach it. Grails suggests that you do something like:
User theUser = //get the user
theUser.name = //the value
theUser.save(flush:true)
However, I've encountered time and again some issues with Hibernate so I don't always use that approach. Instead, I do the usual Java-like programming like:
...
theUser.executeUpdate("UPDATE <table_name> ...")
theUser.save(flush: true)
...
Then just select from the database
...
User.executeQuery("SELECT ...")
...
Hope this helps ;)
For Q#1 you should modify the save function in your controller. There you can check the parameters for a specific username or modify the new created user object as you like.
For Q#2 i reccomend you to have a look at the Datasources plugin
Q1: This is really a job for GORM Hibernate events as it involves business logic constraint for you domain.
beforeInsert(){
this.name = "William"
}
Q2: Using multiple data sources is integrated in Grails 2.0. No need for the plugin.

Custom Binding in ASP.NET MVC with naming-conventions

I've got a View where I use a naming-convention on my text-fields, to indicate what should be done with the content once it is posted back to my controller.
The format is similar to:
<input type="text" name="RegistrationLine#ID" />
for updates
<input type="text" name="CreateRegistrationLine#LineNumber" /> for create
Now since I'm using this Naming-convention, regular model-binding isn't possible. But I've been reading up a bit on the subject and did find a bit of an indication that it would be possible to write a custom model binder, that should be able to help parse and bind these form elements and instantiate the objects correctly.
Please read: Bind formValue to property of different name, ASP.NET MVC
This is a bit similar to what I am doing except, I have the additional complexity of having appended information in the formelement-name that I am trying to bind to.
Am I way off base here? and if not, can any of you drop a few lines of code to show how you would start this model-binder off..
If this is a very bad approach to what I am really trying to achieve, I would love to hear suggestions for better approaches. Just note that what I want to be able to do is post back both updates and creates in one go.
I kinda have to agree with #jfar and #omar. I don't think a custom model binder is where you want to be in this instance.
You can pass a complex type to your view and simply use the full stop like #jfar mentioned.
id="Model.Person.Name.FirstName" will happily bind to an object named Person that has a class in it called Name that has a property called FirstName.
Now if you want to do some special checks on the data you could implement a partial class which would do the validations etc and populate the ModelState errors.
public partial class Name
{
public void Validate(){ }
public int CreateRegistrationLine(){ }
public bool DoSpecialActions(){ }
}
It's a little unclear what your special actions are doing so my example above may not be what you want.

Grails: Supplying Data to a Global UI Element

Please pardon this newbie question...
In Grails, if I want a partial to be embedded in a layout so that it appears globally, which requires live data, let's say a list of categories, where is the best place to pull the category data to feed it into the view?
I realize this is a very basic question, but I haven't seen this covered in any tutorials yet.
I started this as a comment to Bill James's answer but I figured it might be longer. Bill suggeseted using groovy code inside ${} to make the template (called partial in Rails) work globally:
<g:each in="${ Category.findAll() }" var="cat" />
But, you should not just add code if you dont feel like it might mess up your tidy xml/html. You can always put it in a closure inside a TagLib and thus make it a Tag. The closure must have no parameters, or an 'attr' parameter, or an 'attr' and 'body' parameters but other signatures are invalid.
class CustomTagLib {
static namespace = 'cus'
def categories = { attr, body ->
g.each( in: Category.findAll(), var: attr?.var ?: 'categories' )
}
}
Then you can use that tag into the template with the namespace you chose:
<cus:categories />
Personally I prefer using tags since most of the time it is a reusable code, so it's better for not violating the DRY principle.
You want to put it in grails-app\views\layouts\main.gsp. That's the default layout that most generated code (and likely most examples that you'll see) will use.
Check out the sitemesh section of the grails documentation.
I think you're trying to ask... "How do I feed the category data to the view when I don't know which action caused the page to render, so the action can't add the data to the model?" If that's so, you can use Groovy code directly in the ${} block, such as:
<g:each in="${ Category.findAll() }" var="cat" />
Note that findAll is added to every Model class, and can be called statically (via the classname, not an instance).
Hope this helps

Resources