Issue
I have this Angular resolver:
@Injectable()
export class DataResolver implements Resolve<any> {
constructor(private apiService: ApiService) {}
public resolve(route: ActivatedRouteSnapshot): any {
const data = {
param1: route.queryParamMap.get('param1'),
param2: route.queryParamMap.get('param2'),
};
return this.apiService.search(data);
}
}
The apiService.search method looks like this:
public search(data): Observable<any> {
let params = new HttpParams();
for (const key in data) {
if (data.hasOwnProperty(key)) {
const value = data[key];
if (value) {
params = params.set(key, value);
}
}
}
return this.http.get<any>(`${API_URL}/endpoint`, { params });
}
Then I have a component that subscribes to changes on the ActivatedRoute
‘s data:
route.data.subscribe((data) => {
console.log(data);
});
And the route looks like this:
{
component: HomeComponent,
path: '/',
resolve: {
data: DataResolver,
},
runGuardsAndResolvers: 'paramsOrQueryParamsChange',
}
The problem is, the subscription handler only gets called if the data
actually changes, regardless of if the resolve
method of the resolver has been called. In particular, if two (or more) subsequent resolve calls resolve an empty array then the line console.log(data)
only gets called the first time.
Is this the expected behaviour? can I force the observable to emit a new value?
My goal is to show a message every time the resolve resolves an empty array, regardless of if it was empty before.
Solution
You have unnecessarily wrapped the observable in a promise and resolved it. Try rewriting your resolver like this.
@Injectable()
export class DataResolver implements Resolve<any> {
constructor(private apiService: ApiService) {}
public resolve(route: ActivatedRouteSnapshot): any {
const data = {
param1: route.queryParamMap.get("param1"),
param2: route.queryParamMap.get("param2"),
};
return this.apiService.search(data);
}
}
I would also look at cleaning up your API service by using HttpPrams
// import { HttpClient,HttpParams } from '@angular/common/http';
public search(data): Observable<any> {
let params = new HttpParams({ fromObject: data });
return this.http.get<any>(`${API_URL}/endpoint`, { params });
}
you may need to add the resolver to your route table
RouterModule.forRoot([{
path: 'yourRoute',
component: YourComponent,
resolve: {
yourDataWillBeInThisProperty: DataResolver
}
}])
if you want the component to reload you may need to change the onSameUrlNavigation
property in your router module
@NgModule({
imports: [ RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' }) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
I would not recommend using the onSameUrlNavigation
for your issue but would just subscribe to the route.queryParams
observable and trigger the search there.
In your component
ngOnInit(){
this.sub = this.route.queryParams.subscribe(() => { this.data = this.route.snapshot.data.data; });
// don't forget to unSubscribe
}