-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.ts
More file actions
122 lines (112 loc) · 3.13 KB
/
main.ts
File metadata and controls
122 lines (112 loc) · 3.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// deno-lint-ignore-file no-import-prefix
import "@angular/compiler";
import { HttpClient, httpResource } from "@angular/common/http";
import {
Component,
computed,
inject,
Injectable,
resource,
type Signal,
signal,
} from "@angular/core";
import { Field, form } from "@angular/forms/signals";
import { bootstrapApplication } from "@angular/platform-browser";
import type {
Post,
User,
} from "https://esm.sh/*@untypeable/jsonplaceholder@1.0.2";
import { firstValueFrom, fromEvent, takeUntil } from "rxjs";
const urlBase = "https://jsonplaceholder.typicode.com";
@Injectable({ providedIn: "root" })
class UserService {
getUsers() {
return httpResource<User[]>(() => `${urlBase}/users`);
}
}
@Injectable({ providedIn: "root" })
class PostService {
getPosts(userIdSignal: Signal<number | undefined>) {
return httpResource<Post[]>(() => {
const userId = userIdSignal();
if (userId == undefined) return undefined;
return {
url: `${urlBase}/posts`,
params: { userId },
};
});
}
}
@Injectable({ providedIn: "root" })
class ReadmeService {
getReadmeHTML() {
const httpClient = inject(HttpClient);
return resource({
loader: async ({ abortSignal }) => {
const [{ marked }, readmeMarkdown] = await Promise.all([
import("https://esm.sh/*marked@17.0.0"),
firstValueFrom(
httpClient
.get("./README.md", { responseType: "text" })
.pipe(takeUntil(fromEvent(abortSignal, "abort"))),
),
]);
return marked.parse(readmeMarkdown);
},
});
}
}
@Component({
selector: "app-root",
imports: [Field],
template: `
<section [innerHTML]="readmeHTML.value()"></section>
@if (users.hasValue()) {
<label>
Select User:
<select [field]="form.selectedUserId">
<option hidden selected></option>
@for (user of users.value(); track user.id) {
<option value="{{ user.id }}">
@{{ user.username }}: {{ user.name }}
</option>
}
</select>
</label>
} @else if (users.isLoading()) {
<p>Loading Users...</p>
}
@if (posts.hasValue()) {
<ul>
@for (post of posts.value(); track post.id) {
<li>{{ post.title }}</li>
}
</ul>
} @else if (posts.isLoading()) {
<p>Loading Posts...</p>
} @else if (users.hasValue()) {
<p>Select User to view posts</p>
}
<p>
Data Source:
<a href="https://jsonplaceholder.typicode.com/" target="_blank">
JSONPlaceholder
</a>
</p>
`,
})
class App {
readonly #formState = signal({ selectedUserId: "" });
readonly #selectedUserId = computed(() => {
const userId = this.#formState().selectedUserId;
if (userId === "") return undefined;
return +userId;
});
protected readonly form = form(this.#formState);
protected readonly users = inject(UserService).getUsers();
protected readonly posts = inject(PostService).getPosts(
this.#selectedUserId,
);
protected readonly readmeHTML = inject(ReadmeService).getReadmeHTML();
}
await bootstrapApplication(App);