From afc38395fe294813813b48903798766170d9bca9 Mon Sep 17 00:00:00 2001 From: SanderElias Date: Fri, 24 Jan 2020 14:23:45 +0100 Subject: [PATCH] improvement(better demo): a more complete demo --- .../src/app/user/post/post.component.css | 0 .../src/app/user/post/post.component.html | 5 ++ .../src/app/user/post/post.component.spec.ts | 24 ++++++++ .../src/app/user/post/post.component.ts | 50 ++++++++++++++++ .../src/app/user/posts/posts.component.css | 0 .../src/app/user/posts/posts.component.html | 8 +++ .../app/user/posts/posts.component.spec.ts | 24 ++++++++ .../src/app/user/posts/posts.component.ts | 54 ++++++++++++++++++ .../src/app/user/user-routing.module.ts | 17 ++++-- .../src/app/user/user.component.html | 57 +++++++++++++++++-- .../sampleBlog/src/app/user/user.component.ts | 2 +- .../sampleBlog/src/app/user/user.module.ts | 8 ++- .../src/app/user/users/users.component.css | 0 .../src/app/user/users/users.component.html | 18 ++++++ .../app/user/users/users.component.spec.ts | 24 ++++++++ .../src/app/user/users/users.component.ts | 27 +++++++++ scully.config.js | 17 +++++- scully/routerPlugins/jsonRoutePlugin.ts | 2 +- scully/utils/defaultAction.ts | 2 +- scully/utils/httpGetJson.ts | 4 +- 20 files changed, 324 insertions(+), 19 deletions(-) create mode 100644 projects/sampleBlog/src/app/user/post/post.component.css create mode 100644 projects/sampleBlog/src/app/user/post/post.component.html create mode 100644 projects/sampleBlog/src/app/user/post/post.component.spec.ts create mode 100644 projects/sampleBlog/src/app/user/post/post.component.ts create mode 100644 projects/sampleBlog/src/app/user/posts/posts.component.css create mode 100644 projects/sampleBlog/src/app/user/posts/posts.component.html create mode 100644 projects/sampleBlog/src/app/user/posts/posts.component.spec.ts create mode 100644 projects/sampleBlog/src/app/user/posts/posts.component.ts create mode 100644 projects/sampleBlog/src/app/user/users/users.component.css create mode 100644 projects/sampleBlog/src/app/user/users/users.component.html create mode 100644 projects/sampleBlog/src/app/user/users/users.component.spec.ts create mode 100644 projects/sampleBlog/src/app/user/users/users.component.ts diff --git a/projects/sampleBlog/src/app/user/post/post.component.css b/projects/sampleBlog/src/app/user/post/post.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/projects/sampleBlog/src/app/user/post/post.component.html b/projects/sampleBlog/src/app/user/post/post.component.html new file mode 100644 index 000000000..73c65277f --- /dev/null +++ b/projects/sampleBlog/src/app/user/post/post.component.html @@ -0,0 +1,5 @@ +
+

{{ post.title }}

+ +

{{ post.body }}

+
diff --git a/projects/sampleBlog/src/app/user/post/post.component.spec.ts b/projects/sampleBlog/src/app/user/post/post.component.spec.ts new file mode 100644 index 000000000..ae955504a --- /dev/null +++ b/projects/sampleBlog/src/app/user/post/post.component.spec.ts @@ -0,0 +1,24 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; + +import {PostComponent} from './post.component'; + +describe('PostComponent', () => { + let component: PostComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PostComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/sampleBlog/src/app/user/post/post.component.ts b/projects/sampleBlog/src/app/user/post/post.component.ts new file mode 100644 index 000000000..6119ac5e7 --- /dev/null +++ b/projects/sampleBlog/src/app/user/post/post.component.ts @@ -0,0 +1,50 @@ +import {Component, OnInit} from '@angular/core'; +import {Observable, of} from 'rxjs'; +import {pluck, shareReplay, switchMap, catchError, tap, filter, map} from 'rxjs/operators'; +import {Post} from '../posts/posts.component'; +import {isScullyGenerated, TransferStateService} from '@scullyio/ng-lib'; +import {ActivatedRoute} from '@angular/router'; +import {HttpClient} from '@angular/common/http'; + +@Component({ + selector: 'app-post', + templateUrl: './post.component.html', + styleUrls: ['./post.component.css'], +}) +export class PostComponent implements OnInit { + postId$: Observable = this.route.params.pipe( + pluck('post'), + filter(val => ![undefined, null].includes(val)), + map(val => parseInt(val, 10)), + shareReplay(1) + ); + + apiPosts$ = this.postId$.pipe( + switchMap(id => + this.http.get(`https://jsonplaceholder.typicode.com/posts/${id}`).pipe( + catchError(() => + of({ + id, + title: 'not found', + } as Post) + ) + ) + ), + shareReplay(1) + ); + + // This is an example of using TransferState + post$ = isScullyGenerated() + ? this.transferState.getState('post') + : this.apiPosts$.pipe(tap(post => this.transferState.setState('post', post))); + + constructor( + private route: ActivatedRoute, + private http: HttpClient, + private transferState: TransferStateService + ) { + console.log('post inits'); + } + + ngOnInit() {} +} diff --git a/projects/sampleBlog/src/app/user/posts/posts.component.css b/projects/sampleBlog/src/app/user/posts/posts.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/projects/sampleBlog/src/app/user/posts/posts.component.html b/projects/sampleBlog/src/app/user/posts/posts.component.html new file mode 100644 index 000000000..a6c512bd5 --- /dev/null +++ b/projects/sampleBlog/src/app/user/posts/posts.component.html @@ -0,0 +1,8 @@ +

User posts

+
+ +
diff --git a/projects/sampleBlog/src/app/user/posts/posts.component.spec.ts b/projects/sampleBlog/src/app/user/posts/posts.component.spec.ts new file mode 100644 index 000000000..a64686c8d --- /dev/null +++ b/projects/sampleBlog/src/app/user/posts/posts.component.spec.ts @@ -0,0 +1,24 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; + +import {PostsComponent} from './posts.component'; + +describe('PostsComponent', () => { + let component: PostsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PostsComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PostsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/sampleBlog/src/app/user/posts/posts.component.ts b/projects/sampleBlog/src/app/user/posts/posts.component.ts new file mode 100644 index 000000000..0d014319b --- /dev/null +++ b/projects/sampleBlog/src/app/user/posts/posts.component.ts @@ -0,0 +1,54 @@ +import {HttpClient} from '@angular/common/http'; +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {isScullyGenerated, TransferStateService} from '@scullyio/ng-lib'; +import {Observable, of} from 'rxjs'; +import {catchError, filter, map, pluck, shareReplay, switchMap, tap} from 'rxjs/operators'; + +export interface Post { + userId: number; + id: number; + title: string; + body: string; +} + +@Component({ + selector: 'app-posts', + templateUrl: './posts.component.html', + styleUrls: ['./posts.component.css'], +}) +export class PostsComponent implements OnInit { + userId$: Observable = this.route.params.pipe( + pluck('userId'), + filter(val => ![undefined, null].includes(val)), + map(val => parseInt(val, 10)), + shareReplay(1) + ); + + apiPosts$ = this.userId$.pipe( + switchMap(id => + this.http.get(`https://jsonplaceholder.typicode.com/posts?userId=${id}`).pipe( + catchError(() => + of({ + id, + title: 'not found', + } as Post) + ) + ) + ), + shareReplay(1) + ); + + // This is an example of using TransferState + posts$ = isScullyGenerated() + ? this.transferState.getState('posts') + : this.apiPosts$.pipe(tap(posts => this.transferState.setState('posts', posts))); + + constructor( + private route: ActivatedRoute, + private http: HttpClient, + private transferState: TransferStateService + ) {} + + ngOnInit() {} +} diff --git a/projects/sampleBlog/src/app/user/user-routing.module.ts b/projects/sampleBlog/src/app/user/user-routing.module.ts index 057e8e8ea..4c4d15277 100644 --- a/projects/sampleBlog/src/app/user/user-routing.module.ts +++ b/projects/sampleBlog/src/app/user/user-routing.module.ts @@ -2,12 +2,21 @@ import {NgModule} from '@angular/core'; import {Routes, RouterModule} from '@angular/router'; import {UserComponent} from './user.component'; +import {UsersComponent} from './users/users.component'; +import {PostsComponent} from './posts/posts.component'; +import {PostComponent} from './post/post.component'; const routes: Routes = [ - {path: '', component: UserComponent}, - {path: ':userId', component: UserComponent}, - {path: ':userId/:friendCode', component: UserComponent}, - {path: ':userId/:posts/:comments', component: UserComponent}, + {path: '', component: UsersComponent}, + { + path: ':userId', + component: UserComponent, + children: [ + {path: '', component: PostsComponent, pathMatch: 'full'}, + {path: 'friend/:friendCode', component: UserComponent}, + {path: 'post/:post', component: PostComponent}, + ], + }, ]; @NgModule({ diff --git a/projects/sampleBlog/src/app/user/user.component.html b/projects/sampleBlog/src/app/user/user.component.html index 15bf442e6..45e2a9cdd 100644 --- a/projects/sampleBlog/src/app/user/user.component.html +++ b/projects/sampleBlog/src/app/user/user.component.html @@ -1,9 +1,54 @@ -
user works!
-
-

User Data ({{ userId$ | async }})

-
-    {{user$ | async | json}}
-  
+ +
+

User Data

+ +
+ +

{{ user.id }}

+ +

{{ user.name }}

+ +

{{ user.email }}

+ +

{{ user.company.name }}

+
+ + {{ user.company.catchPhrase }}
+ +
+ Loading ... +
+
Previous ({{ prev$ | async }}) Next ({{ next$ | async }}) + +
+
+ +
diff --git a/projects/sampleBlog/src/app/user/user.component.ts b/projects/sampleBlog/src/app/user/user.component.ts index eccb9f078..15e8aec84 100644 --- a/projects/sampleBlog/src/app/user/user.component.ts +++ b/projects/sampleBlog/src/app/user/user.component.ts @@ -36,7 +36,7 @@ export class UserComponent implements OnInit { // This is an example of using TransferState user$ = isScullyGenerated() - ? this.transferState.getState('user') + ? this.transferState.getState('user') : this.apiUser$.pipe(tap(user => this.transferState.setState('user', user))); constructor( diff --git a/projects/sampleBlog/src/app/user/user.module.ts b/projects/sampleBlog/src/app/user/user.module.ts index 0a367f058..92084bb1c 100644 --- a/projects/sampleBlog/src/app/user/user.module.ts +++ b/projects/sampleBlog/src/app/user/user.module.ts @@ -1,11 +1,13 @@ -import {NgModule} from '@angular/core'; import {CommonModule} from '@angular/common'; - +import {NgModule} from '@angular/core'; +import {PostComponent} from './post/post.component'; +import {PostsComponent} from './posts/posts.component'; import {UserRoutingModule} from './user-routing.module'; import {UserComponent} from './user.component'; +import {UsersComponent} from './users/users.component'; @NgModule({ - declarations: [UserComponent], + declarations: [UserComponent, UsersComponent, PostsComponent, PostComponent], imports: [CommonModule, UserRoutingModule], }) export class UserModule {} diff --git a/projects/sampleBlog/src/app/user/users/users.component.css b/projects/sampleBlog/src/app/user/users/users.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/projects/sampleBlog/src/app/user/users/users.component.html b/projects/sampleBlog/src/app/user/users/users.component.html new file mode 100644 index 000000000..4eb2e3c0c --- /dev/null +++ b/projects/sampleBlog/src/app/user/users/users.component.html @@ -0,0 +1,18 @@ +

Users

+ +
+ + + + + + + + + + + +
IdUsername
{{ user.id }} + {{ user.name }} +
+
diff --git a/projects/sampleBlog/src/app/user/users/users.component.spec.ts b/projects/sampleBlog/src/app/user/users/users.component.spec.ts new file mode 100644 index 000000000..554295d92 --- /dev/null +++ b/projects/sampleBlog/src/app/user/users/users.component.spec.ts @@ -0,0 +1,24 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; + +import {UsersComponent} from './users.component'; + +describe('UsersComponent', () => { + let component: UsersComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [UsersComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UsersComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/sampleBlog/src/app/user/users/users.component.ts b/projects/sampleBlog/src/app/user/users/users.component.ts new file mode 100644 index 000000000..827b43776 --- /dev/null +++ b/projects/sampleBlog/src/app/user/users/users.component.ts @@ -0,0 +1,27 @@ +import {HttpClient} from '@angular/common/http'; +import {Component, OnInit} from '@angular/core'; +import {isScullyGenerated, TransferStateService} from '@scullyio/ng-lib'; +import {of} from 'rxjs'; +import {catchError, shareReplay, tap} from 'rxjs/operators'; +import {User} from '../user.component'; + +@Component({ + selector: 'app-users', + templateUrl: './users.component.html', + styleUrls: ['./users.component.css'], +}) +export class UsersComponent implements OnInit { + apiUsers$ = this.http.get(`https://jsonplaceholder.typicode.com/users`).pipe( + catchError(() => of([] as User[])), + shareReplay(1) + ); + + // This is an example of using TransferState + users$ = isScullyGenerated() + ? this.transferState.getState('users') + : this.apiUsers$.pipe(tap(user => this.transferState.setState('users', user))); + + constructor(private http: HttpClient, private transferState: TransferStateService) {} + + ngOnInit() {} +} diff --git a/scully.config.js b/scully.config.js index e6d43f958..bbc40768d 100644 --- a/scully.config.js +++ b/scully.config.js @@ -9,7 +9,7 @@ exports.config = { /** outDir is where the static distribution files end up */ outDir: './dist/static', // hostName: '0.0.0.0', - extraRoutes: [''], + extraRoutes: ['', '/user/:userId/post/:post'], routes: { '/demo/:id': { type: 'extra', @@ -34,6 +34,21 @@ exports.config = { property: 'id', }, }, + '/user/:userId/post/:post': { + // Type is mandatory + type: 'json', + /** + * Every parameter in the route must exist here + */ + userId: { + url: 'https://jsonplaceholder.typicode.com/users', + property: 'id', + }, + post: { + url: 'https://jsonplaceholder.typicode.com/posts?userId=${userId}', + property: 'id', + }, + }, '/nouser/:userId/:friendCode': { // Type is mandatory type: 'json', diff --git a/scully/routerPlugins/jsonRoutePlugin.ts b/scully/routerPlugins/jsonRoutePlugin.ts index 2320bba5f..34547a377 100644 --- a/scully/routerPlugins/jsonRoutePlugin.ts +++ b/scully/routerPlugins/jsonRoutePlugin.ts @@ -22,7 +22,7 @@ export const jsonRoutePlugin = async (route: string, conf: RouteTypeJson): Promi /** helper to get the data, parses out the context, and the property */ const loadData = (param, context = {}): Promise => { /** us es-template lie string to construct the url */ - const url = renderTemplate(conf[param.part].url, context); + const url = renderTemplate(conf[param.part].url, context).trim(); return httpGetJson(url, { headers: conf[param.part].headers, }) diff --git a/scully/utils/defaultAction.ts b/scully/utils/defaultAction.ts index 4d39e5896..2af7005df 100644 --- a/scully/utils/defaultAction.ts +++ b/scully/utils/defaultAction.ts @@ -27,7 +27,7 @@ export const generateAll = async (config?: Partial) => { log('Pull in data to create additional routes.'); const handledRoutes = await addOptionalRoutes(unhandledRoutes); - await storeRoutes(handledRoutes); + // await storeRoutes(handledRoutes); /** launch the browser, its shared among renderers */ const browser = await launchedBrowser(); /** start handling each route, works in chunked parallel mode */ diff --git a/scully/utils/httpGetJson.ts b/scully/utils/httpGetJson.ts index 92322788f..53464bf77 100644 --- a/scully/utils/httpGetJson.ts +++ b/scully/utils/httpGetJson.ts @@ -11,12 +11,12 @@ export function httpGetJson( ) { const httpGet = url.toLowerCase().includes('https:') ? getHttps : get; return new Promise((resolve, reject) => { - const {pathname, hostname, port, protocol} = new URL(url); + const {pathname, hostname, port, protocol, search, hash} = new URL(url); const opt: RequestOptions = { protocol, hostname, port, - path: pathname, + path: pathname + search + hash, headers, }; httpGet(opt, res => {