Angular Custom Validator Doesn't Reflect Changes in View - javascript

I have custom validator like this:
export class PasswordValidator {
static MatchPassword(AC: AbstractControl) {
const formGroup = AC.parent;
if(formGroup) {
let password = formGroup.value.password // to get value in input tag
let confirmPassword = formGroup.value.confirmPassword; // to get value in input tag
if(password != confirmPassword) {
formGroup.get('confirmPassword').setErrors({ matchPassword: true });
} else {
formGroup.get('confirmPassword').setErrors(null);
}
console.log(formGroup.get('confirmPassword').errors);
} else {
return null
}
}
}
And i have added to the form:
this.registerationForm.addControl("confirmPassword", new FormControl('', Validators.compose([Validators.required, PasswordValidator.MatchPassword])));
And in View:
<ion-item class="error-message" *ngIf="registerationForm.controls.confirmPassword.hasError('matchPassword')
&& registerationForm.controls.confirmPassword.touched">
<p>Some message*</p>
</ion-item>
But the problem is i can see the console window but i don't see it reflects in view. The ngIf condition isn't showing the error message

Use detectChanges() when you've updated the model after angular has run it's change detection, or if the update hasn't been in angular world at all.
Use markForCheck() if you're using OnPush and you're bypassing the ChangeDetectionStrategy by mutating some data or you've updated the model inside a setTimeout;
export class PasswordValidator {
static MatchPassword(AC: AbstractControl) {
const formGroup = AC.parent;
if(formGroup) {
let password = formGroup.value.password // to get value in input tag
let confirmPassword = formGroup.value.confirmPassword; // to get value in input tag
if(password != confirmPassword) {
formGroup.get('confirmPassword').setErrors({ matchPassword: true });
} else {
formGroup.get('confirmPassword').setErrors(null);
}
console.log(formGroup.get('confirmPassword').errors);
this.ref.markForCheck();
} else {
return null
}
}
}
add this.ref.markForCheck(); after you update the form.

Related

Apply ngIf validity on submit

I validate a few fields in a form in my Angular 10 project like this:
<div class="question">
<div class="row">
<h5>1. Requestors Name (Your name or JHED ID)</h5><p class="required">*</p>
</div>
<input type="text" class="form-control" id="requestorName" name="requestorName" required minlength="2"
[(ngModel)]="model.requestorName" #requestorName="ngModel"/>
<div *ngIf="requestorName.invalid && (requestorName.dirty || requestorName.touched)"
class="alert">
<div *ngIf="requestorName.errors?.required">
<p class="required">Requester name is required.</p>
</div>
<div *ngIf="requestorName.errors?.minlength">
<p class="required">Requester name must be at least 2 characters long.</p>
</div>
</div>
</div>
Which works fine. However, if the user never touches the fields that have validation like this but fill out the rest of the form then click Submit it will still be acceptable.
I also have written my own validation check on submit like this:
<div class="question">
<button class="submit col-md-2" (click)="onSubmit()">Submit</button>
</div>
validateModel(accessRequest: AccessRequestModel) {
const validityCheck = {
isValid: true,
reason: null
};
validityCheck.isValid = true;
console.log(accessRequest);
if (accessRequest) {
if (!accessRequest.requestorName) {
validityCheck.isValid = false;
validityCheck.reason = 'Requester name is required.';
return validityCheck;
} else if (!accessRequest.lname) {
validityCheck.isValid = false;
validityCheck.reason = 'Last name is required.';
return validityCheck;
}
else if (!accessRequest.fname) {
validityCheck.isValid = false;
validityCheck.reason = 'First name is required.';
return validityCheck;
}
else if (!accessRequest.department) {
validityCheck.isValid = false;
validityCheck.reason = 'Department is required.';
return validityCheck;
}
else if (!accessRequest.title) {
validityCheck.isValid = false;
validityCheck.reason = 'Job title is required.';
return validityCheck;
}
else if (!accessRequest.managerName) {
validityCheck.isValid = false;
validityCheck.reason = 'Manager name is required.';
return validityCheck;
}
else if (!accessRequest.startDate) {
validityCheck.isValid = false;
validityCheck.reason = 'Start date is required.';
return validityCheck;
}
else if (!accessRequest.accessType) {
validityCheck.isValid = false;
validityCheck.reason = 'Access type is required.';
return validityCheck;
}
}
return validityCheck;
}
Which also works.
But what I want is for the same error messages that apply if you do click on the boxes to apply if the validity check function returns false. How could I do that?
If the question wasn't clear or you need additional information please let me know.
Seems like you are trying to recreate form validation. Look into reactive forms module in angular and do the following:
Import ReactiveFormsModule into the module where your component is defined
Dependency Inject it to your component's constructor like so:
constructor(private formBuilder: FormBuilder) {}
Define the form creation logic in your OnInit method:
ngOnInit() {
this.myForm = this.formBuilder.group({
option1: ['', Validators.Required],
...
})
}
Update your HTML to leverage this new form based on the documentation that angular provides. Thus your submit button can define a [disabled] attribute that sets a button as disabled if the form is not valid. The syntax in the form group of: [{initialValue}, {validator | array of validators}] is what controls the validity of the input.
Conversely, you can also iterate over each control in the form and manually set the error state for it by calling the setError method on the FormControl object if you still want to enable a user to click submit even on an invalid form input.

Filtring cards in React using checkbox onChange

this is my first project using React.js, I want to filter the restaurants cards using checkbox when it it check it show only the restaurants cards with these filters or types true such as the music and WIFI. The problems are it show the default cards perfectly but after I checked the checkbox it's change the all type or filters values into false such as Music and WIFI instead of create or map only the cards that false. In addition, it will not create the default cards after double check, can you please help me
The code:
import React, { Component } from 'react';
import axios from 'axios';
import App from "../App";
import Cards from "../Card";
function CreateCards(resturants) {
//Handel the Music, Wifi, Partition (to transfer it from bolean form into string)
if (resturants.Music == true){
resturants.Music = "Music";
}else{
resturants.Music = "No Music";
}
if (resturants.Wifi == true){
resturants.Wifi = "Wifi";
}else{
resturants.Wifi = "No Wifi";
}
if (resturants.Partition == true){
resturants.Partition = "Partition";
}else{
resturants.Partition = "No Partition";
}
return(
<Cards
key={resturants._id} // done
theCardId={resturants._id} // done
placeName={resturants.Name} // done
stars={resturants.Rating} // done
PRating={resturants.PRating} //until filters
music= {resturants.Music} // done
img={resturants.icon} // need uploads file
status={Status(resturants.OpenTime, resturants.CloseTime)} // done
descreption={resturants.Description} // done
wifi={resturants.Wifi} // done
partition={resturants.Partition} // done
/>
);
}
// Check if the place is open or closed depending on the work hours
function Status (Open, Close){
const date = new Date();
var hours = date.getHours();
const red = 'red';
const green = 'green';
if ((Open <= hours) && (hours < Close)){
// console.log("Open");
return "Open";
}else{
// console.log("Close");
return "Close";
}
}
export default class Resturants extends Component {
//constructor elemnts in login
constructor(props){
super(props);
//intialy no data enterd
this.state = {
resturants: [],
filter: ""
}
this.Filtering = this.Filtering.bind(this);
}
componentDidMount(){
//Get Resturants data
axios.get('http://localhost:3000/places')
.then(resp => {
console.log(resp)
this.setState({
resturants: resp.data
})
})
}
Filtering(e){
// this.setState({filter:e.target.value});
e.preventDefault();
this.state.resturants.filter(Type => {
// console.log(Type.Music === true);
})
}
render(){
return(
<div className="flexthem">
<div className="Filters">
<h4>Filters</h4>
<input className="Checkbox" type="checkbox" id="Type1" value="" onClick={this.Filtering}></input>
</div>
<div className="general-card">
{this.state.resturants.map(CreateCards)}
</div>
</div>
);
}
}
a bit of advice.
use "==="
use function componented.
the hook "useState" is a lot simpler than class component state.
restraunt.music = "music"
is a string.
and
restaurant.music = true
is a boolean.
if you set a variable as a string and try to check if it is false or true after. It will return undefined. If it is an empty string, it will return false.
if (resturants.Music == true){
resturants.Music = "Music";
}else{
resturants.Music = "No Music";
}
in react when you set or change the state, then it refreshes. If you are changing the state with this, you are going to put it through he if statement again. It will return undefined and then not change the checkboxes from their default value.

Tried to get data from a form and append it to a global array, but for some reason the data isn't being added

I am trying to get data from a form and append it to a global array but for some reason, the data isn't being added to the array. The code should basically accept the input from the form and store it into the global array. I updated the HTML so you can see the entire syntax. The value should basically be taken from the form and placed into the global array using the "addnew" function.
function addnew()
{
//calculateAge();
//Accept values entered in form
const fname = document.getElementById('fname').value;
const mname = document.getElementById('mname').value;
const lname= document.getElementById('lname').value;
const dob= document.getElementById('dob').value;
const genderM = document.getElementsByName('male').checked;
const genderF = document.getElementsByName('female').checked;
const age = calculateAge.bYear;
const bodyType = document.getElementById('Body Type').value;
const occu= document.getElementById('occu').value;
const height= document.getElementById('height').value;
if (fname==null || fname=="")
{
alert();
}
if(mname==null || mname=="")
{
alert();
}
if (lname==null || lname=="")
{
alert();
}
if(dob==null || dob=="")
{
alert();
}
if (genderM.checked == false || genderF.checked == false){
alert();
}
if (age <=18 || age >=75)
{
alert();
}
if(height>=170 || height<=200)
{
alert();
}
if(bodyType==null || bodyType==""){
alert();
}
if(oocu==null || oocu=="")
{
alert();
}
//Append To array
records.push(fname);
records.push(mname);
records.push(lname);
records.push(dob);
records.push(genderM);
records.push(genderF);
records.push(age);
records.push(bodyType);
records.push(occu);
records.push(height);
for(i=0;i<records.length;i++)
{
console.log(records[i]);
}
//showAll();
//<h1 class="logo"><img src="New folder/logo.jpg" /></h1>
Information.addEventListener('submit', addnew);
}
</script>
```
first of all. name attribute has nothing to do with form element.
second. Information.addEventListener('submit', addnew); has no meaning because Information is not defined.
and to the core. when submiing a form, the page refreshes defaultly, so the addNew function is aborted like all the other variables. in order to prevent it you have to do as follows.
on submit button ad an id attribute:
<button id="submit" type="submit"> Submit </button>
then on top of your JS, get the button element and add an event listener to it:
let submit = document.getElementById('submit');
submit.addEventListener('click', addnew );
and here is the final step. on the addNew function, add an event argument. and on the begining of the function's code, fire the preventDefault method:
function addnew(event) {
event.preventDefault();
// the rest of the code here
}
by the way. you have a typo here. it should be occu.
if (oocu == null || oocu == "") {
alert();
}
good luck!

vue js checkbox state not updated

Hey iam writing piece of code in vue.js. I have problem with checkboxes. I have two of them and they are connected with my backend. They look like this:
<b-form-checkbox
v-model="selectedUser.institutionPersonRelations[0].communicationBlocked" #change="editBlockOfCommunication({institutionId:selectedUser.institutionPersonRelations[0].id, profileId:selectedUser.id})">
</b-form-checkbox>
<b-form-checkbox v-model="selectedUser.institutionPersonRelations[0].uploadBlocked" #change="editUploadBlock({institutionId:selectedUser.institutionPersonRelations[0].id, profileId:selectedUser.id})" :disabled="selectedUser.institutionPersonRelations[0].communicationBlocked == true">
</b-form-checkbox>
Everything working correctly until i check second checkbox and then check first checkbox and then uncheck first checkbox. First changing value X and Y in database. Second changing value Y in database. In this case database in updated correctly but second checkbox even if is set to false is still checked, and i need to reload the page to update it.
My backend in php is hit on change event on checkbox looks like that
public function editBlockOfCommunicationForProfile(int $institutionPersonId, int $profileId): void
{
$entityManager = $this->ormGateway->getEntityManager();
$profile = $entityManager->find(ProfileDto::class, $profileId);
if ($profile !== null) {
$institutionProfile = $profile->getInstitutionPersonRelationWithGivenId($institutionPersonId);
if ($institutionProfile !== null) {
if (!$institutionProfile->getDeactivated()) {
if ($institutionProfile->getCommunicationBlocked() === false) {
$institutionProfile->setCommunicationBlocked(true);
$institutionProfile->setUploadBlocked(true);
}
else {
$institutionProfile->setCommunicationBlocked(false);
$institutionProfile->setUploadBlocked(false);
}
}
}
}
$entityManager->flush();
}
/**
* #param int $institutionPersonId
* #param int $profileId
*/
public function editUploadBlockForProfile(int $institutionPersonId, int $profileId): void
{
$entityManager = $this->ormGateway->getEntityManager();
$profile = $entityManager->find(ProfileDto::class, $profileId);
if ($profile !== null) {
$institutionProfile = $profile->getInstitutionPersonRelationWithGivenId($institutionPersonId);
if ($institutionProfile !== null) {
if (!$institutionProfile->getDeactivated()) {
if($institutionProfile->getCommunicationBlocked() === false) {
if ($institutionProfile->getUploadBlocked() === false) {
$institutionProfile->setUploadBlocked(true);
} else {
$institutionProfile->setUploadBlocked(false);
}
}
}
}
}
$entityManager->flush();
}

How to require a field with a value of "yes" using javascript?

I need to be able to require certain fields if someone selects a value of "Yes" from a dropdown. I've used the following code but it doesn't seem to work.
$(function () {
$('#anyAdditionalInc').keyup(function () {
if ($(this).val() == "No") {
$('#additionalIncomeSource').removeAttr('required');
$('#additionalIncomeAmt').removeAttr('required');
} else {
$('#additionalIncomeSource').attr('required', 'required');
$('#additionalIncomeAmt').attr('required', 'required');
}
});
});
My dropdown looks like this
<div class="form-group">#Html.LabelFor(m => m.anyAdditionalInc, new { #class = "col-sm-2 control-label" })
<div class="col-sm-10">
<div class="col-sm-4">#Html.DropDownListFor(m => m.anyAdditionalInc, new SelectList(new List
<Object>{ new { value = "", text = "----"}, new { value = "Yes", text = "Yes"}, new { value = "No", text = "No"}, }, "value", "text"), new { #class = "form-control", id = "anyAdditionalInc" }) #Html.ValidationMessageFor(m => m.anyAdditionalInc)</div>
</div>
</div>
Any help is appreciated. It doesnt seem to want to require the validation on the source and amt fields when selecting yes.
A dropdown (I guess you mean a <select> element by that) doesn't have much keyup events. Try change instead:
$(function () {
$('#anyAdditionalInc').change(function () {
var active = $(this).val() != "No"),
fields = $('#additionalIncomeSource, #additionalIncomeAmt');
fields.prop('required', active);
if (!active) fields.val("");
});
});
Even though #Bergi answered the question from a client-side perspective, since you tagged the question asp.net-mvc-4 I presume you may wish to know how it's done on the server side (where it really matters!):
You can simply check it in your controller:
public ActionResult Foo(SomeModel someModel) {
if (someModel.anyAdditionalInc != "Yes") {
ModelState.AddModelError("", "You must select yes");
}
}
Or if you want to push the logic into your model itself:
public class SomeModel: IValidatableObject {
public string anyAdditionalInc {get; set;}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
if (this.anyAdditionalInc != "Yes") {
yield return new ValidationResult("You must select yes");
}
}
}
Notice how the model:
Implements IValidateableObject
Has a method named Validate which returns the type IEnumerable<ValidationResult>
During the model binding process this method will automatically be called and if a validation result is returned your ModelState will no longer be valid. So using this familiar code in your controller will make sure you don't take any action unless your custom conditions check out:
public class SomeController {
public ActionResult SomeAction() {
if (ModelState.IsValid) {
//Do your stuff!
}
}
}

Categories