0

Using Angular8, I would show the a user's profile by the url's params-id:

http://localhost:4200/user/El231A

If no user can be retrieved, I would route to my 404 error page.

Now the below code works just fine. However, the routing to the 404 error page occurs not immediately: the enduser would see my empty component for a fracture of a second. However, I would like to route to 404 BEFORE my component shows anything if the userprofile cannot be retrieved.

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.scss']
})
export class UserComponent implements OnInit {
  userprofile: Userprofile;


  constructor(private httpHandler: HttpHandlerService,
              private authService: AuthService,
              private route: ActivatedRoute) {
  }

  ngOnInit(): void {
    this.route.params.subscribe(params => {
      this.getUserprofile(params[`id`]);
    });
  }

  getUserprofile(userId: string): void {
    this.httpHandler.getUserProfile(userId)
      .subscribe(userprofile => this.userprofile = userprofile);
  }

}

(small sidenote: I am intentionally subscribing to the id parameter, as I want to update my GUI if the ID changes on the fly, see here for further details: Angular 2 reload route on param change)

My http handler would route to my 404 error page if I can't successfully fetch the user with the id:

export class HttpHandlerService {
  userApiUrl: string;

  constructor(private http: HttpClient, private router: Router) { }

  getUserProfile(userId: string): Observable<Userprofile> {
    const url = `${this.userApiUrl}/${userId}`;
    return this.http.get<Userprofile>(url).pipe(
      tap(_ => console.log(`fetched userprofile with id=${userId}`)),
      catchError(this.handleError<Userprofile>(`getUserProfile id=${userId}`))
    );
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      console.log(`${operation} failed: ${error.message}`);
      this.router.navigate(['404']).then();
      return of(result as T);
    };
  }

I don't feel like moving the ngOnInit() code part into the constructor would be the right approach. And I'm not aware of a angular lifecycle event before ngOnInit() which would fit.

Any thoughts? Thanks in advance.

2 Answers2

0

how about using resolver.

it can be get data when angular router navigating.

this is link about resolve

https://angular.io/api/router/Resolve

First

@Injectable()
export class exampleResolver implements Resolve<any> {
    constructor(private exampleService: ExampleService) { }

    resolve(route: ActivatedRouteSnapshot) {
        console.log('resolver', route);
        return this.exampleService.getList()
    }
}

then example module


    {
                path: "list", component: ExampleListComponent,
                data: { title: 'title.list' },
                resolve: { users: exampleListResolver }
            },

I hope it helps

RealTak
  • 96
  • 1
  • 5
0

You can do a little change here:

import { from, of, Observable } from 'rxjs';
import { switchMap, delay } from 'rxjs/operators';

private handleError<T>(operation = 'operation', result?: T) {
  return (error: any): Observable<T> => {
    console.log(`${operation} failed: ${error.message}`);

    // switchMap will be called only after navigate resolves
    return from(this.router.navigate(['404'])).pipe(
      delay(1000),
      switchMap((_: boolean) => of<T>(result))
    );
  };
}
julianobrasil
  • 8,954
  • 2
  • 33
  • 55