title: Angular Universal does not render all in server side
body: <p>I am building a solution with Angular 4 + Angular Universal + Knockout.</p>
  
  <p>The idea is that the angular application will render html in server side for SEO purposes, but as part of that rendering process it must be able to use knockoutJs to bind some html text with a view model in order to render first the html bound to knockout and then finalize server side rendering and send the result html to the browser.</p>
  
  <p>The reason to mix angular with knockout is because we have some html (e.g: <code>'&lt;span data-bind="text: test"&gt;&lt;/span&gt;'</code>) as a string coming from an existing third party that contains knockout markup.</p>
  
  <p>I am able to use knockout inside my Angular module and apply the bindings. The html text is able to display the content of the view model variable... <strong>but when executing the Angular app in server side this part is not rendered in server side</strong>, it works but it is rendered in client side and it's not acceptable as a solution for us.</p>
  
  <p>It is as if the server side javascript rendering engine didn't wait for an asynchronous call to apply the knockout bindings before sending to the client the finalized html rendered.</p>
  
  <p>I have followed <a href="https://coursetro.com/posts/code/68/Make-your-Angular-App-SEO-Friendly-(Angular-4-+-Universal)" rel="nofollow noreferrer">these steps to run Angular 4 with Universal</a> in back end.</p>
  
  <p>This is my simple knockout view model <code>mysample.ts</code>:</p>
  
  <pre><code>import * as ko from 'knockout';
  
  export interface IMySample {
      test: string;
  }
  
  export class MySample implements IMySample {
      public test: any = ko.observable("Hi, I'm a property from knockout");
  
      constructor(){
      }
  }
  </code></pre>
  
  <p>And this is my main component <code>home.component.ts</code> where I have some html as a text that contains knockout binding and I want to render in server side.</p>
  
  <pre><code>import { Component, OnInit } from '@angular/core';
  import { MySample } from '../ko/mysample';
  import { KoRendererService } from '../ko-renderer.service';
  
  @Component({
    selector: 'app-home',
    templateUrl: './home.component.html',
    styleUrls: ['./home.component.css'],
    providers: [KoRendererService]
  })
  export class HomeComponent implements OnInit {
  
    htmlWithKnockout: string = '&lt;span data-bind="text: test"&gt;&lt;/span&gt;';
    htmlAfterBinding: string = null;
    constructor(private koRendererService: KoRendererService) 
    { 
    }
  
    ngOnInit() {
      var mySample = new MySample();
      this.koRendererService.getHtmlRendered(this.htmlWithKnockout, mySample).then((htmlRendered: string) =&gt; {
        this.htmlAfterBinding = htmlRendered;
      });
    }
  }
  </code></pre>
  
  <p>with its view <code>home.component.html</code> that should display the same html with knockout binding but already rendered in the server (it's working only on client side):</p>
  
  <pre><code>&lt;p&gt;This content should be part of the index page DOM&lt;/p&gt;
  &lt;div id="ko-result" [innerHTML]="htmlAfterBinding"&gt;&lt;/div&gt;
  </code></pre>
  
  <p>And this is the service <code>ko-rendered.service.ts</code> I have created to apply the knockout bindings. I have made it asynchronous because <a href="https://github.com/angular/universal-starter/issues/181" rel="nofollow noreferrer">I read here</a> that Angular Unviersal should await for asynchronous calls to end before rendering the html in server side)</p>
  
  <pre><code>import * as ko from 'knockout';
  
  interface IKoRendererService {
      getHtmlRendered(htmlAsText: string, viewModel: any): Promise&lt;string&gt;;
  }
  
  export class KoRendererService implements IKoRendererService {
      constructor(){
  
      }
  
      getHtmlRendered(htmlAsText: string, viewModel: any): Promise&lt;string&gt; {
          return new Promise&lt;string&gt;((resolve, reject) =&gt; {
              var htmlDivElement: HTMLDivElement = document.createElement('div');
              htmlDivElement.innerHTML = htmlAsText;
              ko.applyBindings(viewModel, htmlDivElement.firstChild);
              var result = htmlDivElement.innerHTML;
              resolve(result);
          });
      }
  }
  </code></pre>
  
  <p>This is the response to the index.html page at the browser. We can see here that the angular content has been rendered in server side properly, however the part with the knockout binding is not in the DOM, it is retrieved at client side.</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;&lt;html lang="en"&gt;&lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;title&gt;Sample&lt;/title&gt;
    &lt;base href="/"&gt;
  
    &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
    &lt;link rel="icon" type="image/x-icon" href="favicon.ico"&gt;
  &lt;link href="styles.d41d8cd98f00b204e980.bundle.css" rel="stylesheet"&gt;&lt;style ng-transition="carama"&gt;&lt;/style&gt;&lt;/head&gt;
  &lt;body&gt;
    &lt;app-root _nghost-c0="" ng-version="4.1.3"&gt;&lt;ul _ngcontent-c0=""&gt;
    &lt;li _ngcontent-c0=""&gt;&lt;a _ngcontent-c0="" routerLink="/" href="/"&gt;Home&lt;/a&gt;&lt;/li&gt;
    &lt;li _ngcontent-c0=""&gt;&lt;a _ngcontent-c0="" routerLink="about" href="/about"&gt;About Us&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;hr _ngcontent-c0=""&gt;
  
  &lt;h1 _ngcontent-c0=""&gt;Welcome to the server side rendering test with Angular Universal&lt;/h1&gt;
  &lt;router-outlet _ngcontent-c0=""&gt;&lt;/router-outlet&gt;&lt;app-home _nghost-c1=""&gt;&lt;p _ngcontent-c1=""&gt;This content should be part of the index page DOM&lt;/p&gt;
  &lt;div _ngcontent-c1="" id="ko-result"&gt;&lt;/div&gt;&lt;/app-home&gt;
  &lt;/app-root&gt;
  &lt;script type="text/javascript" src="inline.77dfeeb563e4dcc7a506.bundle.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="polyfills.d90888e283bda7f009a0.bundle.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="vendor.451987311459166e7919.bundle.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="main.af6e993f16ecd4063c3b.bundle.js"&gt;&lt;/script&gt;
  
  &lt;/body&gt;&lt;/html&gt;
  </code></pre>
  
  <p>Notice how the div with <code>id="ko-result"</code> is empty. Later on in client side this div is properly modified in the DOM and looks like:</p>
  
  <pre><code>&lt;div _ngcontent-c1="" id="ko-result"&gt;&lt;span&gt;Hi, I'm a property from knockout&lt;/span&gt;&lt;/div&gt;
  </code></pre>
  
  <p><strong>But I need that rendering at server side</strong>...</p>
  
  <p>Any help would be much appreciated. Thanks!</p>
  
  <p><strong>UPDATE 1</strong>: This is my package.json with my dependencies:</p>
  
  <pre><code>{
    "name": "server-side-rendering",
    "version": "0.0.0",
    "license": "MIT",
    "scripts": {
      "prestart": "ng build --prod &amp;&amp; ngc",
      "start": "ts-node src/server.ts"
    },
    "private": true,
    "dependencies": {
      "@angular/animations": "^4.1.3",
      "@angular/common": "^4.0.0",
      "@angular/compiler": "^4.0.0",
      "@angular/core": "^4.0.0",
      "@angular/forms": "^4.0.0",
      "@angular/http": "^4.0.0",
      "@angular/platform-browser": "^4.0.0",
      "@angular/platform-browser-dynamic": "^4.0.0",
      "@angular/platform-server": "^4.1.3",
      "@angular/router": "^4.0.0",
      "core-js": "^2.4.1",
      "rxjs": "^5.1.0",
      "zone.js": "^0.8.4",
      "knockout": "^3.4.2"
    },
    "devDependencies": {
      "@angular/cli": "1.0.6",
      "@angular/compiler-cli": "^4.0.0",
      "@types/jasmine": "2.5.38",
      "@types/node": "~6.0.60",
      "codelyzer": "~2.0.0",
      "jasmine-core": "~2.5.2",
      "jasmine-spec-reporter": "~3.2.0",
      "karma": "~1.4.1",
      "karma-chrome-launcher": "~2.1.1",
      "karma-cli": "~1.0.1",
      "karma-jasmine": "~1.1.0",
      "karma-jasmine-html-reporter": "^0.2.2",
      "karma-coverage-istanbul-reporter": "^0.2.0",
      "protractor": "~5.1.0",
      "ts-node": "~2.0.0",
      "tslint": "~4.5.0",
      "typescript": "~2.2.0"
    }
  }
  </code></pre>
  
  <p><strong>UPDATE 2</strong>: At client side rendering it also works, I can see the final rendering on the browser, but as expected all the content is missing from the index.html request and it's javascript who fetches the content later on. This is the response when running the same app with <code>ng-serve</code> (client-side rendering):</p>
  
  <pre><code>&lt;!doctype html&gt;
  &lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;title&gt;Sample&lt;/title&gt;
    &lt;base href="/"&gt;
  
    &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
    &lt;link rel="icon" type="image/x-icon" href="favicon.ico"&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;app-root&gt;Loading sample, you should not see this in client side...&lt;/app-root&gt;
  &lt;script type="text/javascript" src="inline.bundle.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="polyfills.bundle.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="styles.bundle.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="vendor.bundle.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="main.bundle.js"&gt;&lt;/script&gt;&lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p><strong>UPDATE 3</strong>: I read <a href="http://dev.sebastienlucas.com/universal-angular/#what-not-to-do-in-angular-2-to-be-universal-loader-compatible" rel="nofollow noreferrer">here</a> that to have Angular app universal compatible we should not manipulate the DOM directly. I was wondering whether the fact that I am using <code>document</code> to create the HtmlElement that knockout <code>applyBindings</code> needs in my <code>ko-rendered.service.ts</code> was somehow making angular universal to ignore this rendering at server side, but I have tried to create the DOM element with <code>Renderer2</code> (e.g: <code>import { Component, OnInit, Renderer2 } from '@angular/core';</code>) instead and that did not resolve the issue either:</p>
  
  <pre><code>var htmlDivElement: any = renderer2.createElement('div')
              // var htmlDivElement: HTMLDivElement = document.createElement('div');
  </code></pre>
  
  <p><strong>UPDATE 4</strong>: I have seen the following errors in server-side node environment during the <code>ko.applyBindings</code> call, so I suspect the whole approach is problematic because <strong>knockoutJs is not really designed to be executed in server-side in an environment without a browser. It relies too much on the DOM</strong> and as The <a href="https://universal.angular.io/api/universal/index.html#best-practices" rel="nofollow noreferrer">Angular Universal good practices</a> say:</p>
  
  <blockquote>
    <p>Don't use any of the browser types provided in the global namespace
    such as navigator or document. Anything outside of Angular will not be
    detected when serializing your application into html</p>
  </blockquote>
  
  <p>These are the errors that must be causing that Angular Universal stops rendering at server side and simply passes it on to the browser:</p>
  
  <pre><code>listening on http://localhost:4000!
  ERROR { Error: Uncaught (in promise): TypeError: Cannot read property 'body' of undefined
  TypeError: Cannot read property 'body' of undefined
      at Object.ko.applyBindings 
  
  (C:\Dev\node_modules\knockout\build\output\knockout-latest.debug.js:3442:47)
  ..
  ERROR { Error: Uncaught (in promise): TypeError: this.html.charCodeAt is not a function
  TypeError: this.html.charCodeAt is not a function
  </code></pre>