Skip to content

Commit

Permalink
refactor(movies): use afterNextRender
Browse files Browse the repository at this point in the history
  • Loading branch information
BioPhoton committed Nov 12, 2023
1 parent 13b5544 commit 86d66b2
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 103 deletions.
54 changes: 4 additions & 50 deletions projects/movies/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
"sourceRoot": "projects/movies/src",
"targets": {
"build": {
"executor": "@angular-devkit/build-angular:browser",
"executor": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/projects/movies/browser",
"index": "projects/movies/src/index.html",
"main": "projects/movies/src/main.ts",
"browser": "projects/movies/src/main.ts",
"tsConfig": "projects/movies/tsconfig.app.json",
"inlineStyleLanguage": "scss",
"namedChunks": true,
Expand All @@ -36,9 +36,7 @@
"development": {
"namedChunks": true,
"sourceMap": true,
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"optimization": false,
"serviceWorker": false
},
Expand All @@ -47,7 +45,6 @@
"namedChunks": true,
"sourceMap": true,
"extractLicenses": false,
"buildOptimizer": false,
"optimization": false,
"serviceWorker": false,
"budgets": false
Expand Down Expand Up @@ -102,61 +99,18 @@
"defaultConfiguration": "production",
"outputs": ["{options.outputPath}"]
},
"build-esbuild": {
"executor": "@angular-devkit/build-angular:browser-esbuild",
"options": {
"outputPath": "dist/projects/movies/browser",
"index": "projects/movies/src/index.html",
"main": "projects/movies/src/main.ts",
"tsConfig": "projects/movies/tsconfig.app.json",
"inlineStyleLanguage": "scss",
"namedChunks": true,
"assets": [
"projects/movies/src/favicon.ico",
"projects/movies/src/manifest.json",
"projects/movies/src/manifest.webmanifest",
"projects/movies/src/assets",
"projects/movies/src/_routes.json"
],
"styles": ["projects/movies/src/styles.scss"],
"scripts": []
},
"configurations": {
"development": {
"namedChunks": true,
"sourceMap": true,
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"optimization": false,
"serviceWorker": false
},
"production": {
"serviceWorker": true,
"ngswConfigPath": "projects/movies/src/ngsw-config.json",
"fileReplacements": [
{
"replace": "projects/movies/src/environments/environment.ts",
"with": "projects/movies/src/environments/environment.production.ts"
}
]
}
},
"defaultConfiguration": "production",
"outputs": ["{options.outputPath}"]
},
"serve": {
"executor": "@angular-devkit/build-angular:dev-server",
"options": {
"port": 4200
},
"configurations": {
"development": {
"browserTarget": "movies:build:development"
"buildTarget": "movies:build:development"
},
"production": {
"port": 4201,
"browserTarget": "movies:build:production"
"buildTarget": "movies:build:production"
}
},
"defaultConfiguration": "development"
Expand Down
9 changes: 3 additions & 6 deletions projects/movies/src/app/auth/access-token-facade.service.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import { inject, Injectable, PLATFORM_ID } from '@angular/core';
import {afterNextRender, Injectable} from '@angular/core';
import { environment } from '../../environments/environment';
import { isPlatformBrowser } from '@angular/common';

@Injectable({ providedIn: 'root' })
export class AccessTokenFacade {
private readonly platformId = inject(PLATFORM_ID);

private _accessToken = environment.tmdbApiReadAccessKey;

get accessToken(): string {
return this._accessToken;
}

constructor() {
if (isPlatformBrowser(this.platformId)) {
afterNextRender(() => {
// set accessToken if found in localStorage
const accessToken = window.localStorage.getItem('accessToken');
accessToken && this.setUserAccessToken(accessToken);
}
});
}

setUserAccessToken(accessToken: string) {
Expand Down
17 changes: 8 additions & 9 deletions projects/movies/src/app/auth/auth.effects.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {DOCUMENT, isPlatformBrowser} from '@angular/common';
import {inject, Injectable, PLATFORM_ID} from '@angular/core';
import {DOCUMENT} from '@angular/common';
import {afterNextRender, inject, Injectable} from '@angular/core';
import {AccessTokenResponse, Authv4Resource, RequestTokenResponse,} from '../data-access/api/resources/authv4.resource';
import {AccessTokenFacade} from './access-token-facade.service';
import {AccountState} from '../state/account.state';
Expand All @@ -9,28 +9,27 @@ import {AccountState} from '../state/account.state';
})
export class AuthEffects {
private readonly document = inject(DOCUMENT);
private readonly platformId = inject(PLATFORM_ID);
private readonly authResource = inject(Authv4Resource);
private readonly accessTokenFacade = inject(AccessTokenFacade);
private readonly accountState = inject(AccountState);
private readonly redirectUrl = `${this.document.location.protocol}//${this.document.location.hostname}:${this.document.location.port}/list/category/popular`;

constructor() {
if (isPlatformBrowser(this.platformId)) {
afterNextRender(() => {
// should we finish the signIn ?
const requestToken = window.localStorage.getItem('requestToken');
requestToken && this.signInFinish(requestToken);
}
})
}

signInStart = (): void => {
this.authResource
.createRequestToken(this.redirectUrl)
.subscribe(({ request_token }: RequestTokenResponse) => {
if (isPlatformBrowser(this.platformId)) {
afterNextRender(() => {
// after redirecting to the redirectUrl, the requestToken in localStorage will indicate that an accessToken should be requested
window.localStorage.setItem('requestToken', request_token);
}
})
this.document.location.replace(
`https://www.themoviedb.org/auth/access?request_token=${request_token}`
);
Expand All @@ -41,15 +40,15 @@ export class AuthEffects {
this.authResource
.createAccessToken(requestToken)
.subscribe(({ access_token, account_id }: AccessTokenResponse) => {
if (isPlatformBrowser(this.platformId)) {
afterNextRender(() => {
window.localStorage.removeItem('requestToken');

window.localStorage.setItem('accountId', account_id);
this.accountState.set({ accountId: account_id });

window.localStorage.setItem('accessToken', access_token);
this.accessTokenFacade.setUserAccessToken(access_token);
}
})
});
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {isPlatformBrowser} from '@angular/common';
import {DestroyRef, Directive, ElementRef, inject, Output, PLATFORM_ID} from '@angular/core';
import {afterNextRender, DestroyRef, Directive, ElementRef, inject, Output} from '@angular/core';
import {rxActions} from '@rx-angular/state/actions';
import {observeElementVisibility} from './observe-element-visibility';

Expand All @@ -11,7 +10,6 @@ type Actions = { visible: boolean; onDestroy: void };
selector: '[elementVisibility]',
})
export class ElementVisibilityDirective {
private readonly platformId = inject(PLATFORM_ID);
private readonly destroyRef = inject(DestroyRef);

events = rxActions<Actions>();
Expand All @@ -20,10 +18,10 @@ export class ElementVisibilityDirective {
elementVisibility = this.events.visible$;

constructor(elRef: ElementRef) {
if (isPlatformBrowser(this.platformId)) {
afterNextRender(() => {
const sub = observeElementVisibility(elRef.nativeElement)
.subscribe(this.events.visible);
this.destroyRef.onDestroy(() => sub.unsubscribe());
}
})
}
}
10 changes: 0 additions & 10 deletions projects/movies/src/app/shared/cdk/platform.helper.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { isPlatformBrowser } from '@angular/common';
import {
afterNextRender,
inject,
Injectable,
NgZone,
PLATFORM_ID,
} from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { isZonePresent } from './is-zone-present';
import {NavigationEnd, Router} from '@angular/router';
import {isZonePresent} from './is-zone-present';
import {rxEffects} from '@rx-angular/state/effects';

/**
Expand All @@ -18,7 +17,6 @@ import {rxEffects} from '@rx-angular/state/effects';
export class ZonelessRouting {
private readonly effects = rxEffects();
private readonly router = inject(Router);
private readonly platformId = inject(PLATFORM_ID);
private readonly ngZone = inject(NgZone);

init() {
Expand All @@ -28,20 +26,22 @@ export class ZonelessRouting {
* In zone-less applications we have to trigger CD on every `NavigationEnd` event that changes the view.
* This is a necessity to make it work zone-less, but does not make the app faster.
*/
if (isPlatformBrowser(this.platformId) && !isZonePresent()) {
this.effects.register(
// Filter relevant navigation events for change detection
this.router.events,
// In a service we have to use `ApplicationRef#tick` to trigger change detection.
// In a component we use `ChangeDetectorRef#detectChanges()` as it is less work compared to `ApplicationRef#tick` as it's less work.
(e) => {
if (e instanceof NavigationEnd) {
// Inside appRef [NgZone.onMicrotaskEmpty is used to call appRef.tick()](https://github.com/angular/angular/blob/2fc5b70fcedb8ac35b825b245c0ae394dc125244/packages/core/src/application_ref.ts#L769)
// As the router events are not tracked in a zone-less environment we programmatically schedule onMicrotaskEmpty here to trigger CD after routing occurred
this.ngZone.onMicrotaskEmpty.next(true);
if (!isZonePresent()) {
afterNextRender(() => {
this.effects.register(
// Filter relevant navigation events for change detection
this.router.events,
// In a service we have to use `ApplicationRef#tick` to trigger change detection.
// In a component we use `ChangeDetectorRef#detectChanges()` as it is less work compared to `ApplicationRef#tick` as it's less work.
(e) => {
if (e instanceof NavigationEnd) {
// Inside appRef [NgZone.onMicrotaskEmpty is used to call appRef.tick()](https://github.com/angular/angular/blob/2fc5b70fcedb8ac35b825b245c0ae394dc125244/packages/core/src/application_ref.ts#L769)
// As the router events are not tracked in a zone-less environment we programmatically schedule onMicrotaskEmpty here to trigger CD after routing occurred
this.ngZone.onMicrotaskEmpty.next(true);
}
}
}
);
);
})
}
}
}
8 changes: 3 additions & 5 deletions projects/movies/src/app/state/account.state.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { inject, Injectable, PLATFORM_ID } from '@angular/core';
import {afterNextRender, inject, Injectable} from '@angular/core';
import {rxState} from '@rx-angular/state';
import { filter, map, switchMap } from 'rxjs';
import { TMDBAccountList } from '../data-access/api/model/list.model';
import { AccountResource } from '../data-access/api/resources/account.resource';
import { isPlatformBrowser } from '@angular/common';

export interface AccountStateModel {
accountId: string | null;
Expand All @@ -17,10 +16,10 @@ export class AccountState {
// if account id changes update lists in state
private readonly authResource = inject(AccountResource);
private readonly state = rxState<AccountStateModel>(({connect, set}) => {
if (isPlatformBrowser(this.platformId)) {
afterNextRender(() => {
// set accountId if found in localStorage
set({ accountId: window.localStorage.getItem('accountId') });
}
})
connect('lists', this.accountId$.pipe(
// process only given accountId
filter((accountId): accountId is string => accountId !== null),
Expand All @@ -30,7 +29,6 @@ export class AccountState {
});
set = this.state.set;
select = this.state.select;
private readonly platformId = inject(PLATFORM_ID);

readonly accountId$ = this.state.select('accountId');
readonly loggedIn$ = this.state.select(map(({ accountId }) => accountId !== null));
Expand Down

0 comments on commit 86d66b2

Please sign in to comment.