2016-05-18 14 views
5

Nella funzione dattiloscritto di seguito, 'this' non risolve l'istanza di EmailValidator. Come posso correggere questa funzione in modo che risolva l'istanza corretta di EmailVaildator ea sua volta, in modo che possa accedere a _registerServices?Accesso 'this' Inside Promise

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. Sembra che la freccia grassa dovrebbe già farlo. E guardando il Javascript generato, sembra alias 'questo' correttamente. Sei sicuro che questo sia il problema che stai vedendo? – Thilo

+0

@Thilo Da allora ho scoperto che il problema è un po 'nascosto e che il problema era altrove. Ho scoperto come correggere il mio problema, ma ci sono dettagli su "perché" si è verificato il problema che apprezzerei davvero alcune indicazioni su. Pubblicherò la mia soluzione. –

risposta

7

Stai perdendo this, perché si sta passando intorno al isAvailableEmail in funzione "raw" qui:

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

È possibile risolvere questo legandosi al this (usando la freccia grasso):

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

Grazie Thilo. Mi piace la tua soluzione - è il più piccolo cambiamento - ma rimarrà al mio, perché è coerente con il modo in cui il team Angular sembra aver implementato i suoi validatori. Farò la tua risposta come accettata perché risponde al meglio alla domanda originale. –

+0

Si noti che hanno funzioni "statiche" come "Validators.required" che non devono essere configurate e fabbriche di validatori che generano una funzione di validatore che acquisisce tutta la loro configurazione, come "Validators.minLength (8)".Si potrebbe fare qualcosa come 'EmailValidator (registerServices)' per produrre una funzione che cattura 'registerServices' e fa quello che è il tuo 'isAvailableEmail'. – Thilo

+0

Quindi, un validatore non dovrebbe essere una classe tanto quanto una funzione che crea un'altra funzione (come la tua 'isAvailableEmail'). E quella funzione generata è autonoma. – Thilo

1

si è scoperto che il 'questo' riferimento è stato indefinito, anche se è stato utilizzato come segue:

class EmailValidator { 

    constructor(private _registerServices: RegisterServices) { } 

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

ho raccogliere questo ha qualcosa a che fare con il modo in cui il metodo è stato chiamato, forse passando un metodo non statico, dove era previsto un metodo statico:

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

Se qualcuno potrebbe offrire alcune indicazioni su ciò che sta accadendo qui, sarebbe fantastico.

mia soluzione

ho riordinato il mio codice e prodotto il seguente:

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; 
    } 
} 

e modificato il suo utilizzo:

... 
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] 
    }); 
... 

che funziona correttamente.

1

Si ha il problema perché si sta passando il valore di isAvailable che è una funzione. Non lo stai eseguendo, stai solo passando il riferimento alla funzione.

Un modo per risolvere è come in @Thilo's answer

Un altro modo è quello di assegnare isAvailable a un'espressione lambda invece di una funzione. in questo modo:

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

vorrei offrire a scrivere un po 'diverso

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 })) 

     }); 

    } 
}