2016-05-18 16 views
5

In der folgenden Typoskript-Funktion wird 'this' nicht in die Instanz von EmailValidator aufgelöst. Wie kann ich diese Funktion korrigieren, so dass sie in die richtige Instanz von EmailVaildator aufgelöst wird und umgekehrt, damit ich auf _registerServices zugreifen kann?Zugriff auf "dieses" Inside-Versprechen

class EmailValidator { 

    constructor(private _registerServices: RegisterServices) { } 

    isAvailable(c: AbstractControl): Promise<ValidationResult> { 
     let q = new Promise((resolve, reject) => { 
      this._registerServices.emailIsAvailable(antiForgeryToken(), c.value) 
       .then(result => { 
        // Need to actually check the result. 
        resolve({ "emailtaken": true }) 
       }, 
       error => { 
        // Need to communicate the server error? Probably not. 
        resolve({ "servererror": true }) 
       }); 
     }); 

     return q; 
    } 
} 
+1

Hmm zu schreiben. Es sieht so aus, als würde der dicke Pfeil das schon tun. Und wenn man sich das generierte Javascript anschaut, scheint es das "richtig" zu sein. Sind Sie sicher, dass Sie das Problem sehen? – Thilo

+0

@Thilo Ich habe seit dem entdeckt, das Problem ist ein bisschen versteckt und das Problem war woanders. Ich habe herausgefunden, wie ich mein Problem beheben kann, aber es gibt Details darüber, "warum" das Problem aufgetreten ist, dass ich eine Anleitung sehr schätzen würde. Ich werde meine Lösung posten. –

Antwort

7

Sie verlieren this, weil Sie rund um die isAvailableEmail als „raw“ Funktion sind vorbei hier:

email: ['', Validators.required, this._emailValidator.isAvailableEmail] 

Sie können dieses Problem beheben, indem es this (mit dem Fett Pfeil) Bindung:

email: ['', Validators.required, 
    (control) => { this._emailValidator.isAvailableEmail(control) } 
] 
+0

Danke Thilo. Ich mag Ihre Lösung - es ist die kleinste Änderung - aber wird bei meiner bleiben, weil es im Einklang damit steht, wie das Angular-Team seine Validatoren implementiert zu haben scheint. Ich werde Ihre Antwort als die akzeptierte geben, weil sie die ursprüngliche Frage am besten beantwortet. –

+0

Beachten Sie, dass sie "statische" Funktionen wie "Validators.required" haben, die nicht konfiguriert werden müssen, und Validatorfactorys, die Validatorfunktionen generieren, die ihre gesamte Konfiguration erfassen, wie "Validators.minLength (8)".Sie könnten etwas wie 'EmailValidator (registerServices)' machen, um eine Funktion zu erzeugen, die die 'registerServices' abfängt und tut, was Ihre' isAvailableEmail' tut. – Thilo

+0

Also sollte ein Validator keine Klasse sein, sondern eine Funktion, die eine andere Funktion erzeugt (wie Ihre 'isAvailableEmail'). Und diese generierte Funktion ist in sich geschlossen. – Thilo

1

Es stellte sich heraus, dass die ‚diese‘ Referenz auch nicht definiert wurde, wenn es verwendet wurde, wie folgt:

class EmailValidator { 

    constructor(private _registerServices: RegisterServices) { } 

    isAvailable(c: AbstractControl): EmailValidator { 
     return this; // 'This' is undefined! 
    } 
} 

entnehme ich, das etwas mit dem zu tun hat, wie die Methode aufgerufen wurde, vielleicht ein vorübergehendes nicht-statische Methode, wo eine statische Methode erwartet wurde:

... 
this.registerForm = fb.group({ 
    email: ['', Validators.required, this._emailValidator.isAvailableEmail], 
    password: ['', Validators.compose([Validators.required, Validators.minLength(8)])], 
    phoneNumber: ['', Validators.required], 
    country: ['', Validators.required] 
    }); 
... 

Wenn jemand auf einige Hinweise bieten könnte, was hier vorkommen, dass fantastisch sein würde.

Meine Lösung

ich meinen Code neu geordnet und produzierte die folgenden:

class EmailValidator { 

    static isAvailableEmail(services: RegisterServices): (AbstractControl) => Promise<ValidationResult> { 
     let g = (c: AbstractControl) => { 
      return new Promise((resolve, reject) => { 
       services.emailIsAvailable(antiForgeryToken(), c.value) 
        .then(result => { 
         // Need to actually check the result. 
         resolve({ "emailtaken": true }) 
        }, 
        error => { 
         // Need to communicate the server error? Probably not. 
         resolve({ "servererror": true }) 
        }); 
      }); 
     }; 

     return g; 
    } 
} 

und änderte seine Nutzung:

... 
this.registerForm = fb.group({ 
    email: ['', Validators.required, 
     EmailValidator.isAvailableEmail(this._registerService)], 
    password: ['', Validators.compose([Validators.required, Validators.minLength(8)])], 
    phoneNumber: ['', Validators.required], 
    country: ['', Validators.required] 
    }); 
... 

Welche richtig funktioniert.

1

Sie haben das Problem, weil Sie den Wert isAvailable übergeben, die eine Funktion ist. Sie führen es nicht aus, Sie übergeben nur den Verweis auf die Funktion.

Ein Weg, um es zu lösen ist, wie in @Thilo's answer

Ein anderer Weg isAvailable zu einem Lambda-Ausdruck anstelle einer Funktion zuweisen ist. wie folgt aus:

class EmailValidator { 

    constructor(private _registerServices: RegisterServices) { } 

    isAvailable = (c: AbstractControl): Promise<ValidationResult> => { 
     let q = new Promise((resolve, reject) => { 
      this._registerServices.emailIsAvailable(antiForgeryToken(), c.value) 
       .then(result => { 
        // Need to actually check the result. 
        resolve({ "emailtaken": true }) 
       }, 
       error => { 
        // Need to communicate the server error? Probably not. 
        resolve({ "servererror": true }) 
       }); 
     }); 

     return q; 
    } 
} 
0

ich böte es ein bisschen anders

class EmailValidator { 

    constructor(private _registerServices: RegisterServices) { } 

    isAvailable(c: AbstractControl): Promise<ValidationResult> { 
     return this._registerServices.emailIsAvailable(antiForgeryToken(), c.value) 
      .then(result => { 
       // Need to actually check the result. 
       return { "emailtaken": true } 
      }) 
// shorter .then(result => ({ "emailtaken": true })) 
      .catch(error => { 
       // Need to communicate the server error? Probably not. 
       return { "servererror": true } 
      }); 
// shorter .catch(error => ({ "servererror": true })) 

     }); 

    } 
} 
Verwandte Themen