Search code examples
formsangularionic2formbuilder

How to access this in formbuilder validator callback


I build a form using form builder:

public searchMapForm = this.formBuilder.group({
    country: ["DE"],
    postcode: ["13347", this.searchCont],
    this: [this]
});

The custom validator for the postcode looks like:

private searchCont( c ) {

    if( !c || !c.value || c.value.length < 4 ) return { toShort: { valid: false } };

    var __this = c._parent && c._parent.controls.this.value; // this look too complicated

    if( __this && __this.http ) {
        __this.http.get('http://nominatim.openstreetmap.org/search?format=json&addressdetails=1&limit=5&postalcode=' + c.value + '&countrycodes=' + c._parent.controls.country.value ).subscribe(res => {
            let l = res.json()[0];

            if( l ) {
                __this.map.setView( [l.lat, l.lon], 13, { animate: true } )
                __this.markers.map( m => { m.remove(); } )
                __this.markers = [];
                __this.markers.push( L.marker( [l.lat, l.lon] ).addTo( __this.map ) );
            }
        });
    }

    return null;
}

After each change the callback is called, but this is undefined. So I had to find a way to access this. Everything works fine, but doesn't look fine. What would be best pratice in this case?


Solution

  • I would put the http request call in form valueChanges event instead.

    searchMapForm.valueChanges.subscribe(e=>{
    if(this.searchMapForm.controls['postcode'].valid && !this.searchMapForm.controls['postcode'].pristine){
    this.http.get('http://nominatim.openstreetmap.org/search?format=json&addressdetails=1&limit=5&postalcode=' + e.postcode + '&countrycodes=' + e.country ).subscribe(res => {
                let l = res.json()[0];
    
                if( l ) {
                    this.map.setView( [l.lat, l.lon], 13, { animate: true } )
                    this.markers.map( m => { m.remove(); } )
                    this.markers = [];
                    this.markers.push( L.marker( [l.lat, l.lon] ).addTo( this.map ) );
                }
            });
    }
    });
    

    OR you could think of creating a separate directive like the tutorial here