6
votes

I have an Angular2 form field. I want to require that the entered value doesn't already exist. My component receives the array of existing values via an @Input parameter. I have a custom validator function in my component, codeUnique(), but when it's executed it has no access to instance members. "this" returns either FormControl or undefined. My validator function has been sucked into outer space, stripped of it's context and instance variables. How can I get my list of existing values into my validator? Could I put them in a global scope, horror?

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { NG_VALIDATORS, FormControl, FormBuilder, FormGroup, Validators, AbstractControl } from '@angular/forms';

import { ReferringAppModel } from './referringapp.model';
//import { CodeValidator } from './code-validator';

@Component({
    selector: 'add-client-form',
    templateUrl: 'src/home/add-client-form.component.html'
})
export class AddClientFormComponent {
    myForm: FormGroup;
    code: AbstractControl;
    name: AbstractControl;

    constructor(fb: FormBuilder) {
        this.myForm = fb.group({
            'code': ['', this.codeUnique],
            'name': ['', Validators.required]
        });
        this.code = this.myForm.controls['code'];
        this.name = this.myForm.controls['name'];
    }
    @Input() referringApps: ReferringAppModel[];

    ngOnInit() {
    }
    onSubmit(form: any): void {
        console.log("submitted")
    };

    codeUnique(c: FormControl) {
        try {
            // Blows up. 
            return !this.referringApps.find(appInApps => appInApps.Code == c.value) ? null : {
                //return false ? null : { // WORKS
                validateEmail: {
                    valid: false
                }
            };
        } catch (ex) {
            console.log(ex);
        }
    }
}


TypeError: Cannot read property 'referringApps' of undefined
    at AddClientFormComponent.codeUnique (http://localhost/HubHacienda/dist/bundle.js:50071:26)
    at http://localhost/HubHacienda/dist/bundle.js:43538:54
    at Array.map (native)
    at _executeValidators (http://localhost/HubHacienda/dist/bundle.js:43538:28)
    at FormControl.Validators.compose [as validator] (http://localhost/HubHacienda/dist/bundle.js:43518:38)
    at FormControl.AbstractControl._runValidator (http://localhost/HubHacienda/dist/bundle.js:45083:54)
    at FormControl.AbstractControl.updateValueAndValidity (http://localhost/HubHacienda/dist/bundle.js:45061:38)
    at FormControl.setValue (http://localhost/HubHacienda/dist/bundle.js:45327:19)
    at DefaultValueAccessor.onChange (http://localhost/HubHacienda/dist/bundle.js:44287:22)
    at DebugAppView._View_AddClientFormComponent0._handle_input_12_0 (AddClientFormComponent.ngfactory.js:493:47)
    at DebugAppView.eventHandler (http://localhost/HubHacienda/dist/bundle.js:35576:29)
    at COMPONENT_REGEX (http://localhost/HubHacienda/dist/bundle.js:38521:41)
    at http://localhost/HubHacienda/dist/bundle.js:38634:116
    at ZoneDelegate.invoke (http://localhost/HubHacienda/dist/bundle.js:6875:29)
    at Object.onInvoke (http://localhost/HubHacienda/dist/bundle.js:32132:42)
    at ZoneDelegate.invoke (http://localhost/HubHacienda/dist/bundle.js:6874:35)
    at Zone.runGuarded (http://localhost/HubHacienda/dist/bundle.js:6782:48)
    at NgZoneImpl.runInnerGuarded (http://localhost/HubHacienda/dist/bundle.js:32161:83)
    at NgZone.runGuarded (http://localhost/HubHacienda/dist/bundle.js:32393:78)
    at HTMLInputElement.outsideHandler (http://localhost/HubHacienda/dist/bundle.js:38634:84)
    at ZoneDelegate.invokeTask (http://localhost/HubHacienda/dist/bundle.js:6908:38)
    at Zone.runTask (http://localhost/HubHacienda/dist/bundle.js:6808:48)
    at HTMLInputElement.ZoneTask.ZoneTask.cancelFn.invoke (http://localhost/HubHacienda/dist/bundle.js:6976:34)
2

2 Answers

8
votes

simple: when assigning the validator you bind the this argument of your class to it, like so: 'code : ['', this.codeUnique.bind(this)]

0
votes
codeUnique = (c: FormControl) => {
    // Your validation will go here
 }