Skip to content
This repository was archived by the owner on Nov 6, 2025. It is now read-only.

Commit aacf020

Browse files
authored
Merge pull request #2146 from enkelmedia/routed-modal-issue
Fixes with `umb-route-slot` inside routed modal
2 parents 77800ef + 3cf9fc8 commit aacf020

File tree

12 files changed

+314
-7
lines changed

12 files changed

+314
-7
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { css, html, LitElement, customElement, state } from '@umbraco-cms/backoffice/external/lit';
2+
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
3+
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
4+
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
5+
6+
@customElement('umb-dashboard')
7+
export class UmbDashboardElement extends UmbElementMixin(LitElement) {
8+
@state()
9+
private _routes: UmbRoute[] = [
10+
{
11+
path: `/tab1`,
12+
component: () => import('./tabs/tab1.element.js'),
13+
},
14+
{
15+
path: `/tab2`,
16+
component: () => import('./tabs/tab2.element.js'),
17+
},
18+
{
19+
path: '',
20+
redirectTo: 'tab1',
21+
},
22+
];
23+
24+
override render() {
25+
return html`
26+
<div>
27+
Dashboard 1
28+
<ul>
29+
<li><a href="section/content/dashboard/example/tab1">Tab 1</a></li>
30+
<li><a href="section/content/dashboard/example/tab2">Tab 2 (with modal)</a></li>
31+
</ul>
32+
<hr />
33+
<umb-router-slot .routes=${this._routes}></umb-router-slot>
34+
</div>
35+
`;
36+
}
37+
38+
static override styles = [UmbTextStyles, css``];
39+
}
40+
41+
export default UmbDashboardElement;
42+
43+
declare global {
44+
interface HTMLElementTagNameMap {
45+
'umb-dashboard': UmbDashboardElement;
46+
}
47+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { css, html, LitElement, customElement } from '@umbraco-cms/backoffice/external/lit';
2+
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
3+
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
4+
5+
@customElement('umb-dashboard2')
6+
export class UmbDashboard2Element extends UmbElementMixin(LitElement) {
7+
constructor() {
8+
super();
9+
}
10+
11+
override render() {
12+
return html`
13+
<div>
14+
<h2>Link to modal route</h2>
15+
<p>
16+
This page only shows how to link to the routed modal that is placed on a tab on the "Modal Dashboard".
17+
Clicking this link will not load the slots inside the modal, however, going to the "Modal Dashboard", clicking
18+
on tab 2 and opening the modal from there will work.
19+
</p>
20+
<a href="section/content/dashboard/example/tab2/modal/example-routed-modal/view/abc123/">Open Modal Route</a>
21+
</div>
22+
`;
23+
}
24+
25+
static override styles = [UmbTextStyles, css``];
26+
}
27+
28+
export default UmbDashboard2Element;
29+
30+
declare global {
31+
interface HTMLElementTagNameMap {
32+
'umb-dashboard2': UmbDashboard2Element;
33+
}
34+
}

examples/modal-routed/index.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type { ManifestDashboard, ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
2+
3+
// const section : ManifestSection = {
4+
// type: "section",
5+
// alias: 'demo.section',
6+
// name: "Demo Section",
7+
// meta: {
8+
// label: "Demo",
9+
// pathname: "demo"
10+
// }
11+
// }
12+
13+
const dashboard: ManifestDashboard = {
14+
type: 'dashboard',
15+
name: 'Example Modal Dashboard',
16+
alias: 'example.dashboard.dataset',
17+
element: () => import('./dashboard.element.js'),
18+
weight: 15000,
19+
meta: {
20+
label: 'Modal Dashboard',
21+
pathname: 'example',
22+
},
23+
};
24+
25+
const dashboard2: ManifestDashboard = {
26+
type: 'dashboard',
27+
name: 'Example Modal Dashboard2',
28+
alias: 'example.dashboard.dataset2',
29+
element: () => import('./dashboard2.element.js'),
30+
weight: 15001,
31+
meta: {
32+
label: 'Link Dashboard',
33+
pathname: 'example-2',
34+
},
35+
};
36+
37+
const modal: ManifestModal = {
38+
type: 'modal',
39+
name: 'Example Modal',
40+
alias: 'example.routed.modal',
41+
element: () => import('./modal/example-modal.element.js'),
42+
};
43+
44+
export const manifests = [dashboard, dashboard2, modal];
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
2+
3+
export type Data = object;
4+
export type ModalValue = object;
5+
6+
export const EXAMPLE_ROUTED_MODAL = new UmbModalToken<Data, ModalValue>(
7+
'example.routed.modal', // this needs to match the alias of the modal registered in manifest.ts
8+
{
9+
modal: {
10+
type: 'dialog',
11+
},
12+
},
13+
);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
2+
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
3+
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
4+
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
5+
6+
@customElement('umb-example-modal')
7+
export class UmbExampleModal extends UmbModalBaseElement {
8+
@state()
9+
private _routes: UmbRoute[] = [
10+
{
11+
path: `modalOverview`,
12+
component: () => import('./steps/example-modal-step1.element.js'),
13+
},
14+
{
15+
path: `details`,
16+
component: () => import('./steps/example-modal-step2.element.js'),
17+
},
18+
{
19+
path: '',
20+
redirectTo: 'modalOverview',
21+
},
22+
];
23+
24+
override render() {
25+
return html`
26+
<div>
27+
umb-example modal element
28+
<hr />
29+
<umb-router-slot .routes=${this._routes}></umb-router-slot>
30+
</div>
31+
`;
32+
}
33+
34+
static override styles = [UmbTextStyles, css``];
35+
}
36+
37+
export default UmbExampleModal;
38+
39+
declare global {
40+
interface HTMLElementTagNameMap {
41+
'umb-example-modal': UmbExampleModal;
42+
}
43+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
2+
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
3+
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
4+
5+
@customElement('umb-example-modal-step1')
6+
export class UmbExampleModalStep1 extends UmbModalBaseElement {
7+
override render() {
8+
return html` <div>example modal step1</div> `;
9+
}
10+
11+
static override styles = [UmbTextStyles, css``];
12+
}
13+
14+
export default UmbExampleModalStep1;
15+
16+
declare global {
17+
interface HTMLElementTagNameMap {
18+
'umb-example-modal-step1': UmbExampleModalStep1;
19+
}
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { html, customElement } from '@umbraco-cms/backoffice/external/lit';
2+
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
3+
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
4+
5+
@customElement('umb-example-modal-step2')
6+
export class UmbExampleModalStep2 extends UmbModalBaseElement {
7+
override render() {
8+
return html` <div>example modal step2</div> `;
9+
}
10+
11+
static override styles = [UmbTextStyles];
12+
}
13+
14+
export default UmbExampleModalStep2;
15+
16+
declare global {
17+
interface HTMLElementTagNameMap {
18+
'umb-example-modal-step2': UmbExampleModalStep2;
19+
}
20+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { css, html, LitElement, customElement, state } from '@umbraco-cms/backoffice/external/lit';
2+
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
3+
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
4+
5+
@customElement('umb-dashboard-tab1')
6+
export class UmbDashboardTab1Element extends UmbElementMixin(LitElement) {
7+
@state()
8+
_editLinkPath?: string;
9+
10+
constructor() {
11+
super();
12+
}
13+
14+
override render() {
15+
return html`
16+
<div>
17+
<h2>tab 1</h2>
18+
</div>
19+
`;
20+
}
21+
22+
static override styles = [UmbTextStyles, css``];
23+
}
24+
25+
export default UmbDashboardTab1Element;
26+
27+
declare global {
28+
interface UmbDashboardTab1Element {
29+
'umb-dashboard-tab1': UmbDashboardTab1Element;
30+
}
31+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { EXAMPLE_ROUTED_MODAL } from '../modal/example-modal-token.js';
2+
import { css, html, LitElement, customElement, state } from '@umbraco-cms/backoffice/external/lit';
3+
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
4+
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
5+
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
6+
7+
@customElement('umb-dashboard-tab2')
8+
export class UmbDashboardTab2Element extends UmbElementMixin(LitElement) {
9+
#workspaceModal?: UmbModalRouteRegistrationController<
10+
typeof EXAMPLE_ROUTED_MODAL.DATA,
11+
typeof EXAMPLE_ROUTED_MODAL.VALUE
12+
>;
13+
14+
@state()
15+
_editLinkPath?: string;
16+
17+
constructor() {
18+
super();
19+
20+
// Using workspace modal context
21+
this.#workspaceModal?.destroy();
22+
this.#workspaceModal = new UmbModalRouteRegistrationController(this, EXAMPLE_ROUTED_MODAL)
23+
.addAdditionalPath('view/:entityKey')
24+
.onSetup(() => {
25+
return {
26+
data: {},
27+
value: {},
28+
};
29+
})
30+
.observeRouteBuilder((routeBuilder) => {
31+
this._editLinkPath = routeBuilder({ entityKey: 'abc123' });
32+
});
33+
}
34+
35+
override render() {
36+
return html`
37+
<div>
38+
<h2>tab 2</h2>
39+
<p>This element hosts the UmbModalRouteRegistrationController</p>
40+
41+
<a href=${this._editLinkPath ?? ''}>Open modal</a>
42+
</div>
43+
`;
44+
}
45+
46+
static override styles = [UmbTextStyles, css``];
47+
}
48+
49+
export default UmbDashboardTab2Element;
50+
51+
declare global {
52+
interface UmbDashboardTab2Element {
53+
'umb-dashboard-tab2': UmbDashboardTab2Element;
54+
}
55+
}

src/external/router-slot/router-slot.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,11 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
162162
this._setParent(null);
163163
}
164164
}
165-
if (this.parent && this.parent.match !== null && this.match === null) {
165+
if (this.parent) {
166166
requestAnimationFrame(() => {
167-
this.render();
167+
if (this.parent && this.parent.match !== null && this.match === null) {
168+
this.render();
169+
}
168170
});
169171
}
170172
}

0 commit comments

Comments
 (0)