I confirm that the errors on on the object before I send them to the view
trip.riders.each{rider->
rider.errors.each{it->
//visually confirming to myself the errors are there
println it;
}
}
render(view:'edit',model:[trip:trip);
return;
The error I am confirming prints to console "Field error in object on field 'mileage'...."
Yet when rendered
<g:each in="${trip?.riders}" var="rdr" status='i'>
<div class='form-category'>
<div class='error'>
<g:hasErrors bean="${rdr}" field="mileage">
<g:renderErrors bean="${rdr}" field="mileage" as="list" />
</g:hasErrors>
No errors show up. What could be happening here?
UPDATE
I believe the problem is along these lines...
http://forum.spring.io/forum/other-spring-related/grails/97568-haserrors-true-disappears
Seems hibernate persists things in some instances in a way that causes validation errors to be cleared.
Try
<g:hasErrors>
<g:eachError> ${it} </g:eachError>
</g:hasErrors>
If you have added custom errors using "rejectValue()" method, validate() or save() method will remove custom errors added to the domain instance
Related
The code in controller is as follows:
for(o in options){
if(o){
if(!o.isInteger()){
don.errors.reject("The value was not integer")
render(view: "editdonation", model: [id:id, donation:don])
return
}
don.addToDenominations(o.toInteger())
}
}
I intentionally pass in invalid input so that the don.errors.reject() code is executed.
The editdonation.gsp has the following code to print the error in the donation object.
<ul class="inline-errors" role="alert">
<g:hasErrors bean="${donation}">
<div class="errors">
ok it has errors
</div>
</g:hasErrors>
</ul>
Why is the view not displaying the error? I appreciate any help!
The Errors.reject() method expects an error code rather than an error description.
Creating the error code
To create your own error code:
Edit the file grails-app/i18n/message.properties
Add a new line with your error code. Ex: option.donation.notinteger=The option value {0} was not an Integer
Save the file grails-app/i18n/message.properties
Using the error code
To use the error code, call Errors.reject() like this:
don.errors.reject('option.donation.notinteger', [o] as Object[], 'The value was not integer')
The code above passes the option to reject so that it can insert the value into the error message. And as required, it provides a fallback error message.
I am trying to move my website to Hack and XHP, of course. Below is a structure of what code structure I want to achieve:
<ui:backstageHeader>
<ui:backstageHeader-navItem href="/">stories</ui:backstageHeader-navItem>
<ui:backstageHeader-navItem href="/story/send">send a story</ui:backstageHeader-navItem>
<ui:backstageHeader-navItem href="/aboutus">support</ui:backstageHeader-navItem>
</ui:backstageHeader>
(Note: :ui:backstageHeader-navItem basically renders to <a href={$this->:href}>{$this->getCHildren}</a> so there is not need to attach its class here.)
Below is the code for :ui:backstageHeader:
final class :ui:backstageHeader extends :ui:base {
attribute :div;
children (:ui:backstageHeader-navItem)*;
protected function compose() {
$dom =
<section class="backstage-header">
<div class="container">
<div class="cell-logo">
<a href="/">
<span class="no23-logo-white"></span>
</a>
</div>
<div class="cell-navigation">
</div>
<div class="cell-account">
<div class="cell-login">
<div id="siteNav-login">Autentificare</div>
</div>
</div>
</div>
</section>;
$mainContainer = $dom->getChildren("div")[0];
$cellNavigation = $mainContainer->getChildren("div")[1];
$navItems = <ul class="main-navigation"></ul>;
foreach($this->getChildren() as $child) {
$navItems->appendChild(<li>{$child}</li>);
}
$dom->appendChild($navItems);
return $dom;
}
}
I used the Terminal to debug my code using hhvm -m d <file.php>, and everything was alright there; however, when I get to my browser, I get 500 error header. This is what the log says:
Catchable fatal error: Hack type error: Could not find method getChildren in an object of type XHPChild at /var/www/res/ui/backstage-header.php line 25
The error comes from
$cellNavigation = $mainContainer->getChildren("div")[1];
But, somehow, I need to append ul.main-navigation to div.cell-navigation from my section.backstage-header.
How can I do it?
Don't structure your code this way. Built it up from the inside out, so that you don't have to do a ton of unreadable getChildren calls looking for specific children. Those calls are super hard to read, and super inflexible when you change the structure of your XHP. You wouldn't do something like node.firstChild.lastChild.lastChild.firstChild in the JS DOM, would you? No, there's a better way in JS, to find things by class or ID; in XHP, you can just build it up the right way in the first place!
I'd give you an example of this, but it doesn't look like you actually use $mainContainer or $cellNavigation, so you can just remove those two problematic definitions.
As an aside, you really shouldn't be getting your type errors as catchable fatals from HHVM; this is a last resort sort of check. Try running the hh_client checker directly, maybe even showing its result in your IDE; it will give you a much faster iteration cycle, and much more information than HHVM provides.
From my experience, appendChild is very prone to human error. It's easier to do something like:
$items = (new Vector($this->getChildren()))->map($child ==> <li>{$child}</li>);
return <div id="container">{$items}</div>;
If you want to wrap the children in <li />.
Not sure if that will work but it will be close.
Pro tip: You can assign variables from within an XHP tree.
$root =
<div>
{$child = <span>
Text children
</span>}
</div>;
Now $child is already set to the <span> element.
I have the next constraint in my domain object usuario/Usuario.groovy:
phone blank: false, matches: "[0-9 -+()]{3,15}"
And I have in i18n/messages_es.properties:
usuario.telefono.matches=Se admiten nĂșmeros, espacios y los caracteres: -+(). Se admiten entre 3 y 15 caracteres en total.
This is the error message if the phone doesn't match the pattern:
The translation of the message would be something like: "Please, adjust the requested format"
I have not any similar error message in any of the i18n/messages... files. It looks a client side error message as it appears instantly.
In create gsp there is the next code (I think the error message could come from here):
<g:hasErrors bean="${usuarioInstance}">
<bootstrap:alert class="alert-error">
<ul>
<g:eachError bean="${usuarioInstance}" var="error">
<li <g:if test="${error in org.springframework.validation.FieldError}">data-field-id="${error.field}"</g:if>><g:message error="${error}"/></li>
</g:eachError>
</ul>
</bootstrap:alert>
</g:hasErrors>
How could I change this error message by a custom one?
The first thing you have to understand: this message is html form validation error and doesn't connected to your application messages. So the fix will be in html. Try to add oninvalid attribut to input tag:
<input type="text" name="phone" pattern="[0-9 -+()]{3,15}" required="" value="" id="phone" oninvalid="setCustomValidity('Please, type valid phone number')">
You can move 'Please, type valid phone number' to i18n file
Edit: if you use fields plugin add oninvalid attr with input- prefix.
<f:field bean="${usuarioInstance}" property="phone" input-oninvalid="setCustomValidity('Please, type valid phone number')"/>
I think you are missing 'invalid' as part of the message key.
Use the following error code for matches:
className.propertyName.matches.invalid = 'errorMessage'..
Still if it doesn't work ..try the following approach.
Add def messageSource in controller /service.
user.errors?.allErrors?.each{
println messageSource.getMessage(it, null)
};
Go through the following link which explains this better
http://johnrellis.blogspot.com/2010/02/retrieve-grails-domain-errors-from.html
I'm passing an object to a view and am getting a null reference exception, but the object is not null.
In the Action I have this simple code:
return View(db.Users.First());
View code:
#model User
#using DG.WEB.Models
#{
ViewBag.SecondTitle = "Ver";
ViewBag.MostraEditarTab = "false";
ViewBag.MostraApagarTab = "false";
ViewBag.Tab = "tab2";
Layout = "~/Views/Conds/_Layout.cshtml";
}
<div class="container">
#if (Model != null)
{
<h5>#Model.Nome</h5>
<div id="container_atalhos">
<div class="btn-group">
<i class="icon-th-large"></i> Nova frac
<i class="icon-fire"></i> Nova OcorrĂȘncia
<i class="icon-shopping-cart"></i> Novo Fornecedor
<i class="icon-file"></i> Novo documento
<i class="icon-pencil"></i> Editar
<i class="icon-remove-circle icon-white"></i> Apagar
</div>
</div>
}else{
#:Not found
}
</div>
EDIT:
I just test a small code that prints the name of the first user in the view.
And it happens to me the same error!
The try / catch apparently works badly ... I do not understand.
Look at the picture
EDIT2:
I found the error. In the layout page there was an error and for some reason visual studio didnt detect it.
Thanks to all.
Usually such error are not directly related to the place where they blow up, but a consequence of IoC / Dependency Injection.
What basically happens is that in the background, the dependency injection is able to provide various objects as needed, but does this is a lazy fashion. So if something - like your layout page - isn't needed yet, it won't be created yet.
So then when you access something like your model, which can have internal requirements needing something like your layout, then the dependency injection kicks in, throwing an error at your model, even though the error is not model-related at all.
This is one of the really difficult aspects of dependency injection and will probably plague you again in the future :(.
There is also no best-practice I know of to avoid this. Your approach to gradually cornering the issue is the best way to go ahead AFAIK.
Since we've updated to grails 2.0.1 (from 2.0.0) all of our beans shown via bean fields are incorrectly displayed as the first property of that "withBean" field. In the example I've posted below, all of [firstName, lastName, dateOfBirth, contactNumber] are shown as just 'firstName' (we know it's not just the messages which are wrong because otherwise the 3rd property (dateOfBirth) would be a date picker, not just a text field).
Any potential workarounds or suggestions?
(plugins.bean-fields=1.0-RC3)
I encountered the same problem, and have a work-around.
I has customised beanfield templates extracted into a gsp template called /shared/_beanfieldConfig.gsp , which I then included by rendering before calling any beans tags. e.g.
<g:render template="/shared/beanFieldConfig" />
<bean:withBean beanName='command'>
<bean:input property='username' />
This worked nicely in 1.3.7, and meant I could share beanFieldConfig between views.
When upgrading to 2.0.3, I enountered the same issue as the original question. I've found I can work around this by inlining the content of my _beanFieldConfig in each view.
Yuk, but at least it means I don't need rewrite all my views to use the replacement plugin (yet).
(edit)
Interestingly, although beanField config in a render'd template doesn't work, sticking it in a taglib DOES.
so, while previously I had in beanFieldConfig
<bean:inputTemplate>
<div class='input ${errors ? 'errors' : '' }'>
${label}
${field}
<g:if test="${errors}">
${errors}
</g:if>
</div>
</bean:inputTemplate>
If I define the equivalent tag -
def beanFieldConfig = {
bean.inputTemplate { m ->
m.with {
""" <div class='input ${errors ? 'errors' : '' }'>
${label}
${field}
${errors ?: ''}
</div>"""}
}
}
and then in my gsp replace <g:render template="/shared/beanFieldConfig" /> with <g:beanFieldConfig/>, it works.