I have made an angular app using angular-cli and doing universal rendering in it by following steps given here . But it is mentioned that i can't use Global variables like window and document in my app if i am doing universal rendering, How can i set cookies at front end to maintain user session. Previously i was using JWT, but for doing that i need to set cookies in my browser.
Note: All the information below is only valid if you're using Node with Express to dynamically render (at the time a request hits the server) your Angular app on the server. I haven't looked into pre-rendering. And I don't know how you would go about it if you'd be using a framework other than Express, like Hapi or whatever other frameworks are out there. I can only guess that @nguniversal
should offer a solution for those as well, but haven't looked into it.
That being said, here's the way I've just managed to make cookies available in my app when it is rendered server side:
app.server.module.ts
:
// ...
import { Request } from 'express';
import { REQUEST } from '@nguniversal/express-engine/tokens';
@Injectable()
export class RequestCookies {
constructor(@Inject(REQUEST) private request: Request) {}
get cookies() {
return !!this.request.headers.cookie ? this.request.headers.cookie : null;
}
}
@NgModule({
imports: [
// ...
],
providers: [
CookieService,
{ provide: 'req', useClass: RequestCookies }
],
bootstrap: [AppComponent]
})
export class AppServerModule {}
app.module.ts
: (some might call it app.browser.module.ts
)
@NgModule({
declarations: [
// ...
],
imports: [
// ...
],
providers: [
CookieService,
{
provide: 'req',
useValue: null
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
cookie.service.ts
:
import { Inject, Injectable } from '@angular/core';
@Injectable()
export class CookieService {
private cookieStore = {};
constructor(
@Inject('req') private readonly req: any,
) {
if (this.req !== null) {
this.parseCookies(this.req.cookies);
} else {
this.parseCookies(document.cookie);
}
}
public parseCookies(cookies) {
this.cookieStore = {};
if (!!cookies === false) { return; }
let cookiesArr = cookies.split(';');
for (const cookie of cookiesArr) {
const cookieArr = cookie.split('=');
this.cookieStore[cookieArr[0]] = cookieArr[1];
}
}
get(key: string) {
return !!this.cookieStore[key] ? this.cookieStore[key] : null;
}
}
any.component.ts
:
// ...
constructor(
private cookieService: CookieService
) {}
needMyCookie() {
const userCookie = this.cookieService.get('user');
}
Make sure you > npm install express @nguniversal/express-engine
P.S. I started by looking at this repo: https://github.com/angular/universal-starter/tree/master/cli for the server-side-rendering, only did the cookie part myself (wasn't included there). That repo follows the universal story from your link but goes beyond. If you simply follow the universal story, it says:
Lazy loading is not yet supported
But if you try the repo I gave the link to, you'll discover that lazy loaded modules ARE RENDERED on the server also! I don't know what the key is, maybe it has to do with the code in the server.js
file and @nguniversal/module-map-ngfactory-loader
I've tried it with: CLI version 1.4.2 and Angular version: 4.4.1
This is what I get with javascript disabled in the browser:
My carousel items are spaced like that because they're actually scaled to 90%. I have a zoomIn animation on the item in onInit. And on the server-rendered view, I force-style them to 90% so they won't appear at 100% on the first load and then, after the client kicks in, have them animate 90 to 100.
Also, if anybody comes across this answer and notices a reference to the viewport width in the screenshot, in the codeblock below the main navigation links - in case they're wondering - this is my WindowService
:
import { Injectable, PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
@Injectable()
export class WindowService {
constructor(
@Inject(PLATFORM_ID) private readonly platformId: any,
) {}
get width() {
if (isPlatformBrowser(this.platformId)) {
return window.innerWidth;
} else {
return 'Not available server-side!';
// return null;
}
}
}
Simply add it to the providers: []
array in both app.module.ts
and app.server.module.ts
.
Another thing to be noted here is that I'm using Node with Express. I don't know about doing this if you're using other frameworks, like Hapi or whatever other frameworks that are out there.
@Injectable()
decorator to the RequestCookies
class (I've also updated the answer)... But that wouldn't be needed unless you'd want to directly inject that class in another service, plus I think that the error would sound different. –
Emblazonry console.log('token',this.cookieService.get('token'));
gives undefined
in node console, although the cookie token
is there –
Countercurrent I have had success using the npm package ng2-cache (I am using Angular 4 and it works just fine). I am using the local storage, so I have it in my module providers array like this:
providers: [
CacheService,
{provide: CacheStorageAbstract, useClass: CacheLocalStorage},
...
]
Another option is to use isPlatformBrowser() as shown here.
The ugliest option is to just put your code dealing with cookies in try-catch statements. That way it will work on the browser and be ignored on the server side.
© 2022 - 2024 — McMap. All rights reserved.