未在 Router.navigate() 上触发角度变化检测
Posted
技术标签:
【中文标题】未在 Router.navigate() 上触发角度变化检测【英文标题】:Angular Change Detection not triggering on Router.navigate() 【发布时间】:2018-06-28 16:39:01 【问题描述】:我在 Angular 中有一个名为 NewEventComponent
的组件,它只包含一个用于提交新事件的表单。在它的提交方法上有这个代码:
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();
);
它只将事件发送到服务器并重定向到事件页面,即EventDetails
组件。该组件仅向服务器请求请求的事件并将其作为输入传递给子组件。这是代码:
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>
子组件EventDetailsInfo
只接收事件作为像这样@Input() event: EventResponse;
这样的输入,并在html中显示这样的信息:<h5> event?.name </h5>
。
这里的问题是,当从NewEvent
组件导航到EventDetails
组件时,不会触发更改检测,因此直到我单击 DOM 中的任何位置,例如,更改不会显示。但是当我通过 url 直接导航到 EventDetails
组件时,页面正在正确呈现。
我在变更检测方面遗漏了什么?任何想法?谢谢!
PS:EventService
只执行 HTTP 调用并将它们作为 Observables 返回,例如:
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:这是“onSubmit()”方法中使用的GeolocationService
方法:
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;
【问题讨论】:
什么是EventService
?也许该事件是在 Angulars 区域之外发出的。
我已经用服务方法更新了答案,它只有http调用
可能是路由配置有问题。请尝试在stackblitz.com中创建一个最小的复制品
好的,这是一个复杂的应用程序,但我稍后会尝试创建一个简单的复制品并在此处发布。我对这个问题很迷茫......
只添加绝对必要的复制。其他一切都只是噪音,难以追查问题。
【参考方案1】:
更新
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();
);
);
原创
也许事件是在 Angular 区域之外发出的。
试试:
constructor(private zone: NgZone)
和:
this.zone.run(() => this.router.navigate(['events', res.data.event.id]));
如果这解决了问题,你应该修复EventService
【讨论】:
我试过这个,它解决了问题,但我不明白为什么......那是服务问题? 这可能是服务,但很难说。您分享的代码看起来不错。 我好像遇到过这个问题……不过我不是很懂。我想发布一个最少的代码,以便清楚地理解,但我错过了在提交表单时使用GeolocationService
...我已经用GeolocationService
的完整代码更新了我的答案和onSubmit()
方法。所以现在,我认为问题出在GeolocationService
对吗?如果你能更新你的答案会让我很开心!
感谢您的解释!最后我所做的是在GeolocationService
方法中调用zone.run(...)
方法。因此,当服务发出 Subject 的下一个值时,它位于 Angular 区域内,因此在对该方法的任何订阅后,都会触发更改检测。
是的!问题是Google JS library
使用JSONP
来获取Google APIS,所以它在Angular Zone 之外运行。【参考方案2】:
根据订阅发生的顺序,您可能会完全错过该事件。考虑使用shareReplay(1)
并公开一个事件。
或者,将事件的订阅移动到构造函数:
constructor(
private activatedRoute: ActivatedRoute,
private eventService: EventService
)
this.getEvent();
ngOnInit()
【讨论】:
以上是关于未在 Router.navigate() 上触发角度变化检测的主要内容,如果未能解决你的问题,请参考以下文章
防止在Angular中的单个router.navigate调用上滚动到顶部
Backbone.history.navigate和this.router.navigate之间有什么区别
Angular router.navigate w/ route guard 在组件上时不起作用