Estoy escribiendo un formulario en Angular 2 donde el usuario envía el formulario, se valida y si hay algún error con las entradas, quiero desplazar el navegador del usuario al primer elemento con la clase "error".
El problema es que todos mis errores usan *ngIf así:
<input type="text" [(ngModel)]="model.first_name"> <div class="error" *ngIf="errors.first_name"> {{errors.first_name}} </div>En mi función de envío
submit(){ this.errors = this.validate(); if(this.errors.any()){ var errorDivs = document.getElementsByClassName("error"); if(errorDivs.length > 0){ errorDivs[0].scrollIntoView(); } } }Me doy cuenta de que esto se debe a que * ngIf elimina completamente el div del DOM y aún no se ha dado la oportunidad de ejecutar la verificación angular de cambios. ¿Hay una forma inteligente y limpia de hacer esto?
No estoy seguro de entender completamente tu pregunta.
El uso de una directiva como la siguiente haría que el elemento se desplazara a la vista cuando errors.first_name se vuelva verdadero:
<div class="error" *ngIf="errors.first_name" scrollTo> {{errors.first_name}} </div> @Directive({ selector: '[scrollTo]'}) class ScrollToDirective implements AfterViewInit { constructor(private elRef:ElementRef) {} ngAfterViewInit() { this.elRef.nativeElement.scrollIntoView(); } }Aquí hay una manera que descubrí:
Crear una clase auxiliar
export class ScrollHelper { private classToScrollTo: string = null; scrollToFirst(className: string) { this.classToScrollTo = className; } doScroll() { if (!this.classToScrollTo) { return; } try { var elements = document.getElementsByClassName(this.classToScrollTo); if (elements.length == 0) { return; } elements[0].scrollIntoView(); } finally{ this.classToScrollTo = null; } } }Luego cree uno en el componente en el que desea usarlo
private scrollHelper : ScrollHelper = new ScrollHelper();luego cuando descubres que tienes errores
submit(){ this.errors = this.validate(); if(this.errors.any()){ this.scrollHelper.scrollToFirst("error"); } } luego posponga el desplazamiento real hasta ngAfterViewChecked después de que se haya evaluado *ngIf
ngAfterViewChecked(){ this.scrollHelper.doScroll(); }Puede que esta no sea la solución más elegante, pero puede intentar envolver su código de enfoque de error en un setTimeout
submit(){ this.erroors = this.validate(); setTimeout(() => { if(this.errors.any()){ var errorDivs = document.getElementsByClassName("error"); if(errorDivs.length > 0){ errorDivs[0].scrollIntoView(); } } }, 50); }La clave no es tanto retrasar el código de enfoque como asegurarse de que el código se ejecute después de un tic del bucle de eventos. Eso le dará tiempo a la detección de cambios para que se ejecute, asegurando así que sus divisiones de error tengan tiempo para que Angular las vuelva a agregar al DOM.