Search code examples
angulartypescriptasynchronousresolveangular-resolver

How to use Angular 8 resolver with typescript?


I am trying to make an application just like pastebin.com where i can use syntax highlight. Now i am trying to make the share file method. I am getting all the data from an .NET Core API, and the response are exactly what i need.

The problem is when i open the shared link the component gets initialized before the promise is resolved.

Let's say i want to open the following link: http://localhost:4200/shared/1

When i open the link, the data where the file=1 is fetched and placed in a model. Then i want the component to be loaded and html displayed.

I don't understand how resolver work, what can i do ? Thanks.

user.service.ts

@Injectable({
    providedIn: 'root'
})
export class UserService implements Resolve<any> {

resolve(route: ActivatedRouteSnapshot){
        console.log('Logging collected route parameter', route.params['file']);
        this.http.get(this.BaseURL + '/Share?IdentityString=' + route.params['file'])
        .subscribe(res =>{
        this.sharedFormData = res as ShareModel;

        console.log(this.sharedFormData);
    });
      }
}

app-routing.module.ts

export const routes: Routes = [
  { 
    path: 'shared/:file',
    component: FileShareComponent,
    resolve: {
      shared: UserService
    }
  }
]

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

fileshare.component.html

export class FileShareComponent implements OnInit {

  constructor(
    private route: ActivatedRoute,
    private router: Router,
    private service: UserService,
    private http: HttpClient
  ) {}

  ngOnInit() {
    console.log('Component initialized');
  }
}

fileshare.component.html

<pre class="text-white"style="color: white;">Name: {{service.sharedFormData?.Name}}</pre>
<pre style="color: white;">Description: {{service.sharedFormData?.Description}}</pre>
<pre style="color: white;">Syntax: {{service.sharedFormData?.Syntax}}</pre>
<pre style="color: white;">LastModified: {{service.sharedFormData?.LastModified | date: "HH:mm dd/MM/yyyy"}}</pre>
<pre style="color: white;">ExpirationDate: {{service.sharedFormData?.ExpirationDate | date: "HH:mm dd/MM/yyyy"}}</pre>
<pre><code class="hljs">{{service.sharedFormData?.Content}}</code></pre>

This is how the URL looks: http://localhost:4200/shared/MThBU1AgLk5FVCBDb3Jl

Console log


Solution

  • You have to return the Observable/Promise in the resolve() method so that the HTTP request is finished before the component is initialized. Also note that you should not subscribe to the HTTP call in the resolve() method. Just return it as it is. If you want to log/store the data, use the tap() rxjs operator.

    Modify your code as below:

    Resolver:

    @Injectable({
        providedIn: 'root'
    })
    export class UserService implements Resolve<any> {
    
      resolve(route: ActivatedRouteSnapshot){
        console.log('Logging collected route parameter', route.params['file']);
        return this.http.
          get(this.BaseURL + '/Share?IdentityString=' + route.params['file'])
          .pipe(tap(res => console.log('Response from HTTP req: ', res)));
      }
    }
    

    Component:

    export class FileShareComponent implements OnInit {
    
      constructor(
        private route: ActivatedRoute,
        private router: Router,
        private service: UserService,
        private http: HttpClient
      ) {}
    
      ngOnInit() {
        console.log('Component initialized');
        this.route.data.subscribe((data: { shared: any }) => {
          let formData = data.shared as ShareModel;
          // perform your logic now
        });
      }
    }
    

    More information on resolver can be found here.