In Config.groovy one can specify default constraints that will apply to all properties, e.g.
grails.gorm.default.constraints = {
'*'(nullable: true)
}
Is there a way to specify default constraints for properties of a certain type? For example, if I want to add a (blank: false) constraint for all String properties is there a way to do that?
Not sure about adding a default constraint for a certain type, but in Programming Grails, Burt suggests a filter to handle blank fields:
class SiteFilters {
def filters = {
blankToNullAndTrim(controller: '*', action: '*') {
before = {
if (request.post) {
convertBlanksToNullsAndTrim(params)
}
true
}
}
}
private static void convertBlanksToNullsAndTrim(Map map) {
def keys = [] + map.keySet() // copy to avoid
//ConcurrentModificationException
for (name in keys) {
def value = map[name]
if (value instanceof String) {
value = value.trim()
if (value.length() == 0) {
map[name] = null // don't remove - explicity set to null
} else {
map[name] = value // update if trimmed
}
} else if (value instanceof Map) {
// recurse with empty nested param, e.g., "location":["id":""]
convertBlanksToNullsAndTrim value
}
}
}
}
With that there's no need to add blank:false.
Also, in Grails 2.3.x this behavior changed: by default all blank and empty Strings will be converted to null during data binding (configurable).
Related
My modelView:
public string Status {
get { return _status; }
set {
if (value == _status) {
return;
}
_status = value;
OnPropertyChanged ("Status");
}
My View:
Label labelStatus = new Label {
TextColor = Color.Green,
FontSize = 20d
};
labelStatus.SetBinding (Label.TextProperty, "Status");
Then I want to present the status using something like:
string presentStatus = string.Format("Your status is {0}...", labelStatus);
Label yourStatus = new Label{Text=presentStatus}
But that doesn't really work. Nor does using
string presentStatus = string.Format("Your status is {0}...", SetBinding(Label.TextProperty,"Status"));
So how should I do to add my bound values with more text before presenting them for the user in a view.
If using XAML (which i don't), it seems possible according to: http://developer.xamarin.com/guides/cross-platform/xamarin-forms/xaml-for-xamarin-forms/data_binding_basics/
Xamarin Forms binding implementation doesn't currently allow complex binding scenarios like embedding bound text within static text.
There are two options
a. use multiple labels - one with the static text, one with the bound text
b. use a property on your ViewModel that concatenates the text for you
public string StatusText
{
get
{
return string.Format("Your status is {0}...", Status);
}
}
public string Status {
get { return _status; }
set {
if (value == _status) {
return;
}
_status = value;
OnPropertyChanged ("Status");
OnPropertyChanged ("StatusText");
}
You can do that in the BindingContextChanged-event:
labelStatus.BindingContextChanged += (sender, e) =>
{
// Here you can change the Text dynamically
// E.G. labelStatus.text = "Title: " + labelStatus.text
};
public class Service {
String reviewChanges
String comment
static constraints = {
reviewChanges (inList:['NO','YES'])
comment validator: { val, obj ->
if(reviewChanges=='YES') {
(nullable:false, blank:false, minSize:1, maxSize:500)
} else {
(nullable:true, blank:true, minSize:1, maxSize:500)
}
}
}
}
Above comment validator does not work for me.
I want if reviewChanges field selected YES then Comment field must be Mandatory field else Comment filed Non-Mandatory
The best way working with custom validators would be like this..
static constraints = {
reviewChanges(inList:['NO','YES'])
comment validator: { val, obj,errors ->
if (obj.reviewChanges == 'YES' && StringUtils.isEmpty(val)) {
errors.rejectValue('comment',"some.custom.validation.key")
}
}
}
errors.rejectValue will allow you to give proper field errors using propertyName and also you can use it for parameterized error...
errors.rejectValue('propertyName','errorCode',errorArgs as Object[],'defaultMessage')
and define errorCode is message.properties to access errorArgs like
errorCode = This is {0} first parameter being passed as errorArgs.
Thanks
You could do something like this I think (I haven't tested this, but you get the idea):
static constraints = {
reviewChanges(inList:['NO','YES'])
comment validator: { val, obj ->
if (obj.reviewChanges == 'YES' && StringUtils.isEmpty(val)) {
return "some.custom.validation.key"
}
}
}
Unless there is a requirement to have reviewChanges as a String, I would make it a Boolean field and using Groovy truth, you should be able to do something like:
class Service {
Boolean reviewChanges
String comment
static constraints = {
comment nullable:true, minSize:1, maxSize:500, validator: { val, obj ->
if (obj.reviewChanges && (!val)){
return "comments.required"
}
}
}
}
using Grails 2.3.3
I have a problem in registering custom property editor. I register it like this:
class BooleanEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Boolean.class,
new CustomBooleanEditor(CustomBooleanEditor.VALUE_YES, CustomBooleanEditor.VALUE_NO, false))
registry.registerCustomEditor(Boolean.class,
new CustomBooleanEditor(CustomBooleanEditor.VALUE_ON, CustomBooleanEditor.VALUE_OFF, true))
}
}
But the only first is applied. Is it possible to register more then one?
You can only set one property editor per class. If you are using Spring's CustomBooleanEditor, you can either use the default values ("true"/"on"/"yes"/"1", "false"/"off"/"no"/"0") with the one-arg constructor, or exactly one string each for true and false. If you need something more flexible, you'll have to implement your own property editor. For example:
import org.springframework.beans.propertyeditors.CustomBooleanEditor
class MyBooleanEditor extends CustomBooleanEditor {
def strings = [
(VALUE_YES): true,
(VALUE_ON): true,
(VALUE_NO): false,
(VALUE_OFF): false
]
MyBooleanEditor() {
super(false)
}
void setAsText(String text) {
def val = strings[text.toLowerCase()]
if (val != null) {
setValue(val)
} else {
throw new IllegalArgumentException("Invalid boolean value [" + text + "]")
}
}
}
I need to perform some initialization when new instances of my domain class are created.
class ActivationToken {
String foo
String bar
}
When I do this I want bar to be initialized by code inside ActivationToken:
def tok = new ActivationToken(foo:'a')
I cannot see how to 'override' the 'constructor' to make this happen. I know in this case I could just add a normal constructor but this is just a simple example.
The map constructor is coming from Groovy - not Grails in this case. I did some experimentation, and this is what I came up with:
class Foo {
String name = "bob"
int num = 0
public Foo() {
this([:])
}
public Foo(Map map) {
map?.each { k, v -> this[k] = v }
name = name.toUpperCase()
}
public String toString() {
"$name=$num"
}
}
assert 'BOB=0' == new Foo().toString()
assert 'JOE=32' == new Foo(name:"joe", num: 32).toString()
Basically, it appears that you'll have to manually override the constructors if you need to process the property after construction.
Alternately, you can override individual setters, which is cleaner and safer in general:
class Foo {
String name = "bob"
int num = 0
public void setName(n) {
name = n.toUpperCase()
}
public String toString() {
"$name=$num"
}
}
assert 'bob=0' == new Foo().toString()
assert 'JOE=32' == new Foo(name:"joe", num: 32).toString()
Note that the default value isn't processed, but that should be OK in most instances.
The solution above is also good for cases where initializing an object from parameters in a web request, for example, where you wish to ignore extraneous values, catching Missing property exceptions.
public Foo(Map map) {
try {
map?.each { k, v -> this[k] = v }
}
catch(Exception e){
}
}
I have a few forms configured in symfony. One things I need is to have an asterisk (*) or other indicator next to fields that are required. The fields are all set to required int he form framework, and return a "this field is required" error when the form is submitted, but I want an indicator before the form is submitted.
If there any way to do this without overriding the labels for each field manually?
Here's an automatic solution found in Kris Wallsmith's blog:
lib/formatter/RequiredLabelsFormatterTable.class.php, this will add a 'required' class to the labels of required fields
<?php
class RequiredLabelsFormatterTable extends sfWidgetFormSchemaFormatterTable
{
protected
$requiredLabelClass = 'required';
public function generateLabel($name, $attributes = array())
{
// loop up to find the "required_fields" option
$widget = $this->widgetSchema;
do {
$requiredFields = (array) $widget->getOption('required_fields');
} while ($widget = $widget->getParent());
// add a class (non-destructively) if the field is required
if (in_array($this->widgetSchema->generateName($name), $requiredFields)) {
$attributes['class'] = isset($attributes['class']) ?
$attributes['class'].' '.$this->requiredLabelClass :
$this->requiredLabelClass;
}
return parent::generateLabel($name, $attributes);
}
}
lib/form/BaseForm.class.php, this is the common base class for all the forms in your project:
protected function getRequiredFields(sfValidatorSchema $validatorSchema = null, $format = null)
{
if (is_null($validatorSchema)) {
$validatorSchema = $this->validatorSchema;
}
if (is_null($format)) {
$format = $this->widgetSchema->getNameFormat();
}
$fields = array();
foreach ($validatorSchema->getFields() as $name => $validator) {
$field = sprintf($format, $name);
if ($validator instanceof sfValidatorSchema) {
// recur
$fields = array_merge(
$fields,
$this->getRequiredFields($validator, $field.'[%s]')
);
} else if ($validator->getOption('required')) {
// this field is required
$fields[] = $field;
}
}
return $fields;
}
add the following few lines to BaseForm as well, in the __construct() method:
$this->widgetSchema->addOption("required_fields", $this->getRequiredFields());
$this->widgetSchema->addFormFormatter('table',
new RequiredLabelsFormatterTable($this->widgetSchema)
);
After all this, all your labels will have the required class, use whatever css you need to mark it to the user.
What about the simpler solution from the original cookbook - just a few lines in twig:
http://symfony.com/doc/2.1/cookbook/form/form_customization.html#adding-a-required-asterisk-to-field-labels
you can set the field's class as part of the constructor of the sfWidget
i.e.
$this->widgetSchema['form_field'] = new sfWidgetFormInput(array(), array('class' => 'required_field'));
Note: this is assuming you're not on the ancient sfForms (ala 1.0)
UPDATE
here is some CSS code from techchorus.net to show the required asterisk
.required
{
background-image:url(/path/to/your/images/dir/required-field.png);
background-position:top right;
background-repeat:no-repeat;
padding-right:10px;
}
I did it using Javascript:
$('form').find('select, input, textarea').each(function(){
if($(this).attr('required') == 'required'){
$label = $('label[for='+ $(this).attr('id') +']');
if($label.find('.required-field').length == 0){
$label.append('<span class="required-field">*</span>');
}
}
});