Mikael
Mikael

Reputation: 1309

Pass data from server side to client without http call

I develop angular universal & node.js as server application. I do everything like everybody suggests including official documentation.

Normally when client app is loaded it performs ajax query to API. API placed on this my server. and my goal is to avoid this ajax call and render page from server already with this data.

I try it like typical example:

ngOnInit() {
      let myTransferStateKey = makeStateKey<any>("myDatas");

      if(this.transferState.hasKey(myTransferStateKey)) {
          this.result = this.transferState.get(myTransferStateKey, {});
          this.transferState.remove(myTransferStateKey);
      } else {
          this.http.get("link-to-api").subscribe(response => {
              this.result = response;
              this.transferState.set(myTransferStateKey, this.result);
          });
      }
  }

So as I understand the following code will be executed on server side:

      this.http.get("link-to-api").subscribe(response => {
          this.result = response;
          this.transferState.set(myTransferStateKey, this.result);
      });

So server side will perform real http query to itself server ? It is ugly! Ideally I should just use service on my server and pass the data to view and then server will render html to client with this data. I hope you know what I mean..

Also this is my server.ts, typical code you most likely saw in the web:

import 'zone.js/dist/zone-node';
import 'reflect-metadata';

import { enableProdMode } from '@angular/core';

import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
import { AppServerModule } from './src/main.server';

import {ngExpressEngine} from '@nguniversal/express-engine';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
const app = express();

const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist', 'calendar');

// Our index.html we'll use as our template
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();

const domino = require('domino');

const window = domino.createWindow(template);

global['window'] = window;
global['document'] = window.document;

global['requestAnimationFrame'] = cb => cb();

app.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,
}));

app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));

// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));

// All regular routes use the Universal engine
app.get('/', (req, res) => {
    res.render(join(DIST_FOLDER, 'browser', 'index.html'), { req });
});


// Start up the Node server
app.listen(PORT, () => {
    console.log(`Node server listening on http://localhost:${PORT}`);
});

So how to solve it gracefully ? I like this universal approach and server side rendering but it looks for me as pretty damp for now.

I use angular 9 version, node.js 12 version...

Let me clarify and formulate the idea and question: How can I use single service (same class/file etc) for both client and server? Only the difference should be the server will use service directly, but client when it needs get data - will use ajax request to API, and here on server side - this service class will be used ) I have to make it works together with server.ts or something like this...

Upvotes: 2

Views: 2328

Answers (1)

MindingData
MindingData

Reputation: 12480

So I think you are getting mixed up with say Angular Universal vs a NodeJS Application.

Angular Universal renders the first page requested on the server, and from then on as you click around the site, it acts like a regular Angular application. It's really only to give the illusion that the first "paint" is really fast because you get almost the entire page rendered entirely as soon as you hit the site rather than a regular Angular app where you get sort of a blank page then as your subscriptions return you fill out the page etc.

If you want things to always be server side rendered, then you are probably looking at doing a standard Express NodeJS application that returns HTML views, not Angular Universal.

If you really want to still use Universal. Then you can use the angular methods called "isPlatformBrowser" and "isPlatformServer" to check whether you are running on the server or the browser, and then you can have logic to either call the API or fetch data directly.

For example :

export class PostfeedComponent implements OnInit {

  constructor(@Inject(PLATFORM_ID) private platform: Object) { }

  ngOnInit() {
      if (isPlatformBrowser(this.platform)) {
        // here you can run any browser specific code
      } else {
         // Runs only on server
      }
  }
}

More Info :

Upvotes: 3

Related Questions