I have a GSP page:
<g:if test="freelancer">
<g:each in="${ freelancer }" var="freelance">
${ freelance.firstName }
</g:each>
</g:if>
and an action:
def homepage() {
println(params.id)
def user = User.find{
username == params.id
}
if(user){
println(user.username + "!")
return[user:user]
}
}
and a welcome page:
<body>
Welcome ${ user.username }
</body>
in the first GSP page I get firstName link, and when I click on it to view his homepage I get an error:
Cannot get property 'username' on null object
But in the Console of my IDE, println(params.id) prints a username, BUT with square brackets. What is wrong in my code?
In your "homepage" action try
def user = User.find{ it.username == params.id } instead of
def user = User.find{ username == params.id }
Yes, you will have to use brackets in your tag. That's number one.
<g:if test="${freelancer}">
</g:if>
Otherwise, the groovy truth will always evaluate a non-empty string as true, thus your test will be flawed.
Also, I would use the g:link instead of html 'a' tag.
<g:each in="${ freelancer }" var="freelance">
<g:link controller='user', action='homepage', id="${freelance.user.username}">
${freelance.firstName}
</g:link>
</g:each>
As a suggestion, think of using User.findByUsername() instead of find closure.
Let us know if that works. ;)
This is my User domain class:
class User {
String username
String passwordHash
byte[] passwordSalt
Profile profile
static hasMany = [ roles: Role, permissions: String ]
static constraints = {
profile(nullable:false)
username(nullable: false, blank: false, unique: true, size:3..15)
passwordHash(nullable:false, blank:false, minSize:6)
}
static mapping = {
profile lazy:false
}
In the g:if tag I put freelancer to the brackets and changed to User.findByUsername(). But there is the same error. I don't want params.id as list.
Related
I have the following domain class:
class User {
String name
String contactName
String primaryEmail
String url
String phoneNumber
String address
static hasMany = [users: User]
static constraints = {
name blank: false
contactName blank: false
primaryEmail email: true
url blank: false
phoneNumber blank: false
address blank: false
}
}
And controller for the User:
class UserController {
def create() {
User user = new User()
[user: user]
}
def save(User user) {
if (!user.save(flush: true)) {
render (view : 'create', model: [user: user])
}
redirect action: 'create'
}
}
I want show validation errors in case if validation fails. My create.gsp looks like this:
<body>
<g:form action="save" >
<g:renderErrors bean="${user}"/>
<g:textField name="user.name" id="message" value="${user.name}"/>
<g:textField name="user.contactName" id="contactName" value="${user.contactName}"/>
<g:textField name="user.primaryEmail" id="primaryEmail" value="${user.primaryEmail}"/>
<g:textField name="user.url" id="url" value="${user.url}"/>
<g:textField name="user.phoneNumber" id="phoneNumber" value="${user.phoneNumber}"/>
<g:textField name="user.address" id="address" value="${user.address}"/>
<g:submitButton name="submit" value="Save"/>
</g:form>
</body>
</html>
But after sumbit of create.gsp with invalid data two strange thing happen
1) Despite the fact that all fields have value property mapped to some field of User bean all fields are empty
2) There are no validation errors on the page
What I'm doing wrong?
Thank you!
you must return after calling render() or use else
def save(User user) {
if (!user.save(flush: true)) {
render (view : 'create', model: [user: user])
return // either return here
}else // or else here
redirect action: 'create'
}
In your original code you redirect to create and pass no models into it
I am working on a Grails form item that just populates a list of FaqCategories from an FaqCategory domain class. All I want the select dropdown to do is display the list. So far, this sort of works, but I'm not sure how to generate the list or what to put in the Value section if anything.
Form item:
<div class="col-sm-9">
<g:select name="Category" from="${FaqCategory.list()}" required="" class="form-control" aria-labelledby="faqCategory-label" value=""/>
</div>
Domain class #1
class Faq {
String question
String answer
FaqCategory faqCategory
static constraints ={
question nullable:false, maxSize:1000
answer nullable:false, maxSize:1000
faqCategory nullable:false
}
}
Domain class #2
class FaqCategory {
String categoryType
String toString(){
"$categoryType"
}
static constraints = {
categoryType nullable:true, maxSize:100, unique:true
}
}
Controller snippet
#Transactional(readOnly = true)
def create() {
respond new Faq(params)
}
Controller code :
yourAction(int id){
//do some
def faqInstance = Faq.get(id)
render[view:"form",model:[faqInstance:faqInstance]]
}
View code :
<g:select name="faqCategory"
from="${FaqCategory.list()}"
value="${faqInstance?.faqCategory?.categoryType}"
optionKey="id" />
Hope it helps..
You haven't provided enough information to show the context in which this select is being used so it is hard to say exactly what you need, but something like this should work:
<g:select name="faqCategory"
from="${FaqCategory.list()}"
value="${you only need this if you want to preselect a value}"
optionKey="id" />
See http://grails.org/doc/latest/ref/Tags/select.html for more details.
I hope that helps.
I use html encoding for my form input fields. I have a form to create a new user object, where one can insert a name for the new user. To prevent this input field from script injection I do encodeAsHTML() in the save() action listed below.
The problem:
1. the entered name is: Schäfchen
2. this would be validated correctly after my validation rules below
3. html encoding transform ä into \auml which will fail the validation
How can I achieve that the name which in html encoded will be correctly validated?
Given the following Grails class:
class User {
String name
static constraints = {
name blank: false, validator: { val, obj ->
Pattern pattern = Pattern.compile("[a-zA-Z0-9äöüßÄÖÜ\\- ]+")
pattern.matcher(val).matches()
}
}
}
in my UserController.groovy:
dev save() {
def name = params?.name?.encodeAsHTML()
def user = new User()
user.name = name
user.save()
}
You should use encodeAsHTML() only in your GSP views.
See: http://grails.org/doc/latest/ref/Tags/each.html
<tbody>
<g:each status="i" in="${itemList}" var="item">
<!-- Alternate CSS classes for the rows. -->
<tr class="${ (i % 2) == 0 ? 'a' : 'b'}">
<td>${item.id?.encodeAsHTML()}</td>
<td>${item.parentId?.encodeAsHTML()}</td>
<td>${item.type?.encodeAsHTML()}</td>
<td>${item.status?.encodeAsHTML()}</td>
</tr>
</g:each>
</tbody>
I have a registration form that contains fields related to two domain objects; User and Profile. The relationship is a 1:1 mapping owned by the User domain class.
A 'register' action on the User controller marshals the form values, and provided there are no validation errors, persists the user object and redirects to the applications root when the form is submitted. Otherwise, the controller will redirect back to the registration form showing pre-populated fields with failed values.
However, in practice, when validation fails, the failed values aren't displayed in the view. Below is the code for the register action:
def registration = {
}
def register = {
def user = new User()
bindData(user, params)
if (user.save()) {
flash.message = 'Successfully Registered User'
redirect(uri: '/')
}else {
flash.message = 'Registration Failed!'
redirect(action: registration, params: [ user: user ])
}
}
Below is an example html excerpt from the view showing User and Profile related fields:
<div class="row">
<label for="city"> City, State: </label>
<g:textField id="city" name="profile.city"
value="${user?.profile?.city}" size="28" />
<span class="red">*</span>
</div>
<hr />
<div class="row">
<label for="email"> E-mail address: </label>
<g:textField id="email" name="userId" value="${user?.userId}" size="28" />
<span class="red">*</span>
</div>
Syntactically, everthing looks okay; I'm using appropriate naming conventions and grail's interpolation for acessing values, so I'm at wits end as to why this isn't behaving as expected.
Any comments or suggestions would be appreciated.
Thanks,
-Tom
If i remember correctly i thought it was something in the lines of:
def user = new User()
user.properties = params
You need to somehow pass the submitted values from user in register action to user in registration action. Like this:
if (params.user) {
user.properties = params.user.properties
}
Try explicitly calling the erorr?
Ive been using this pattern to redirect back to the same form.
if (user.save()) {
...
} else {
return error()
}
I normally use command objects in webflows, so my normal pattern looks like:
def registerFlow = {
registerPage = {
on("submit") { FormDataCommand cmd ->
cmd.validate()
if (cmd.hasErrors()) {
flow.cmd = cmd
return error()
} else {
...
}
}
}
}
class FormDataCommand implements Serializable {
User u
Profile p
static constraints = {
u(validator: { it.validate() })
p(validator: { it.validate() })
}
}
I am having hard time getting hasErrors to work with indexed properties. For example
class Order {
String prop1
String prop2
static hasMany = [items: Item]
}
class Item {
String name
static constraints = {
name(blank:false)
}
}
Validation works properly and on item.name being blank I do get an error with
<g:renderErrors bean="${orderInstance}"/>
However, I am trying to have input box highlighted using hasErrors :
<g:each in="${orderIntsance.items}" status="i" var="item">
<span class="field ${hasErrors(bean: orderInstance, field: ????????? , 'errors')}">
<g:textField name="items[${i}].name" value="${item?.name}"/>
</span>
</g:each>
Not sure how to get to it with a field: property, any ideas?
Thanks
Found it, got to implement a custom validator per Grails Validation doc page (duh):
"In some situations (unusual situations), you might need to know how to transfer an error from a nested child object to a parent domain object. In some circumstances, if you validate the children objects before the parent object, then the errors on the children objects will get reset before the object is sent to the JSP." (http://www.grails.org/Validation)
static constraints = {
children( nullable:true, validator: {val, obj, errors ->
def errorFound = false;
val.each{ child ->
if(!child .validate()){
errorFound = true;
child .errors.allErrors.each{ error->
obj.errors.rejectValue('children', "parent.child.invalid",
[child, error.getField(), error.getRejectedValue()] as Object[],
"For source [${child}],
field [${error.getField()}] with value [${error.getRejectedValue()}] is invalid.")
}
}
}
if(errorFound) return false;
})
}
I had a similar requirement and tried the following way and it worked. Just wanted to share it
${hasErrors(bean: orderInstance, field: 'items['+ i +'].name', 'errors')