Necesito agregar el resultado a la lista después del evento place_changed. Muestro la lista debajo de la entrada en la que encuentro ubicaciones. El evento funciona y el resultado se envía a los elementos de la matriz. Pero el problema es que el nuevo elemento agregado no se muestra de inmediato. Se mostró después de un tiempo o cuando hago clic en el formulario donde se muestra esta entrada.
.ts:
@ViewChild('locationInput', { static: true }) input: ElementRef; autocomplete; items = []; ngOnInit() { this.autocomplete = new google.maps.places.Autocomplete(this.input.nativeElement, this.localityOptions); this.autocomplete.addListener('place_changed', () => { this.addToListSelectedItem(); }); } public addToListSelectedItem() { if (this.input.nativeElement.value) { this.items.push(this.input.nativeElement.value); this.input.nativeElement.value = ''; } }.html:
<input #locationInput class="shadow-none form-control" formControlName="locality" placeholder="" [attr.disabled]="locationForm.controls['region'].dirty ? null : true" /> <div *ngFor="let item of items; let index = index"> <div class="listOfLocation"> <div class="itemList">{{ item }}</div> <img [src]="icons.cross" class="delete-button-img" alt="edit-icon" (click)="deleteTask(index)" /> </div> </div>¡Gracias por la ayuda!
Probablemente la estrategia de detección de cambios de su componente sea OnPush o Google Autocompletar se esté ejecutando fuera de zone.js:
changeDetection: ChangeDetectionStrategy.OnPushY dado que los elementos son una matriz y se almacenan en la memoria por referencia, debe ejecutar manualmente la detección de cambios:
constructor(private cdr: ChangeDetectorRef) public addToListSelectedItem() { ... this.input.nativeElement.value = ''; this.cdr.detectChanges();Aún mejor sería trabajar con un Sujeto RxJS, un Observable para elementos $ y usar la tubería asíncrona. ¡La tubería asíncrona funciona como magia en lo que respecta a actualizar la plantilla :-)!
@ViewChild('locationInput', { static: true }) input: ElementRef; autocomplete; itemsSubject$ = new Subject<any[]>(); items$ = this.itemsSubject$.asObservable(); // Use a separate array to hold the items locally: existing = []; ngOnInit() { this.autocomplete = new google.maps.places.Autocomplete(this.input.nativeElement, this.localityOptions); this.autocomplete.addListener('place_changed', () => { this.addToListSelectedItem(); }); } public addToListSelectedItem() { if (this.input.nativeElement.value) { // Use spread syntax to create a new array with the input value pushed at the end: this.existing = [...this.existing, this.input.nativeElement.value]; // Send the newly created array to the Subject (this will update the items$ Observable since it is derived from this Subject): this.itemsSubject$.next(this.existing); this.input.nativeElement.value = ''; } } // I added the deleteTask implementation to show you how this works with the subject: deleteTask(index: number) { // The Array "filter" function creates a new array; here it filters out the index that is equally to the given one: this.existing = this.existing.filter((x, i) => i !== index); this.itemsSubject$.next(this.existing); }Y en la plantilla:
<input #locationInput class="shadow-none form-control" formControlName="locality" placeholder="" [attr.disabled]="locationForm.controls['region'].dirty ? null : true" /> <!-- Only difference here is adding the async pipe and using the items$ Observable instead --> <div *ngFor="let item of items$ | async; let index = index"> <div class="listOfLocation"> <div class="itemList">{{ item }}</div> <img [src]="icons.cross" class="delete-button-img" alt="edit-icon" (click)="deleteTask(index)" /> </div> </div>Para ver un ejemplo práctico del sujeto RxJS en este concepto, consulte https://stackblitz.com/edit/angular-ivy-dxfsoq?file=src%2Fapp%2Fapp.component.ts .
Tal vez más allá de esta pregunta, pero dado que está utilizando un formulario reactivo, ¿por qué no usar this.locationForm.get('locality').setValue('...') para configurar la entrada en lugar de usar un ViewChild para trabajar con el ¿aporte? Más control de esta manera que usando ViewChild.