Skip to content

Commit 3b4a6b3

Browse files
feat(pos-switch): use observeTypes
1 parent 2623ec9 commit 3b4a6b3

File tree

3 files changed

+97
-60
lines changed

3 files changed

+97
-60
lines changed

elements/src/components/pos-switch/pos-switch.integration.spec.tsx

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,19 @@ import { PosLabel } from '../pos-label/pos-label';
66
import { PosSwitch } from './pos-switch';
77
import { PosResource } from '../pos-resource/pos-resource';
88
import { when } from 'jest-when';
9-
import { Thing } from '@pod-os/core';
9+
import { RdfType, Thing } from '@pod-os/core';
10+
import { Subject } from 'rxjs';
1011

1112
describe('pos-switch', () => {
12-
it('renders template based on properties of resource', async () => {
13+
it('renders template based on properties of resource, reactively', async () => {
1314
const os = mockPodOS();
15+
const observedTypes$ = new Subject<RdfType[]>();
1416
when(os.store.get)
1517
.calledWith('https://resource.test')
1618
.mockReturnValue({
1719
uri: 'https://resource.test',
1820
label: () => 'Recipe 1',
19-
types: () => [
20-
{
21-
label: 'Recipe',
22-
uri: 'http://schema.org/Recipe',
23-
},
24-
],
21+
observeTypes: () => observedTypes$,
2522
} as unknown as Thing);
2623
const page = await newSpecPage({
2724
components: [PosApp, PosCase, PosLabel, PosSwitch, PosResource],
@@ -39,6 +36,9 @@ describe('pos-switch', () => {
3936
<pos-case else if-typeof="http://schema.org/Recipe">
4037
<template>Will not render as else is specified</template>
4138
</pos-case>
39+
<pos-case if-typeof="http://schema.org/Thing">
40+
<template>Also a Thing</template>
41+
</pos-case>
4242
<pos-case else>
4343
<template>Will not render as previous conditions are satisfied</template>
4444
</pos-case>
@@ -47,6 +47,26 @@ describe('pos-switch', () => {
4747
</pos-app>`,
4848
});
4949
expect((os.fetch as jest.Mock).mock.calls).toHaveLength(0);
50+
expect(page.root?.innerText).toEqualText('');
51+
observedTypes$.next([
52+
{
53+
label: 'Recipe',
54+
uri: 'http://schema.org/Recipe',
55+
},
56+
]);
57+
await page.waitForChanges();
5058
expect(page.root?.innerText).toEqualText('Recipe 1');
59+
observedTypes$.next([
60+
{
61+
label: 'Recipe',
62+
uri: 'http://schema.org/Recipe',
63+
},
64+
{
65+
label: 'Thing',
66+
uri: 'http://schema.org/Thing',
67+
},
68+
]);
69+
await page.waitForChanges();
70+
expect(page.root?.innerText).toEqualText('Recipe 1\nAlso a Thing');
5171
});
5272
});

elements/src/components/pos-switch/pos-switch.spec.tsx

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { newSpecPage } from '@stencil/core/testing';
22
import { PosSwitch } from './pos-switch';
33
import { when } from 'jest-when';
4+
import { RdfType, Thing } from '@pod-os/core';
5+
import { Subject } from 'rxjs';
46

57
describe('pos-switch', () => {
68
it('contains only templates initially', async () => {
@@ -35,8 +37,6 @@ describe('pos-switch', () => {
3537
</pos-case>
3638
</pos-switch>`,
3739
});
38-
await page.rootInstance.receiveResource({ types: () => [] });
39-
await page.waitForChanges();
4040
expect(page.rootInstance.caseElements.length).toEqual(2);
4141
expect(page.rootInstance.caseElements[0].getAttribute('if-typeof')).toEqual('http://schema.org/Recipe');
4242
expect(page.rootInstance.caseElements[1].getAttribute('if-typeof')).toEqual('http://schema.org/Video');
@@ -54,8 +54,6 @@ describe('pos-switch', () => {
5454
</pos-case>
5555
</pos-switch>`,
5656
});
57-
await page.rootInstance.receiveResource({ types: () => [] });
58-
await page.waitForChanges();
5957
expect(page.rootInstance.caseElements.length).toEqual(1);
6058
expect(page.rootInstance.caseElements[0].getAttribute('if-typeof')).toEqual('http://schema.org/Recipe');
6159
});
@@ -65,15 +63,11 @@ describe('pos-switch', () => {
6563
components: [PosSwitch],
6664
html: `<pos-switch></pos-switch>`,
6765
});
68-
await page.rootInstance.receiveResource({});
69-
await page.waitForChanges();
70-
7166
const el: HTMLElement = page.root as unknown as HTMLElement;
72-
7367
expect(el.textContent).toEqual('No pos-case elements found');
7468
});
7569

76-
it('renders matching condition templates', async () => {
70+
it('renders matching condition templates, reactively', async () => {
7771
const page = await newSpecPage({
7872
components: [PosSwitch],
7973
html: `
@@ -95,14 +89,17 @@ describe('pos-switch', () => {
9589
</pos-case>
9690
</pos-switch>`,
9791
});
98-
await page.rootInstance.receiveResource({
99-
types: () => [
100-
{
101-
label: 'Recipe',
102-
uri: 'http://schema.org/Recipe',
103-
},
104-
],
105-
});
92+
const observedTypes$ = new Subject<RdfType[]>();
93+
const thing = {
94+
observeTypes: () => observedTypes$,
95+
} as unknown as Thing;
96+
page.rootInstance.receiveResource(thing);
97+
observedTypes$.next([
98+
{
99+
label: 'Recipe',
100+
uri: 'http://schema.org/Recipe',
101+
},
102+
]);
106103
await page.waitForChanges();
107104
expect(page.root?.innerHTML).toEqualHtml(`
108105
<div>Recipe 1</div>
@@ -121,14 +118,17 @@ describe('pos-switch', () => {
121118
<pos-case else><template><div>No matches</div></template></pos-case>
122119
</pos-switch>`,
123120
});
124-
await page.rootInstance.receiveResource({
125-
types: () => [
126-
{
127-
label: 'Recipe',
128-
uri: 'http://schema.org/Recipe',
129-
},
130-
],
131-
});
121+
const observedTypes$ = new Subject<RdfType[]>();
122+
const thing = {
123+
observeTypes: () => observedTypes$,
124+
} as unknown as Thing;
125+
page.rootInstance.receiveResource(thing);
126+
observedTypes$.next([
127+
{
128+
label: 'Recipe',
129+
uri: 'http://schema.org/Recipe',
130+
},
131+
]);
132132
await page.waitForChanges();
133133
expect(page.root?.innerHTML).toEqualHtml(`
134134
<div>Recipe 1</div>
@@ -144,14 +144,17 @@ describe('pos-switch', () => {
144144
<pos-case else><template><div>No matches</div></template></pos-case>
145145
</pos-switch>`,
146146
});
147-
await page.rootInstance.receiveResource({
148-
types: () => [
149-
{
150-
label: 'Recipe',
151-
uri: 'http://schema.org/Recipe',
152-
},
153-
],
154-
});
147+
const observedTypes$ = new Subject<RdfType[]>();
148+
const thing = {
149+
observeTypes: () => observedTypes$,
150+
} as unknown as Thing;
151+
page.rootInstance.receiveResource(thing);
152+
observedTypes$.next([
153+
{
154+
label: 'Recipe',
155+
uri: 'http://schema.org/Recipe',
156+
},
157+
]);
155158
await page.waitForChanges();
156159
expect(page.root?.innerHTML).toEqualHtml(`
157160
<div>No matches</div>
@@ -166,14 +169,17 @@ describe('pos-switch', () => {
166169
<pos-case not if-typeof="http://schema.org/Video"><template><div>Not a Video</div></template></pos-case>
167170
</pos-switch>`,
168171
});
169-
await page.rootInstance.receiveResource({
170-
types: () => [
171-
{
172-
label: 'Recipe',
173-
uri: 'http://schema.org/Recipe',
174-
},
175-
],
176-
});
172+
const observedTypes$ = new Subject<RdfType[]>();
173+
const thing = {
174+
observeTypes: () => observedTypes$,
175+
} as unknown as Thing;
176+
page.rootInstance.receiveResource(thing);
177+
observedTypes$.next([
178+
{
179+
label: 'Recipe',
180+
uri: 'http://schema.org/Recipe',
181+
},
182+
]);
177183
await page.waitForChanges();
178184
expect(page.root?.innerHTML).toEqualHtml(`
179185
<div>Not a Video</div>

elements/src/components/pos-switch/pos-switch.tsx

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { Thing } from '@pod-os/core';
1+
import { RdfType, Thing } from '@pod-os/core';
22
import { Component, Element, Event, h, Host, State } from '@stencil/core';
33
import { ResourceAware, ResourceEventEmitter, subscribeResource } from '../events/ResourceAware';
4+
import { firstValueFrom, Subject, takeUntil } from 'rxjs';
45

56
/**
67
* Selects a child template to render based on properties of the subject resource, usually defined by an ancestor `pos-resource` element.
@@ -15,30 +16,28 @@ export class PosSwitch implements ResourceAware {
1516
@Element() host: HTMLElement;
1617
@State() error: string = null;
1718
@State() resource: Thing;
18-
@State() caseElements: NodeListOf<HTMLPosCaseElement>;
19-
@State() templateString: string;
19+
@State() caseElements: HTMLPosCaseElement[];
20+
@State() types: RdfType[];
21+
22+
private readonly disconnected$ = new Subject<void>();
2023

2124
@Event({ eventName: 'pod-os:resource' })
2225
subscribeResource: ResourceEventEmitter;
2326

2427
componentWillLoad() {
25-
subscribeResource(this);
26-
2728
const caseElements = this.host.querySelectorAll('pos-case');
2829
if (caseElements.length == 0) {
2930
this.error = 'No pos-case elements found';
3031
} else {
31-
this.caseElements = caseElements;
32+
this.caseElements = Array.from(caseElements);
33+
subscribeResource(this);
3234
}
3335
}
3436

3537
test(caseElement): boolean {
3638
let state = null;
3739
if (caseElement.getAttribute('if-typeof') !== null) {
38-
state = this.resource
39-
.types()
40-
.map(x => x.uri)
41-
.includes(caseElement.getAttribute('if-typeof'));
40+
state = this.types.map(x => x.uri).includes(caseElement.getAttribute('if-typeof'));
4241
}
4342
if (caseElement.getAttribute('if-property') !== null) {
4443
const relations = this.resource.relations(caseElement.getAttribute('if-property'));
@@ -54,7 +53,14 @@ export class PosSwitch implements ResourceAware {
5453
return state;
5554
}
5655

57-
receiveResource = (resource: Thing) => {
56+
receiveResource = async (resource: Thing) => {
57+
if (this.caseElements.some(caseElement => caseElement.hasAttribute('if-typeof'))) {
58+
const observeTypes = resource.observeTypes().pipe(takeUntil(this.disconnected$));
59+
observeTypes.subscribe(types => {
60+
this.types = types;
61+
});
62+
await firstValueFrom(observeTypes);
63+
}
5864
this.resource = resource;
5965
};
6066

@@ -81,4 +87,9 @@ export class PosSwitch implements ResourceAware {
8187
const activeElementsContent = activeElements.map(el => el.querySelector('template').innerHTML).join('\n');
8288
return <Host innerHTML={activeElementsContent}></Host>;
8389
}
90+
91+
disconnectedCallback() {
92+
this.disconnected$.next();
93+
this.disconnected$.unsubscribe();
94+
}
8495
}

0 commit comments

Comments
 (0)