9

I want to use SSR to improve search engine optimization on my angular single page application. I have enabled SSR by using Angular-Universal which is working to serve the static html but my components heavily rely on asynchronous api calls to build the content on the page. See the example below where the $obs is initialized in the ngOnInit function and then used with the async pipe in the html to pull out data. The problem I am having is the static html served by the SSR does not include anything that uses an async pipe, these calls are made on the client side and then the content is loaded. This is not what I want because I need the content from the api call to generate meta tags. Is it possible to force angular universal to wait for the api call to finish, render the html with this data and then serve the static html?

@Component({
  selector: 'app-example-component',
  template: `
    <div *ngIf="(obs$ | async) as model">
      {{model.title}}
    </div>
  `
})
export class ExampleComponent implements OnInit {

  obs$: Observable<SomeModel>;

  constructor(private exampleHttpService: ExampleHttpService) {}

  ngOnInit() {
    this.obs$ = this.exampleHttpService.doSomeApiCall();
  }
}

I want the SSR to render the template html with the title from the api call then serve that static html.

Jack Zavarella
  • 335
  • 1
  • 4
  • 13
  • You would probably need to add a server-side route that did an async / await request for the same content in order to force the request to wait until the content is retrieved before rendering the response. That would only apply to spiders though. Universal only serves the index.html once if you're in a browser. – Brandon Taylor Aug 21 '19 at 02:16

1 Answers1

1

I ended up fixing my issue which was being caused by two different problems:

First problem: Not shown in my example component but it my actual code, I was modifying the document object in the first line of the ngOnInit method which when ran would cause the server side rendering to fail before it got to the http call.

Second problem: After removing usage of document, I needed to add an api route to my server.ts file to proxy the requests to the backend as @Brandon suggested.

const request = require('request');

app.get('/api/**', (req, res) => {
  const url = `${backendUrl}${req.originalUrl}`;
  request(url).pipe(res);
});
Jack Zavarella
  • 335
  • 1
  • 4
  • 13