/
noutlet.component.tsx
75 lines (69 loc) · 2.58 KB
/
noutlet.component.tsx
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
import { Properties } from '../../decorators/properties.decorator';
import { BaseComponent } from '../base.component';
import { LifeCycle } from '../lifecycle.enum';
import { uuidv4 } from '../../code/utils';
import { Events } from '../../decorators';
/**
* This component allows to create an outlet, that has no vivible DOM node.
* A comment node is being replaced by the actual node delivered from router.
* That's an option onw might need in case of weak CSS that changes its behavior if a DIV element or other regular HTML element appears.
*
* In the render method add the element as a regular component.
*
* This component fires an event, `mutation`, that indicates the content has been changed by the router infrastructure.
*
* `<n-outlet></n-outlet>`
*
* As with any other outlet you can add a name by using the *name* parameter. That is an observed attribute.
*
* `<n-outlet name="target"></n-outlet>`
*
* @event mutation Custom event that has a {@link MutationRecord} in the detail property.
*
*/
@Properties<{ name?: string }>({ name: '' })
@Events(['mutation'])
export class NOutletComponent extends BaseComponent<{ name: '' }> {
constructor() {
super();
}
private observer: MutationObserver;
private outletId: string;
render() {
this.outletId = uuidv4();
return `<!--OUTLET n-router-outlet=${this.data.name} id=${this.outletId} -->`;
}
lifeCycle(state: LifeCycle) {
if (state === LifeCycle.Load) {
const tw = document.createTreeWalker(this, NodeFilter.SHOW_COMMENT, null, null);
let watchTarget: Comment = null;
while (watchTarget = tw.nextNode() as Comment) {
if (watchTarget.data.indexOf('OUTLET') === 0) {
const targetContainer = watchTarget.parentElement;
this.observer = new MutationObserver((mutations) => {
// a router has added an element and removed the comment
mutations.forEach((mutation) => {
if (mutation.target === this) {
this.dispatch('mutation', {
bubbles: true,
cancelable: false,
detail: mutation
});
}
});
// let's conserve this information and re-add
});
this.observer.observe(targetContainer, {
attributes: false,
childList: true,
characterData: true,
subtree: true
});
}
}
}
if (state === LifeCycle.Disconnect && this.observer) {
this.observer.disconnect();
}
}
}