Ember.js 2.7 - How to check validation on an input field? - javascript

I'm pretty new to Ember.js and I'm having trouble how to do a validation on a certain input field.
Here is the code for my template index.hbs:
<div class="jumbotron text-center">
<h1>Coming Soon</h1>
<br/><br/>
<p>Don't miss our launch date, request an invitation now.</p>
<div class="form-horizontal form-group form-group-lg row">
<div class="col-xs-10 col-xs-offset-1 col-sm-6 col-sm-offset-1 col-md-5 col-md-offset-2">
{{input type="email" value=model.email class="form-control" placeholder="Please type your e-mail address." autofocus="autofocus"}}
</div>
<div class="col-xs-10 col-xs-offset-1 col-sm-offset-0 col-sm-4 col-md-3">
<button disabled={{isDisabled}} {{action 'saveInvitation' model}} class="btn btn-primary btn-lg btn-block">Request invitation</button>
</div>
</div>
{{#if responseMessage}}
<div class="alert alert-success">{{responseMessage}}</div>
{{/if}}
<br/><br/>
</div>
and here is the code from my controller index.js:
import Ember from 'ember';
export default Ember.Controller.extend({
headerMessage: 'Coming soon',
responseMessage: '',
email: '',
isValid: Ember.computed.match('email', /^.+#.+\..+$/),
isDisabled: Ember.computed.not('isValid'),
});
The input field that I want to get validation for is the email one. I know how to go about the validation by replacing the value="" field to just value="email", but I want to know how I can do it using the value=model.email
This seems like an easy problem, but I can't find anything on the docs about this particular issue.

As you are using input helper this will update model.email property when you type in text field.
1.You dont need to declare email property in controller.
2.isValid computed property dependent key should be model.email
import Ember from 'ember';
export default Ember.Controller.extend({
headerMessage: 'Coming soon',
responseMessage: '',
isValid: Ember.computed.match('model.email', /^.+#.+\..+$/),
isDisabled: Ember.computed.not('isValid'),
});

You can check the validity of email inside saveInvitation action.

Related

How can I get a input required with vuejs

I have my chat and I dont want people to send empty message so I would like that my input become required. Thanks for your help.
I tried to put "required='required'" in the input line, I also tried veeValidate but it broke my chat when I use it, I also tried to put "Required = true" in Props and data but without a good result
This is ChatForm.vue
<template>
<div class="input-group" >
<input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Ecrire..." v-model="newMessage" #keyup.enter="sendMessage">
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendMessage">
&#10003
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user'],
data() {
return {
newMessage: '',
}
},
methods: {
sendMessage() {
this.$emit('messagesent', {
user: this.user,
message: this.newMessage
});
setTimeout(function() {
const messages = document.getElementById('mess_cont');
messages.scrollTop = messages.scrollHeight;
}, 200);
this.newMessage = '';
}
}
}
</script>
And this is my form in the app.blade.php
<div id="app" class="container-chat">
<div class="row">
<div class="col-md-12 col-md-offset-2">
<div class="col-md-12 col-md-offset-2">
<div class="panel-body panel-content" id="mess_cont">
<chat-messages id="mess" :messages="messages" :currentuserid="{{Auth::user()->id}}"></chat-messages>
</div>
<div class="panel-footer">
<chat-form
v-on:messagesent="addMessage"
:user="{{ Auth::user() }}"
></chat-form>
</div>
</div>
</div>
</div>
</div>
Try to change your ChatForm.vue like this:
<template>
<form #submit.prevent="sendMessage">
<div class="input-group" >
<input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Ecrire..." v-model="newMessage" required>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" type="submit" id="btn-chat">
&#10003
</button>
</span>
</div>
</template>
You are not treating the input in the correct way, the input which is required needs to be inside a form and the required keyword will prevent the form submission if the input field is empty.
There are a few things I would do differently.
1/ Wrap your chat form in a tag, and execute the sendMessage() method on submit. This will give your users a nicer experience, as they can just to submit the message.
2/ Convert the button into a submit button so it triggers the form.submit event.
3/ You can easily disable the button by checking whether newMessage has contents. I don't think you need vee validate or anything else to achieve this; for something as simple as a chat form, your user doesn't need much more feedback than seeing a disabled button to realise (s)he needs to write something first.
4/ in the addMessage method you can just check the contents of newMessage and not do anything when it's empty. This is perfectly fine because you already hinted the user by disabling the button too.
I think this is a subtle way where you guide your user, but don't overdo it.
Please add name attributes to all of your form elements. Some of the element in my form had name attribute and some didn't. Element which had name attributes worked correctly but the one's which didn't had name failed.

Angular 5 reactive forms validators error

I have been stuck at this silly angular 5 reactive forms error which i am not able to get rid of. While adding the validation message block in html, I am getting the error
"Cannot read property 'invalid' of undefined"
which is weird as there is a form control element with the same name and I am able to access the value of that feild. Below is the code
HTML file
<form [formGroup]='signUpForm'>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" formControlName='password'>
<div *ngIf="password.invalid && (password.dirty || password.touched)"
class="alert alert-danger">
<div *ngIf="password.errors.required">
Name is required.
</div>
</div>
</div>
</div>
</div>
</form>
ts code
signUpForm: FormGroup;
this.signUpForm = new FormGroup({
username:new FormControl('',Validators.required),
email:new FormControl('',[Validators.required]),
password:new FormControl('',Validators.required),
})
Please help. Thanks in advance
Try This Code.
<div *ngIf="signUpForm.controls['password'].invalid && (signUpForm.controls['password'].dirty || signUpForm.controls['password'].touched)"
class="alert alert-danger">
<div *ngIf="signUpForm.get('password').hasError('required')">
Name is required.
</div>
</div>
Where do you initialize the form?? If you do it in ngOnInit(), you should not be facing that problem.
If you are initializing the form under any other custom method of yours then you can use something like:
Use the safe navigation operator ?. This checks whether the first operator results to true or not. When the view is rendered it might be possible that the control is not initialized yet. So suppose if the component variable password is not defined when your view is rendered and you try to access a property invalid of password(which is undefined), you will get the error you get now..
for example:
<div *ngIf="password?.invalid && (password?.dirty || password?.touched)" class="alert alert-danger">
So your actual view could be like:
<form [formGroup]='signUpForm'>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" formControlName='password'>
<div *ngIf="password?.invalid && (password?.dirty || password?.touched)" class="alert alert-danger">
<div *ngIf="password?.errors?.required">
Name is required.
</div>
</div>
</div>
</div>
</div>

Angular 5 two-way binding to update another field

I have two fields in the exported class. The template has a drop-down with its ngModel bound to the first field (selectedInterval) with two-way binding. When the dropdown option changes, the calculateReviewDate() event takes place and successfully updates the 2nd field (nextReviewDate), but the dropdown stays blank until I select the same option twice. In addition, the spinner never appears during the calculation. Does anyone know why?
<form #FormVar="ngForm" novalidate>
<div class="form-group">
<div class="row">
<div class="col col-md-2 col-sm-3">
<input type="text" [ngModel]="nextReviewDate | date:shortDate" name="nextReviewDate" id="nextReviewDate1" class="form-control" disabled/>
</div>
<div class="col col-md-1 com-sm-3" *ngIf="showSpinner">
<fa [name]="'spinner'" [size]=1 [spin]=true></fa>
</div>
<div class="col col-md-2 col-sm-3">
<select class="form-control" name="nextReviewDate" id="nextReviewDate2" [(ngModel)]="selectedInterval" (change)="calculateReviewDate()">
<option *ngFor="let r of reviewIntervals" [value]="r.interval">{{r.intervalDescription}}</option>
</select>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!FormVar.valid" (click)="save(FormVar)">Review Note</button>
</form>
calculateReviewDate(): void {
this.showSpinner = true;
let calculator: calculateDate = new calculateDate();
let today: Date = new Date();
this.nextReviewDate = calculator.addMonth(today, this.selectedInterval);
this.showSpinner = this.nextReviewDate === undefined;
}
How you get reviewIntervals? And for the spinner, my thought it's because too fast, try to add a delay before this.showSpinner = this.nextReviewDate === undefined;like set time out.
Not sure about your issue with the select, but I know what is going on with your spinner. You have no asychronous code in your calculateReviewDate method so the spinner won't be shown. JS runs on a single thread and unless you break the synchronous code up into parts that allow the control to be given back to the browser to paint, your spinner will not be shown.
I think you have two issues here:
1. onChange, the selected value is not shown the first time.
2. Spinner is not shown on Select value change.
Why the Spinner is not shown?
On Change since the calculateReviewDate() method is being called directly (Synchronous behavior), and in this method the spinner is set to true in the starting and then state gets set to either true/false based on nextReviewDate variable, I guess nextReviewDate variable would never become undefined,so nextReviewDate always holds some valid value, so it sets to false again, so in the background the spinner will become rendered and immediately gets removed as you have used a structural directive and all logic in the method happens synchronous manner and will be in a very short span, so visually we are not able to see the rendered spinner getting on and off.
Why the Select controls selected value is not shown?
I have shared a modified example of your version in which things are fine,
Template:
<div>
<form #FormVar="ngForm" novalidate>
<div class="form-group">
<div class="row">
<div class="col col-md-2 col-sm-3">
<div class="form-group">
<input type="text" [ngModel]="nextReviewDate" name="nextReviewDate" id="nextReviewDate1" class="form-control" disabled/>
</div>
</div>
<div class="col col-md-1 com-sm-3" *ngIf="showSpinner">
<p>Spinner</p>
</div>
<div class="col col-md-2 col-sm-3">
<select class="form-control" name="nextReviewDate" id="nextReviewDate2" [(ngModel)]="selectedInterval" (change)="calculateReviewDate()">
<option *ngFor="let r of reviewIntervals" [value]="r">{{r}}</option>
</select>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" >Review Note</button>
</form>
</div>
TS:
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
reviewIntervals = [1,2,3,4,5];
selectedInterval = 5;
showSpinner = false;
nextReviewDate;
calculateReviewDate(value): void {
this.nextReviewDate = this.selectedI`enter code here`nterval;
}
}

Unable to assign form control to template variable in Reactive Forms - angular?

I am new to angular let say, i have reactive form like follow
ngOnInit() {
this.registerFormGroup = this.formBuilder.group({
email: [ '', Validators.compose([Validators.required, Validators.email])],
password: this.formBuilder.group({
first: [ '', Validators.required ],
second: [ '', Validators.required, ]
})
});
}
and my angular template looks like follow
<div class="container">
<form [formGroup]="registerFormGroup"
(ngFormSubmit)="registerUser(registerFormGroup.value)" novalidate>
<div class="form-group" >
<label for="email">Email</label>
<input type="email" formControlName="email" placeholder="Enter Email"
class="form-control">
</div>
<div *ngIf="!registerFormGroup.get('password').get('first').valid"
class="alert alert-danger">
</div>
<div class="form-group text-center">
<button type="submit" class="btn btn-success btn-lg"
[disabled]="!registerFormGroup.valid">Submit</button>
</div>
For example, email field has two validations such as required and email type validate so depends upon the error I have to display error message so in my template am using like
<div *ngIf="!registerFormGroup.get('email').valid && (registerFormGroup.get('email').touched)"
class="alert alert-danger">
</div>
Instead of adding same registerFormGroup.get('email') again and again i trying to create template expression like #emailForm="registerFormGroup.get('email')" in
<input type="email" formControlName="email" placeholder="Enter Email" class="form-control" #emailForm="registerFormGroup.get('email')">
so that i can use use like
<div *ngIf="!emailForm.valid" class="alert alert-danger">
</div>
but i am getting error like
compiler.es5.js:1690 Uncaught Error: Template parse errors:
There is no directive with "exportAs" set to "registerFormGroup.get('email')" ("l>
]#emailForm="registerFormGroup.get('email')">
what mistake i made??
You can create common function to access form like below:
validateFormControl(controName: string) {
let control = registerFormGroup.get(controName);
return control.invalid && control.touched;
}
In Templete use this call wherever you need, you just need to pass your control name in function, you can modify this function as per your need as well and you do not need to use form.get all the time. This makes your template more cleaner and performance efficient.
<div *ngIf="validateFormControl('email')"
class="alert alert-danger">
error message
</div>
<div *ngIf="validateFormControl('password')"
class="alert alert-danger">
error message
</div>
Create a method on the component that returns if the form is valid or not and return it in the component
checkError(){ // either you can pass the form from the template or use the component for decleration
return registerFormGroup.get('email').valid;
}
In the template call
<div *ngIf="checkError()" class="alert alert-danger">
// Always make sure not to use controls in the template it will result in AOT compilation error
</div>
try this :
component.html
<div class="container">
<form [formGroup]="registerFormGroup"
(ngFormSubmit)="registerUser(registerFormGroup.value)" novalidate>
<div class="form-group" [ngClass]="{'has-error':!registerFormGroup.controls['email'].valid}">
<label for="email">Email</label>
<input type="email" formControlName="email" placeholder="Enter Email"
class="form-control">
<p class="alert alert-danger" *ngIf="registerFormGroup.controls['email'].dirty && !registerFormGroup.controls['email'].valid">Invalid email address</p>
</div>
<div class="form-group text-center">
<button type="submit" class="btn btn-primary" [disabled]="!registerFormGroup.valid">Submit</button>
</div>
</form>
</div>
component.ts
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
export class AppComponent implements OnInit {
registerFormGroup: any;
constructor(
private formBuilder: FormBuilder
) {}
ngOnInit() {
this.registerFormGroup = this.formBuilder.group({
email: [null , Validators.compose([Validators.required, Validators.email])]
});
}
}
Angular team strongly discourage from using functions outputs in templates due to change detection strategy. You might be interested in following solution, using ngForm directive:
<div class="container">
<form [formGroup]="registerFormGroup"
(ngFormSubmit)="registerUser(registerFormGroup.value)" novalidate>
<div class="form-group" >
<label for="email">Email</label>
<input type="email" formControlName="email" placeholder="Enter Email "
class="form-control" #email="ngForm">
</div>
<div *ngIf="email.invalid"
class="alert alert-danger">
</div>
It's still a hush to copy-paste it in template, but at least you might have direct reference to control via it's template variable. I personally go with controller getter function still, but I'm posting this answer for sake of answer completeness.
Although I agree with the accepted answer (you should have a dedicated method in your form component that will encapsulate the validation process)
sometimes you need a quick check in the template:
The trick is to expose the formGroup from your component and use it like so:
Template:
<input id="name" class="form-control"
formControlName="name" required
[class.is-invalid]="
f.name.invalid &&
(f.name.touched ||
f.name.touched.dirty)">
Component:
//easily access your form fields
get f() { return this.checkoutForm.controls; }
I was also looking for a more elegant solution than calling form.get multiple times. Here is what I come up with using ngif
<div class="col-sm-6" *ngIf="form.get('sponsor') as sponsor">
<input type="text" formControlName="sponsor" id="sponsor" class="form-control" name="sponsor"
[class.is-invalid]="sponsor.errors && sponsor.touched">
</div>
using the as feature on ngIf to create a template variable

How to implement Ember-Validations in Ember-App-Kit(EAK)

I have a ember-app-kit application. For the form I am using ember default views. But for form validations I have came across with this lib which everyone highly recommends. Ember Validations By Docyard . But I am not sure how to implement the same with my eak set-up.
Questions that I have:
1. Where should I add validations ?
2. What to declare when defining validations?
3. Errors how to show them on focus out or even on submit button ?
Say for example I have a sign up form and I want to validate firstname lastname, email, password, gender(select options) . How should I go about it ?
If possible please clarify the queries with a JSbin.
Validations should go to controller, unless your working with dyanmic formsets, which can be duplicated. Also u have to wrap ControllerObject into this
var AddController = Ember.ArrayController.extend(Ember.Validations.Mixin, {}
To start validation u have to make new Object named validations
You have to add input value to be validated
validations: {
newFirstname:{
format: { with: /^[A-Za-z-]{2,16}$/, allowBlank: true, message: 'Enter valid name.' }
},
newFamilyname: {
format: { with: /^[A-Za-z-]{3,16}$/ , message: 'Required field lastname.' }
}
},
Showing errors.
<div class="row">
<div class="col-md-6 col-xs-4">
<label>First name: </label>
{{input type="text" placeholder="First name" value=newFirstname class="form-control"}}
{{#if errors.newFirstname}}
<span class="error errorForValidation"><span class="glyphicon glyphicon-warning-sign"></span> {{errors.newFirstname}}</span>
{{/if}}
</div>
<div class="col-md-6 col-xs-4">
<label>*Last name: </label>
{{input type="text" placeholder="Family name" value=newFamilyname class="form-control"}}
{{#if errors.newFamilyname}}
<span class="error"><span class="glyphicon glyphicon-warning-sign"></span> {{errors.newFamilyname}}</span>
{{/if}}
</div>
</div><!--end row-->
Showing button when validation is flawless
<button type="submit" class="btn btn-primary" {{bind-attr disabled="isInvalid"}}{{action 'GetData'}}>Create</button>
JSBIN : http://emberjs.jsbin.com/iDeQABo/17/edit

Categories

Resources