Bind a form field in Play 2.0 with a constant value? - forms

I have a scala form with several fields.The fields in the form map to the member variables of a Java class. I want to bind one of the fields(say userId) with a value (I dont want the user to enter values for this field. Instead i want to pass this as a parameter to the scala template). However, i was unable to manually bind a form field. Any help is highly appreciated.
See the sample below for easier understanding :
`#(itemForm: Form[Item], user: User)
#import helper._
#main("Item list") {
#if(user != null) {
#form(routes.Application.newItem()) {
#itemForm("userId") = #user.id /**I want to bind the userId form field */
#inputText(itemForm("title"))
#inputText(itemForm("description"))
#inputText(itemForm("price"))
<input type="submit" value="Create">
}
}
}`

In this case it would be better to pass it as action's argument (remember to modify routes declaration)
#form(routes.Application.newItem(user.id)){
....
you can also just use common html
<input type="hidden" name="userId" value="#user.id" />
edit:
Validation in action.Note: it doesn't make sense to display errors on the page next to hidden field, so you do not need placeholders for error messages. It's up to you to pass VALID value into the hidden field. Displaying validation errors to user who can not change the value of hidden field is bad conception.
public static Result newItem(){
Form<ItemModel> itemForm = form(ItemModel.class).bindFromRequest();
if (itemForm.hasErrors(){
return badRequest(newItemView.render(itemForm));
}
itemForm.get().save();
return ok("Your new item is saved...");
}

Related

Angular 2++ | NgForm: Form.Dirty is Always Dirty

Determine if NgForm Looks Exactly As It Did Before Any User-Input
It seems that form.dirty doesn't redact its value after it has been changed, and form.touched seems to always be false no matter what: dirty is touched, and touched is tetched.
template.html
<form #form="ngForm" (ngSubmit)="handleSubmission($event, {}, form)">
...
<input
#input
type="text"
[name]="item.title"
[(ngModel)]="item.estimate"
(ngModelChange)="handleEstimateChange(item, item.estimate, input, form)"
/>
...
</form>
component.ts
export class LeComponent {
#Input('data') public data: any;
public handleEstimateChange: Function;
constructor(private $: Sandbox) {
this.handleEstimateChange = $.debounce(this.handleEstimate.bind(this), (1000*0.2));
}
handleEstimate(item: any, estimate: number, input: HTMLInputElement, form: NgForm) {
if (!estimate) delete item.esitmate;
(this, item, estimate, input, form);
// Why does form.dirty never change back to pristine again???
}
}
In the TypeScript, I'm debouncing the ngModelChange handler to give Angular a chance to change the form.dirty value before I check it. This is because ngModelChange gets triggered before the NgForm object has been modified.
If !estimate, because estimate === "", then set it back to its original value of undefined. In this case, the form should look exactly like it did before any user-input had occurred.
However, when I put a breakpoint on the line right above the comment and I output form.dirty to the console, the NgForm never changes dirty back to false.
Is it possible to determine if the form looks exactly like it did before any user-input?
Obviously, I can write my own dirty logic, but wouldn't that mean that NgForm is kind of useless? There's got to be something I'm missing, right? How could dirty not mean dirty?
I've taken a look at some other SO questions -- the first one being similar but definitely not the question I am asking. They are asking if this is intentional -- I don't care; I'd like to know how to accomplish the goal above.
Close, but no cigar:
angular2 formcontrol stays dirty even if set to original value
Block routing if form is dirty [ Angular 2 ]
Angular 2 getting only the dirty values in a controlgroup
How do I programmatically set an Angular 2 form control to dirty?
Angular 2.x/4.x & bootstrap: patchValue does not alter dirty flag. Possible bug?
With template-driven forms and a very flat data model, I implemented it like this:
private currentProduct: IProduct;
private originalProduct: IProduct;
get isDirty(): boolean {
return JSON.stringify(this.originalProduct) !== JSON.stringify(this.currentProduct);
}
get product(): IProduct {
return this.currentProduct;
}
set product(value: IProduct) {
this.currentProduct = value;
// Clone the object to retain a copy
this.originalProduct = Object.assign({}, value);
}
But this only works for very simple cases.
As I mentioned in the comments, using reactive forms gives you more flexibility in managing your data model separate from your user entries.
What Was Most Useful
template.html
<form #form="ngForm" (ngSubmit)="handleSubmission($event, {}, form)">
...
<input
#input
type="text"
[name]="item.title"
[attr.name]="item.title"
[(ngModel)]="item.estimate"
(ngModelChange)="handleEstimateChange(item, item.estimate, input, form)"
/>
...
</form>
component.ts
export class LeComponent {
#Input('data') public section: any;
public handleEstimateChange: Function;
private resetFormControl = (input: HTMLInputElement, form: NgForm) => {
var name = input.name, control = form.controls[name];
control.reset();
// control.markAsPristine();
// control.setValue(undefined);
// control.updateValueAndValidity();
};
constructor(private $: Sandbox) {
this.handleEstimateChange = $.debounce(this.handleEstimate.bind(this), (1000*0.2));
}
handleEstimate(item: any, estimate: number, input: HTMLInputElement, form: NgForm) {
if (!estimate) this.resetFormControl(input, form);
(this, item, estimate, input, form);
// Why does form.dirty never change back to pristine again???
}
}
Note
[attr.name]="..." (template.html)
resetFormControl
Basically, simply deleteing the value was not enough because it was still present on the FormControl object (form.controls). To clear it properly, invoke control.reset() for the individual control -- this in-turn invokes .markAsPristine() which communicates to the parent NgForm. Also, input.name was empty as it was only represented by ng-reflect-name unless [attr.name] elucidated the same value -- [name] is really just there because its required by Angular.
Now, anytime an <input /> value changes -- and its falsey -- we reset the input ensuring that if all are falsey, Angular will automatically handle the NgForm's dirty-state correctly.

how to make mapping function work if the incoming request has less fields than expected

I am experimenting with play/scala. I have following two case classes and I want to map data from form into this model
case class User (
name:String,
age:Int,
female:Boolean,
address:Address
)
case class Address (
fullStreet:String,
county:String,
country:String
)
In controller class, I have following mapping function and action defined
val userForm = Form((mapping("name"->text,
"age"->number,
"female"->boolean,
"address"->mapping("fullStreet"->text,
"county"->text,
"country"->text)(Address.apply)(Address.unapply)
)(User.apply)(User.unapply)))
def post = Action { implicit request =>
val u:Form[User] = userForm.bindFromRequest
Ok(views.html.dataIndex(u))
}
I am facing the following issue: To make the complete code work, I have to create a form which contains all the fields required in mapping as follows:
<h1>Feed User Data</h1>
#helper.form(action=routes.Data.post){
#helper.inputText(userForm("name"))
#helper.inputText(userForm("age"))
#helper.checkbox(userForm("female"))
<fieldset>
#helper.inputText(userForm("address.fullStreet"),'_label -> "Full Street")
#helper.inputText(userForm("address.county"),'_label -> "County")
#helper.select(userForm("address.country"),Seq(""->"---",
"United Kingdom"->"UK",
"France"->"FR") )
</fieldset>
<input type="submit" name="send" value="submit"/>
}
If I create a form with say only input field for name, then bindFromRequest returns None instead of mapping only name field. Is there a way in which the form can contain less fields than required in mapping. I am not talking about fields in form with empty/optional values. I do not want to put the fields in the form at all.
I usually create a case class that represents the form data (probably not all the info from the domain class), and in the controller/service I create the domain entity using my own rules (for instance, a default value for a field not represented on the form)

Play Framework Form Error Handling

This is my view file containing the form that has to filled in by the user:
#helper.form(call) {
#helper.input(resumeForm("surname"), '_label -> "Surname") { (id, name, value, args) =>
<input name="#name" type="text" value="#value" placeholder="Enter your surname">
}
}
This is my custom field constructor:
#(elements: helper.FieldElements)
#if(!elements.args.isDefinedAt('showLabel) || elements.args('showLabel) == true) {
<div class="input-with-label text-left">
<span>#elements.label</span>
#elements.input
</div>
} else {
#elements.input
}
Now I have a dilemma. When the entered value doesn't clear validation, I need to add the class field-error to the input and I need to add data-toggle, data-placement and title. However, I don't know of any way to check if there are errors for the specific field. What is the best way to implement this? I already looked at using inputText or something but that is basically the same as the base input thus also does not have access to any errors. I'm also unable to alter the HTML of the elements.input inside the field constructor.
Have a look at play documentation: Writing your own field constructor.
You can check on errors with #if(elements.hasErrors) within the template of your custom field constructor.
<div class="input-with-label text-left #if(elements.hasErrors){field-error}">
...
Edit:
You can pass the error state of your field via the args parameter to your input. From the play docs:
Note: All extra parameters will be added to the generated HTML, except for ones whose name starts with the _ character. Arguments starting with an underscore are reserved for field constructor argument (which we will see later).
You need to cast to the matching type though.
#input(resumeForm("surname"), '_label -> "Surname", 'hasErrors -> resumeForm("surname").hasErrors) { (id, name, value, args) =>
<input name="#name" type="text" value="#value" placeholder="Enter your surname"
class="#if(args.get('hasErrors).map(_ match { case x:Boolean => x}).get){field-error}">
}

grails: custom validation of just one field/property

I have a "Thing" domain class, where each Thing has an record number (which is not the automatically generated id), that the user will use to access a Thing:
class Thing {
...
String recordNumber
...
}
There is a form to look for a Thing, knowing its recordNumber:
<g:form action="search">
<input name="recordNumber">
<g:submitButton name="btn" value="go to this Thing"/>
</g:form>
I would like to use a validation process in this form: if the recordNumber is not found (Thing.findByRecordNumber(recordNumber) == null), then the input field must turn in red, and a tooltip must show the error message "record number not found".
As far as I know/read (I'm a grails rookie), this has to be written as a constraint in the Thing class:
static constraints = {
recordNumber validator: { n -> Thing.findByRecordNumber(recordNumber) }
}
The problem is: I do not have in this form all the "Thing" properties to populate, just the recordNumber one, so I just can't call
new Thing(params).validate()
How to call validation on just one field, not on the whole object ?
If this is your main question, although I see others there:
"How to call validation on just one field, not on the whole object ?"
You can pass a list of values to validate and it will only validate those properties
new Thing(params).validate(["recordNumber"])
http://grails.org/doc/latest/ref/Domain%20Classes/validate.html
Validation is for constraints for domain class properties. You need an action in your controller:
def search = {
if(params.recordNumber && Thing.findByRecordNumber(params.recordNumber)){
redirect(action: "show", params:[id:Thing.findByRecordNumber(params.recordNumber).id])
}else{
flush.message = "No record found"
render(view:'VIEW_WITH_SEARCH_FORM')
}
}
If you want to validate without refreshing page, write a javascript code.

Zend Form MutliCheckbox Validate Number of Checked Items

I have a Zend Form with a MutliCheckbox element.
I would like to validate the number of checked items, i.e. verify that exactly 3 items are checked.
Can I do it with any current validates or do I have to write my own?
Thanks.
You will have to write your own, but that's quite simple. There is a second optional argument on the isValid() method that gives you access to all the form values, and enables this way to validate against multiple inputs.
class MyValidator extends Zend_Validate_Abstract {
public function isValid($value, $formData = null){
//you can access to all the form values in the $formData, and check/count
//the values of your multicheckbox
//this is the super-quick way, but you could also add error messages
return $isValid;
}
}
and then add it to your element
$myElement->addValidator( new MyValidator());