Universal: ReferenceError: document is not defined

Created on 6 Dec 2017  路  8Comments  路  Source: angular/universal

  • I'm submitting a ...
- [x] bug report
- [ ] feature request
- [ ] support request => Please do not submit support request here, see note at the top of this template.
  • What modules are related to this Issue?
- [ ] aspnetcore-engine
- [x] express-engine
- [ ] hapi-engine
  • Do you want to request a feature or report a bug?
    Bug.

  • What is the current behavior?
    When you try and enter your server bundle on localhost:4000 in the browser you get an error saying ReferenceError: document is not defined for one of my services which handles cookies.

  • If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem by creating a github repo.

Follow the story here, run the bundle and go to localhost:4000.

https://github.com/angular/angular-cli/wiki/stories-universal-rendering

  • What is the expected behavior?
    I expect the bundle to run and/or fail silently for this kind of error, or if there's some kind of polyfill I can use.

  • What is the motivation / use case for changing the behavior?
    If I have a service which uses document how can I avoid this error for being thrown? It's not like I can just exclude it from the server bundle because basically every module uses this service.

  • Please tell us about your environment:

  • Angular version: 4.4.6

  • Browser: [all]
  • Language: [all]
  • OS: [all]
  • Platform: [NodeJs]

Most helpful comment

Please read the Universal "Gotchas" section of the README. It explains both why document isn't available and how to check for the current platform to write conditional code.

window, document, navigator, and other browser types - do not exist on the server - so using them, or any library that uses them (jQuery for example) will not work.

import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';

constructor(@Inject(PLATFORM_ID) private platformId: Object) { ... }

ngOnInit() {
  if (isPlatformBrowser(this.platformId)) {
     // Client only code.
     ...
  }
  if (isPlatformServer(this.platformId)) {
    // Server only code.
    ...
  }
}

All 8 comments

Please read the Universal "Gotchas" section of the README. It explains both why document isn't available and how to check for the current platform to write conditional code.

window, document, navigator, and other browser types - do not exist on the server - so using them, or any library that uses them (jQuery for example) will not work.

import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';

constructor(@Inject(PLATFORM_ID) private platformId: Object) { ... }

ngOnInit() {
  if (isPlatformBrowser(this.platformId)) {
     // Client only code.
     ...
  }
  if (isPlatformServer(this.platformId)) {
    // Server only code.
    ...
  }
}

That works, thanks. These gotchas should almost be thrown in your face, cuz I completely missed them.

// SSR
import { isPlatformBrowser } from '@angular/common';
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';

constructor(@Inject(PLATFORM_ID) private platformId: Object) {
   // BROWSER
   if (isPlatformBrowser(this.platformId)) {

   }
}

Hey @chriseugenerodriguez - thank you for posting the code. Where would it go in the angular project? I have the same issue with a library using document and, being new to angular, still haven't got a handle on how it all comes together.

whenever you are referencing window, document, localstorage, sessionstorage you wrap it with if statement.

if (isPlatformBrowser(this.platformId)) {

   }

Question: what if we have no place to inject the platform_id? IE regular function that say, injects an html element in body, there is no class to inject into, is there a way?
example: extending the Storage object

Storage.protoytype.getObject  = function()...

Question: what if we have no place to inject the platform_id? IE regular function that say, injects an html element in body, there is a class to inject into, is there a way?

@ayyash What do you mean regular function? Where is it located? If it's in an Angular component/service/module, then you have access to platformId through dependency injection. If your functions is just in its own script file with no connection to Angular, then it has no way to access it, as far as I know, unless you are willing to go a very hackish route.

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings