Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
5 changes: 5 additions & 0 deletions projects/sampleBlog/src/app/user/post/post.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<section *ngIf="post$ | async as post">
<h4>{{ post.title }}</h4>

<p>{{ post.body }}</p>
</section>
24 changes: 24 additions & 0 deletions projects/sampleBlog/src/app/user/post/post.component.spec.ts
Original file line number Diff line number Diff line change
@@ -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<PostComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [PostComponent],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(PostComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
50 changes: 50 additions & 0 deletions projects/sampleBlog/src/app/user/post/post.component.ts
Original file line number Diff line number Diff line change
@@ -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<number> = 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<Post>(`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>('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() {}
}
Empty file.
8 changes: 8 additions & 0 deletions projects/sampleBlog/src/app/user/posts/posts.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<h4>User posts</h4>
<section *ngIf="posts$ | async as posts">
<ul>
<li *ngFor="let post of posts">
<a [routerLink]="['post', post.id]">{{ post.title }}</a>
</li>
</ul>
</section>
24 changes: 24 additions & 0 deletions projects/sampleBlog/src/app/user/posts/posts.component.spec.ts
Original file line number Diff line number Diff line change
@@ -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<PostsComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [PostsComponent],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(PostsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
54 changes: 54 additions & 0 deletions projects/sampleBlog/src/app/user/posts/posts.component.ts
Original file line number Diff line number Diff line change
@@ -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<number> = 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<Post[]>(`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() {}
}
17 changes: 13 additions & 4 deletions projects/sampleBlog/src/app/user/user-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
57 changes: 51 additions & 6 deletions projects/sampleBlog/src/app/user/user.component.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,54 @@
<section>user works!</section>
<section>
<h4>User Data ({{ userId$ | async }})</h4>
<pre>
<code>{{user$ | async | json}}</code>
</pre>
<style>
#user {
display: grid;
grid-template-columns: 10rem 1fr;
grid-template-rows: repeat(4, 1rem);
}

#user .label {
text-align: right;
}

#user .label::after {
content: ':';
}

strong {
display: inline-block;
padding: 5px;
border-radius: 5px;
background-color: #afafaf;
margin: 10px;
}
#sub {
padding: 20px;
}
</style>
<section *ngIf="user$ | async as user; else loading">
<h4>User Data</h4>

<section id="user">
<label>Id</label>
<p>{{ user.id }}</p>
<label>Name</label>
<p>{{ user.name }}</p>
<label>email</label>
<p>{{ user.email }}</p>
<label>company</label>
<p>{{ user.company.name }}</p>
</section>

<strong>{{ user.company.catchPhrase }}</strong>
</section>
<ng-template #loading>
<section>
Loading ...
</section>
</ng-template>
<a [routerLink]="['/user/' + (prev$ | async)]">Previous ({{ prev$ | async }})</a>
<a [routerLink]="['/user/' + (next$ | async)]">Next ({{ next$ | async }})</a>

<hr />
<section id="sub">
<router-outlet></router-outlet>
</section>
2 changes: 1 addition & 1 deletion projects/sampleBlog/src/app/user/user.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>('user')
: this.apiUser$.pipe(tap(user => this.transferState.setState('user', user)));

constructor(
Expand Down
8 changes: 5 additions & 3 deletions projects/sampleBlog/src/app/user/user.module.ts
Original file line number Diff line number Diff line change
@@ -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 {}
Empty file.
18 changes: 18 additions & 0 deletions projects/sampleBlog/src/app/user/users/users.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<h1>Users</h1>

<section *ngIf="users$ | async as users">
<table>
<thead>
<th>Id</th>
<th>Username</th>
</thead>
<tbody>
<tr *ngFor="let user of users">
<td>{{ user.id }}</td>
<td>
<a [routerLink]="user.id"> {{ user.name }}</a>
</td>
</tr>
</tbody>
</table>
</section>
24 changes: 24 additions & 0 deletions projects/sampleBlog/src/app/user/users/users.component.spec.ts
Original file line number Diff line number Diff line change
@@ -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<UsersComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [UsersComponent],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(UsersComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
27 changes: 27 additions & 0 deletions projects/sampleBlog/src/app/user/users/users.component.ts
Original file line number Diff line number Diff line change
@@ -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<User[]>(`https://jsonplaceholder.typicode.com/users`).pipe(
catchError(() => of([] as User[])),
shareReplay(1)
);

// This is an example of using TransferState
users$ = isScullyGenerated()
? this.transferState.getState<User[]>('users')
: this.apiUsers$.pipe(tap(user => this.transferState.setState('users', user)));

constructor(private http: HttpClient, private transferState: TransferStateService) {}

ngOnInit() {}
}
17 changes: 16 additions & 1 deletion scully.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
projectName: 'sampleBlog',
routes: {
'/demo/:id': {
Expand All @@ -35,6 +35,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',
Expand Down
2 changes: 1 addition & 1 deletion scully/routerPlugins/jsonRoutePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<any[]> => {
/** 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,
})
Expand Down
Loading