4

I have a service that makes request to an api and according to its response I should decide that a component must be loaded or not. but because of a time spent to receive the response, component loads regardless of response status, and after some time (about 0.5 secs) response is received and if the component must not be loaded, we navigate to somewhere else. I don't want the component to be loaded before receiving the response.

I'm using canActivate function from AuthGuard in angular 4 as below:

export class AuthGuard implements CanActivate {
access = true;
res: any;

constructor(private router: Router, private routeService: RouteService){}

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    setTimeout(() => {
        if( !this.exept.includes(this.router.url) ){
            this.routeService.FormOperation(this.router.url).subscribe(item=> {
                this.res = item;
                if (this.res.status == 200) {
                    if (this.res.data.Access[1] == false) {
                        this.access = false;
                    }
                    if (this.access == true)
                    {
                       return true;
                    }
                else {
                    this.router.navigate(['/dashboard']);
                    return false;
                }
            })
        }
    },0);

    if (sessionStorage.getItem('token') && this.access)
    {
        // logged in so return true
        return true;
    }

    // not logged in so redirect to login page with the return url
    this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
    return false;
}

I'm using setTimeout so that I can get a correct this.router.url .

Update:

I added resolver as below:

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): void {

    this.routeService.FormOperation(this.router.url).toPromise()
        .then(response => {
            this.form_operation_data = response;

            if(!this.form_operation_data['data']['Access'][1]) {
                this.router.navigate(['/dashboard']);
            }
        })
        .catch(err => {
            console.error(err);
        });
}

but still the component loads before response data receives ...

Hamid Hosseini
  • 217
  • 4
  • 8

1 Answers1

2

You're so close: your AuthGuard should return true or false, and based on this value, the route will be activated or not. Now you have to add this auth guard to your routing (here is an example for activating child route). And if you want to fetch data before component load, you can use resolvers.

Resolver

/* Imports */
@Injectable()
export class DataResolverService {

  constructor(
    private _serviceToShareData: ServiceToShareData,
    private _serviceToGetData: ServiceToGetData,
  ) { }

  /* An example with Promise */
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<void> {
    return this._serviceToGetData.anyRequestToApi()
      .then(response => this._serviceToShareData.setData(response))
      .catch(err => {
        console.error(err);
      });
  }
}

And now you can get fetched data from ServiceToShareData service in your component, which you want to load with this data.

Routing module

/* Other imports */
import {DataResolverService } from './path-to-service/data-resolver-service'
import {AuthGuard} from './path-to-service/auth-guard'

const routes: Routes = [
  {
    path: 'app',
    component: ParentComponent,
    children: [
      {
        path: 'child-route',
        component: childRouteComponent,
        canActivate: [AuthGuard],
        resolve: {
          data: DataResolverService
        }
      }
    ]
  }
];

/* Other stuff like @NgModule and class export*/
P.S.
  • 15,970
  • 14
  • 62
  • 86
  • thank you Commercial Suicide. I updated my question and added resolver, please take a look ... – Hamid Hosseini Nov 20 '17 at 06:47
  • @Commercial Suicide I am wondering what would cause resolve not to load? I haven't used one since angular 1. Do I need a certain data type? – Winnemucca Oct 07 '20 at 12:06
  • 1
    @Winnemucca, you can find more details here: https://angular.io/api/router/Resolve. If you're making an asynchronous call inside your resolver, you should return `Promise` or `Observable` (there was the same mistake in my answer, corrected). Actually, if all the operations are synchronous, you can just return the value, it's fine (but in most cases you're dealing with asynchronous calls). – P.S. Oct 07 '20 at 13:33