0

I'm working with a simple angular5 app in front end , using HTTPCLIENT , and spring-boot in back-end , i'm creating a simple component to add a new client,with field username .

i'm trying to use custum validator so i can check if the username is unique or already used , but i'm fascing many errors . This is Angular side

new-client.component.html

<div >
  <div class="col-sm-10">
    <div class="card">
      <div class="card-header">
        <strong>add a new client</strong>
      </div>

      <form [formGroup]="form" (ngSubmit)="SaveClient()">

      <div class="card-body">

        <div class="form-group">
          <label for="vat">Email </label>
          <input type="text" class="form-control" id="vat"   formControlName="username" />
          <div class="error" *ngIf="form.controls['username'].invalid && form.controls['username'].errors.required && (form.controls['username'].dirty || form.controls['username'].touched)">Please enter an email</div>
          <div class="error" *ngIf="form.controls['username'].invalid && form.controls['username'].errors.email && (form.controls['username'].dirty || form.controls['username'].touched)">Please enter a valid email</div>
          <div class="error" *ngIf="form.controls['username'].invalid && form.controls['username'].errors.emailTaken">This email has been taken, please use another one.</div>
        </div>
        <div formGroupName = "passwordG">

          <div class="form-group">
            <label for="vat">Password</label>
            <input type="password" class="form-control" id="vat"    formControlName="password" />
          </div>

          <div class="form-group">
            <label for="vat">Confirmation Password</label>
            <input type="password" class="form-control" id="vat" formControlName="Confirmationpassword" />
          </div>


          <div *ngIf="(form.controls['passwordG'].invalid && form.controls['passwordG'].touched)" class="col-sm-3 text-danger">

            <ng-container *ngIf="form.controls['passwordG'].errors?.mismatch;
                then first else second"> </ng-container>

            <ng-template #first>
              Password do not match </ng-template>

            <ng-template #second>
              Password needs to be more than 8 characters
            </ng-template>
          </div>

        </div>
      </div>

      <div class="card-footer">
        <button type="submit" class="btn btn-sm btn-primary" ><i class="fa fa-dot-circle-o"></i>Enregistrer</button>
      </div>
      </form>
    </div>
  </div><!--/.col-->
</div>

new-client.component.ts

function passwordMatch(control: AbstractControl):{[key: string]: boolean}{

  const password = control.get('password');
  const Confirmationpassword = control.get('Confirmationpassword');

  if( !password || !Confirmationpassword) {
    return null; }

  if(password.value === Confirmationpassword.value){
    return null;
  }

  return {
    mismatch:true
  }

}


@Component({
  selector: 'app-new-clients',
  templateUrl: './new-clients.component.html',
  styleUrls: ['./new-clients.component.scss']
})
export class NewClientsComponent implements OnInit {

  client:Clients = new Clients();
  form: FormGroup;

  constructor(private clientService:ClientService,
              private formBuilder: FormBuilder,
              public router:Router,
              public activatedRoute:ActivatedRoute) { }

  ngOnInit() {

    this.form = this.formBuilder.group({

      username: ['', Validators.required , Validators.email  , this.validateEmailNotTaken.bind(this)],
      passwordG: this.formBuilder.group({
        password: ['',[Validators.required,Validators.minLength(9)]],
        Confirmationpassword : ['',[Validators.required,Validators.minLength(9)]]

      }, {validator: passwordMatch})

    });
  }

  SaveClient(){

    this.client.setUsername(this.form.value.username);
    this.client.setPassword(this.form.value.passwordG.password);

    this.clientService.saveClient(this.client)
      .subscribe((data:Clients)=>{
        swal("operation réussi !", "great !", "success");
        this.router.navigate([ '../list' ], { relativeTo: this.activatedRoute });
      },err=>{
        console.log(err);
      })

  }

  validateEmailNotTaken(control: AbstractControl) {
    return this.clientService.checkEmailNotTaken(control.value).map(res => {
      return res ? null : { emailTaken: true };
    }); //somthing is wrong HERE ! 
  }


}

client.service.ts

@Injectable()
export class ClientService {
checkEmailNotTaken(email:string){
    if(this.authService.getToken()==null) {
      this.authService.loadToken();
    }
    return this.http.post(this.host+
      "/checkEmailUnique/",{email},{headers:new HttpHeaders({'Authorization':this.authService.getToken()})});
  }


}

In spring-boot :

 @RequestMapping(value="/checkEmailUnique",method=RequestMethod.POST)
    public EmailStatusCheckJson checkEmailUnique(@RequestBody final AppUser appUser){

        final EmailStatusCheckJson returnValue = new EmailStatusCheckJson();

              System.out.println("username **"+appUser.getUsername());
         AppUser app = userRepo.findByUsername(appUser.getUsername());


         if(app!=null){
             System.out.println("exists");
             returnValue.setEmailIsAvailable(false);
         }
         else{
             System.out.println("doesnt exist ");
             returnValue.setEmailIsAvailable(true);

         }

         return returnValue;
    }

This is the error i'm getting

ERROR Error: Expected validator to return Promise or Observable.
    at toObservable (forms.js:749)
    at Array.map (<anonymous>)
    at FormControl.eval [as asyncValidator] (forms.js:729)
    at FormControl.AbstractControl._runAsyncValidator (forms.js:3447)
    at FormControl.AbstractControl.updateValueAndValidity (forms.js:3390)
    at FormControl.setValue (forms.js:3973)

Any idea ? I'm new to angular .

2
  • Its either Angular or Spring. Both are separate applications. Sio you ask for validator on backend or frontend? Commented Jun 21, 2018 at 20:06
  • I'm asking for validator in front end in angular side , i just added all the code so it seems clear . Commented Jun 21, 2018 at 20:18

2 Answers 2

1

What is expacted for a control is

  • the value of the control, then
  • a validator or an array of validators, then
  • an async validator or an array of async validators

So it should be

['', [Validators.required, Validators.email], this.validateEmailNotTaken.bind(this)]

since the validateEmailNotTaken is an async validator.

Sign up to request clarification or add additional context in comments.

12 Comments

I dont get any error now , the Validators.required, Validators.email are working , but this.validateEmailNotTaken.bind(this) seems not to work as it doesnt tell me that username is already in use . i've already tested the rest controller with ARC client and it works well .
That's because your validator is incorrect: it returns null if you get a non-null body as a response from your post request. And your server controller always returns a non-null body.
Ah i see , how can i then test and return true or false then?
You're not supposed to return true or false. You're supposed to return null if there is no error, or { emailTaken: true } if there is one. The server returns { emailIsAvailable: false } when the email is taken, and { emailIsAvailable: true } when it's not taken. This shouldn't be too hard to figure out.
Thank you so much for being this much helpful , i could understand how this was working and fixed the problem , i appreaciate your help againe :)
|
1

You are missing bracket here

username: ['', Validators.required , Validators.email  , this.validateEmailNotTaken.bind(this)]

should be

username: ['', [Validators.required , Validators.email  , this.validateEmailNotTaken.bind(this)]]

1 Comment

I dont get any error now , the Validators.required, Validators.email are working, but this.validateEmailNotTaken.bind(this) seems not to work as it doesnt tell me that username is already in use . i've already tested the rest controller with ARC client and it works well .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.