简体   繁体   中英

Angular Change Detection not triggering on Router.navigate()

I have a component in Angular called NewEventComponent that only contains a form to submit a new event. On it's submit method it has this code:

onSubmit() {
  this.isSendingRequest = true;

  this.geolocationService.geocodeAddress(this.location.value).subscribe(
    (results: google.maps.GeocoderResult[]) => {
      if (results && results.length) {
        const eventData: EventData = {
          name: this.name.value,
          location: [results[0].geometry.location.lat(), results[0].geometry.location.lng()],
          startDate: this.datetimeService.convertDateAndTimeToISOString(this.startDate.value, this.startTime.value),
          endingDate: this.datetimeService.convertDateAndTimeToISOString(this.endingDate.value, this.endingTime.value),
          description: this.description.value,
          sport: this.sport.value,
          intensity: this.intensity.value,
          fee: this.fee.value,
          maxPlayers: this.maxPlayers.value
        };

        this.eventService.createEvent(eventData).subscribe(
          (res: any) => {
            this.alertService.createAlert({ message: EVENT_CREATED_MESSAGE, type: AlertType.Success });
            this.router.navigate(['events', res.data.event.id]);
          }
        );
      } else {
        this.handleInvalidLocationError();
      }
    }
  );
}

It only sends the event to the server and redirects to the event page, which is the EventDetails component. This component only asks for the requested event to the server and passes it as an Input to a child component. This is the code:

TS:

@Component({
  selector: 'app-event-details',
  templateUrl: './event-details.component.html',
  styleUrls: ['./event-details.component.scss']
})
export class EventDetailsComponent implements OnInit {

  private event: EventResponse;

  constructor(
    private activatedRoute: ActivatedRoute,
    private eventService: EventService
  ) { }

  ngOnInit() {
    this.getEvent();
  }

  getEvent(): void {
    this.activatedRoute.params.subscribe(
      (params: Params) => {
        this.eventService.getEvent(params.id).subscribe(
          (res: any) => {
            this.event = res.data.event;
          }
        );
      }
    );
  }
}

HTML:

<div class="row">
  <div class="col">
    <div class="info-wrapper">
      <app-event-details-info [event]="event">
      </app-event-details-info>
    </div>
  </div>
</div>

And the child component EventDetailsInfo only receives the event as an Input like this @Input() event: EventResponse; and displays the information in the html like this: <h5>{{ event?.name }}</h5> .

The problem here is that when navigating from the NewEvent component to the EventDetails component, the change detection is not triggered, so until I click anywhere in the DOM for example, the changes are not showing. But when I navigate to the EventDetails component trough the url directly the page is rendering properly.

What am I missing on change detection? Any idea? Thanks!

PS: EventService only executes HTTP calls and return them as Observables, like:

createEvent(eventData: EventData): Observable<any> {
  return this.http.post(`${environment.apiUrl}/events/`, eventData);
}

getEvent(eventId: string): Observable<any> {
  return this.http.get(`${environment.apiUrl}/events/${eventId}`);
}

PS2: This is the GeolocationService method used in the ´onSubmit()´ method:

geocodeAddress(address: string): Observable<google.maps.GeocoderResult[]> {
  const response: Subject<google.maps.GeocoderResult[]>
    = new Subject<google.maps.GeocoderResult[]>();
  const request: google.maps.GeocoderRequest = { address };

  this.geocoder.geocode(request,
    (results: google.maps.GeocoderResult[]) => {
      response.next(results);
    }
  );

  return response;
}

Update

onSubmit() {
  this.isSendingRequest = true;

  this.geolocationService.geocodeAddress(this.location.value).subscribe(
    (results: google.maps.GeocoderResult[]) => {
      this.zone.run(() => π
        if (results && results.length) {
            const eventData: EventData = {
              name: this.name.value,
              location: [results[0].geometry.location.lat(), results[0].geometry.location.lng()],
              startDate: this.datetimeService.convertDateAndTimeToISOString(this.startDate.value, this.startTime.value),
              endingDate: this.datetimeService.convertDateAndTimeToISOString(this.endingDate.value, this.endingTime.value),
              description: this.description.value,
              sport: this.sport.value,
              intensity: this.intensity.value,
              fee: this.fee.value,
              maxPlayers: this.maxPlayers.value
            };

            this.eventService.createEvent(eventData).subscribe(
              (res: any) => {
                this.alertService.createAlert({ message: EVENT_CREATED_MESSAGE, type: AlertType.Success });
                this.router.navigate(['events', res.data.event.id]);
              }
            );
          } else {
            this.handleInvalidLocationError();
          }
        }
     });
  );
}

Original

Perhaps the event is emitted outside Angular zone.

Try:

constructor(private zone: NgZone) { }

and:

this.zone.run(() => this.router.navigate(['events', res.data.event.id]));

If this solves the issue, you should fix EventService

Depending on the order of when the subscription occurs, you could be missing the event entirely. Consider using shareReplay(1) and exposing an event.

Alternatively, move the subscription of the event to the constructor:

  constructor(
    private activatedRoute: ActivatedRoute,
    private eventService: EventService
  ) { 
     this.getEvent();
  }

  ngOnInit() {
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM