I'm quite new to play and scala. I'm working on form and validations. But I couldn't figure out to get all errors from multiple verification on form.
My form tuple looks like;
val companyMapping = Forms.tuple(
"name" -> nonEmptyText,
"email" -> email,
"password" -> nonEmptyText(8),
"re-password" ->nonEmptyText(8)).verifying(
// Add an additional constraint: both passwords must match
"Passwords don't match", data => {
data._3 == data._4 }
).verifying(
// Second constraint
"Test error", data => {
false }
)
In the view I print global errors and errors, it looks like;
#println(companyForm.globalError)
#println(companyForm.errors)
and output;
Some(FormError(,Passwords don't match,WrappedArray()))
List(FormError(,Passwords don't match,WrappedArray()), FormError(,Test error,WrappedArray()))
At this stage I have absolutely no idea about how to print both of the errors. I'm showing errors separately for the each input and show global errors at the end.
But if passwords match I can see test constraint in the global errors. Other than it only shows password match constraint.
Here is the view part;
#helper.form(action = routes.Login.register) {
<div class="row">
<span class="label">Name</span>
<input type="text" name="name" placeholder="Company Name" value="#companyForm("name").value" >
#if(!companyForm.errors("name").isEmpty){
<span class="error">#Messages(companyForm.errors("name")(0).message,"Company name")</span>
}
</div>
<div class="row">
<span class="label">Email</span>
<input type="text" name="email" placeholder="Email" value="#companyForm("email").value" >
#if(!companyForm.errors("email").isEmpty){
<span class="error">#Messages(companyForm.errors("email")(0).message,companyForm.errors("email")(0).key)</span>
}
</div>
<div class="row">
<span class="label">Password</span>
<input type="password" name="password" placeholder="Password" value="#companyForm("password").value" >
#if(!companyForm.errors("password").isEmpty){
<span class="error">#Messages(companyForm.errors("password")(0).message,8)</span>
}
</div>
<div class="row">
<span class="label">Re-type Password</span>
<input type="password" name="re-password" placeholder="Re-type your password" value="#companyForm("re-password").value" >
#if(!companyForm.errors("re-password").isEmpty){
<span class="error">#Messages(companyForm.errors("re-password")(0).message,8)</span>
}
</div>
#println(companyForm.globalError)
#println(companyForm.errors)
<div class="row">
<span class="label"><button type="submit">Save</button></span>
#companyForm.globalError.map { error =>
<span class="error">#error.message</span>
}
</div>
}
Maybe I'm just confused about those error types. So please can you explain it detailed.
In the re-password section of your template, you currently test if !companyForm.errors("re-password").isEmpty but then only show the message for companyForm.errors("re-password")(0), i.e. the first error only. Even if you have multiple errors.
You have to iterate over companyForm.errors("re-password") to print something for each error.
You can for example output a <span class="error">... for each error, using a for comprehension:
<div class="row">
<span class="label">Re-type Password</span>
<input type="password" name="re-password" placeholder="Re-type your password" value="#companyForm("re-password").value" >
#for (error <- companyForm.errors("re-password")) {
<span class="error">#Messages(error.message,8)</span>
}
</div>
See the play doc for Scala templates for other useful syntax to use in templates.
Related
I have created step in each tabs which represent the steps in the form. I have used v-if condition to check which step should be displayed. As of now the steps work perfectly fine when i click the next button. Even if the inputs are empty I am able to go to the next step. I want some validation on each step that will check if the input is empty and add a class to that input say "error-class". How do I do that in vuejs?
This is my form in .vue file.
<form id="product_form" enctype="multipart/form-data">
<!-- One "tab" for each step in the form: -->
<button type="button" v-if="step === 2 || step === 3 || step === 4" id="prevBtn1" #click.prevent="prev()"></button>
<div v-if="step === 1" class="tab">
<h3>Post a product</h3>
<div class="preview" id="preview">
</div>
<div class="single-holder">
<input type="text" name="pname" id="pname" placeholder="Title*" required="true" ref="pname">
</div>
</div>
<div v-if="step === 2" class="tab">
<h3>Describe your Product</h3>
<div class="descrip">
<textarea name="description" id="description" placeholder="Description" required="true"></textarea>
</div>
</div>
<div v-if="step === 3" class="tab">
<h3>Set Inventory</h3>
<div class="fixed-width">
<div class="single-holder">
<label>Quantity</label>
<input type="number" name="quantity" id="quantity" required="true">
</div>
</div>
</div>
<div v-if="step === 4" class="tab">
<h3>Share On</h3>
<div class="address-details-holder clearfix">
<div class="single-holder">
<input placeholder="_ _ _ _" id="zipcode" name="zipcode" maxlength="4" type="text" #keypress="onlyNumber">
</div>
</div>
</div>
</form>
This is my method in Vuejs
methods:{
onlyNumber ($event) {
let keyCode = ($event.keyCode ? $event.keyCode : $event.which);
if ((keyCode < 48 || keyCode > 57) && keyCode !== 46) { // 46 is dot
$event.preventDefault();
}
},
prev() {
this.step--;
},
next() {
this.step++;
//if(this.step===1){
// console.log(this.$refs.name.value);
//if(this.$refs.pname.value !== null){
// this.step++;
//}
//}
}
As of now the steps work fine if i remove the if condition in the function next() in methods. But I need input validations on each step so the user has to fill out the missing data in all the form fields.
I think you can use Vee Validate . It will help you check required in each input
<input v-validate="'required'" data-vv-as="field" name="required_field" type="text">
And return error message for that input if it false
<span>{{ errors.first('email') }}</span>
I have a working b3 play framework form with file upload. The only issue is I cannot see anywhere in the documentation to remove an already uploaded file. Ideally there would just be a "remove" type button by the file upload that could remove the already uploaded file before form submission.
My current form is below. Any help or suggestions on solving this are more than welcome.
Thank you
#b3.form(routes.SettingsController.submitEditProfile, 'enctype -> "multipart/form-data") {
#CSRF.formField
#b3.text(userForm("displayName"), '_label -> "Display name")
<div class="form-group">
<label class="control-label col-md-2" for="settingsImage">Settings Image</label>
<div class="col-md-6">
#user.settingsImage.fold {
<p>#Messages("has.no.image")</p>
}{ c =>
<p>#Messages("has.image")</p>
#c.artifacts.find(a => a.label == "small" && a.url.nonEmpty).map{ ca =>
<img src="#ca.url" #includes.artifactDimensions(ca) /></a>
}
}
<input type="file" name="settingsImage" />
</div>
</div>
#b3.free('_id -> "idFormGroup") {
<button type="submit" class="btn btn-secondary">#Messages("update")</button>
<a class="btn btn-default" href="#routes.SettingsController.settings()">#Messages("cancel")</a>
}
corporate.html
<form #f="ngForm" name="corporateProfileForm" ng-submit="corporateFrmSave(objDS, objDSCurrency)" novalidate="">
<div class="row form-group">
<div class="col-md-12" >
<input type="text" *ngIf="formData" [(ngModel)]="formData.Corporate_Id" id="corpid" title="Corporate ID" tab-index="1" name="corpid" maxlength="20" #corpid="ngModel" required/>
<label for="corp"><b>Corporate ID</b></label>
<div *ngIf="corpid.invalid && (corpid.dirty || corpid.touched)" class="alert alert-danger">
<div *ngIf="corpid.errors.required">
Name is required.
</div>
<div *ngIf="ncorpidame.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="corpid.errors.forbiddenName">
Name cannot be Bob.
</div>
</div>
</div>
</div>
</form>
Iam getting error message as
ERROR TypeError: Cannot read property 'invalid' of undefined
Make sure you define your variable with this structure:
TS file
export class ContactComponent implements OnInit {
myform: any;
corpid: FormControl;
constructor() {
}
ngOnInit() {
this.createFormControls();
this.createForm();
}
createFormControls() {
this.corpid= new FormControl('', Validators.required);
}
createForm() {
this.myform = new FormGroup({
corpid: this.corpid,
});
}
HTML file
<div class="md-form form-sm form-group"
[ngClass]="{
'invalid': corpid.invalid && (corpid.dirty || corpid.touched),
'valid': corpid.valid && (corpid.dirty || corpid.touched)
}">
<i class="fa fa-user prefix"></i>
<input
type="text" id="corpid" class="form-control"
required
[formControlName]="'corpid'">
<label for="corpid" class="">Your corpid</label>
</div>
<div class="form-control-feedback"
*ngIf="corpid.errors && (corpid.dirty || corpid.touched)">
<p *ngIf="corpid.errors.required">corpid is required</p>
</div>
It's hard to tell because issue is not in your HTML snipped but in .ts file.
I hope my Code will be helpfull
The issue is with the *ngIf, so when that condition is checked, Angular renders the rest of the template, and while the small fraction of time while *ngIf is being evaluated, your template reference variable corpid does not exist, so it will throw an error when trying to check the validation intially.
Wrap the input field with the validation div's inside the *ngIf instead of applying it only on the input field.
<div class="row form-group" *ngIf="formData">
<input [(ngModel)]="formData.Corporate_Id" id="corpid" ... >
<!-- more code here... -->
</div>
DEMO
I have two forms into a template, how can I identify every html form in order
to process it into my handler?
Is possible get the form name in the post handler code?
I'm using nosurf, therefore I must generate and check the
token in the same request, maybe I'm doing wrong..
<form action="/form" method="post" name="form1">
<label class="control-label">Set A</label>
<div class="controls">
<input type="text" id="my" name="my">
</div>
<div style="display:none;">
<input name="_formkey" type="hidden" value="{{.token}}">
</div>
</form>
<form action="/form" method="post" name="form2">
<label class="control-label">Set thing</label>
<div class="controls">
<input type="text" id="thing" name="thing">
</div>
<div style="display:none;">
<input name="_formkey" type="hidden" value="{{.token}}">
</div>
</form>
My Handler
func myHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method{
case "GET":
data:=map[string]interface{}{
"key":nosurf.Token(req),
}
if err := renderTemplate(w, "base", data); err != nil {
log.Error(err)
}
case "POST":
// how?
if r.FormValue("my"){}
...
if r.FormValue("thing"){}
...
}
}
Thanks
Is possible get the form name in the post handler code?
I don't think that's possible, but you can send the form name in another hidden input field.
I've added this to my Boot.scala
LiftRules.viewDispatch.append({
case List("admin", "categories") => Right(Admin)
})
Here is my Admin.scala in (admin/view package)
object Admin extends LiftView{
def dispatch = {
case "add" => editCategory
}
def editCategory(): NodeSeq = {
<lift:embed what="/admin/add_category"></lift:embed>
}
}
Here is my add_category template -
<lift:surround with="admin" at="content">
<div class="container-fluid" id="main_container">
<lift:Admin:addCategory form="POST" class="form-horizontal">
<fieldset>
<legend>Add Category</legend>
<div class="control-group">
<label class="control-label" for="cat_name">Name</label>
<div class="controls">
<cat:name></cat:name>
</div>
</div>
<div class="control-group">
<label class="control-label" for="cat_desc">Description</label>
<div class="controls">
<cat:desc></cat:desc>
<cat:submit></cat:submit>
</div>
</div>
</fieldset>
</lift:Admin:addCategory>
</div>
</lift:surround>
I'm trying to bind this with a snippet -Admin.scala in (admin/snippet package) with addCategory method.
object name extends RequestVar("")
object desc extends RequestVar("")
def addCategory(in: NodeSeq): NodeSeq = {
def doAdd() {
//todo: Save Category
}
bind("cat", in,
"name" -> SHtml.text(name.is, (n: String) => name(n), ("id", "cat_name"), ("class", "input-large")),
"desc" -> SHtml.textarea(desc.is, (d: String) => desc(d), ("id", "cat_desc"), ("class", "input-large")),
"submit" -> SHtml.submit("Save", doAdd, ("class", "btn btn-info"))
)
}
I'm getting this error -
Error processing snippet: admin:addcategory
Reason: Method Not Found
XML causing this error:
<lift:admin:addcategory class="form-horizontal" form="POST">
<fieldset>
<legend>Add Category</legend>
<div class="control-group">
<label for="cat_name" class="control-label">Name</label>
<div class="controls">
<cat:name></cat:name>
</div>
</div>
<div class="control-group">
<label for="cat_desc" class="control-label">Description</label>
<div class="controls">
<cat:desc></cat:desc>
<cat:submit></cat:submit>
</div>
</div>
</fieldset>
</lift:admin:addcategory>
And in the logs -
[net.liftweb.http.LiftRules] - Snippet Failure: SnippetFailure(/admin/categories/add -> ParsePath(List(admin, categories, add),,true,false),Full(admin:addcategory),Method Not Found)
Need help with this. I'm unable to figure out why lift is not able to find the method.
Have you added your admin package into LiftRules? Something like this should allow Lift to search admin.snippets for resolution:
LiftRules.addToPackages("admin")
Also, I believe you need to be calling the snippet as Admin.addCategory instead of with a :.
Edit:
I believe that the Lift HTML5 parser was case sensitive and had trouble with camel case method names. You may want to try renaming your method to all lowercase, or try calling your snippet as (instead of with the <lift: style):
<div class="lift:admin.addCategory"> ... </div>
or
<div data-lift="admin.addCategory"> ... </div>