diff --git a/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo-children-url/markdown-navigator-demo-children-url.component.html b/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo-children-url/markdown-navigator-demo-children-url.component.html
new file mode 100644
index 0000000000..bc011fe9a2
--- /dev/null
+++ b/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo-children-url/markdown-navigator-demo-children-url.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo-children-url/markdown-navigator-demo-children-url.component.scss b/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo-children-url/markdown-navigator-demo-children-url.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo-children-url/markdown-navigator-demo-children-url.component.ts b/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo-children-url/markdown-navigator-demo-children-url.component.ts
new file mode 100644
index 0000000000..53fa4d3cf0
--- /dev/null
+++ b/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo-children-url/markdown-navigator-demo-children-url.component.ts
@@ -0,0 +1,16 @@
+import { Component } from '@angular/core';
+import { IMarkdownNavigatorItem } from '@covalent/markdown-navigator';
+
+@Component({
+ selector: 'markdown-navigator-demo-children-url',
+ styleUrls: ['./markdown-navigator-demo-children-url.component.scss'],
+ templateUrl: './markdown-navigator-demo-children-url.component.html',
+})
+export class MarkdownNavigatorDemoChildrenUrlComponent {
+ items: IMarkdownNavigatorItem[] = [
+ {
+ title: '🔥',
+ childrenUrl: 'https://api.myjson.com/bins/aqnfk',
+ },
+ ];
+}
diff --git a/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo.component.html b/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo.component.html
index 581c76a8e1..8b92c3829e 100644
--- a/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo.component.html
+++ b/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo.component.html
@@ -9,3 +9,7 @@
+
+
+
+
diff --git a/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo.module.ts b/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo.module.ts
index e1d6573240..9079d56592 100644
--- a/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo.module.ts
+++ b/src/app/content/components/component-demos/markdown-navigator/demos/markdown-navigator-demo.module.ts
@@ -13,6 +13,7 @@ import {
} from './markdown-navigator-demo-footer/markdown-navigator-demo-footer.component';
import { MatListModule } from '@angular/material/list';
import { MarkdownNavigatorDemoEventsComponent } from './markdown-navigator-demo-events/markdown-navigator-demo-events.component';
+import { MarkdownNavigatorDemoChildrenUrlComponent } from './markdown-navigator-demo-children-url/markdown-navigator-demo-children-url.component';
@NgModule({
declarations: [
@@ -22,6 +23,7 @@ import { MarkdownNavigatorDemoEventsComponent } from './markdown-navigator-demo-
MarkdownNavigatorDemoFooterExampleAComponent,
MarkdownNavigatorDemoFooterExampleBComponent,
MarkdownNavigatorDemoEventsComponent,
+ MarkdownNavigatorDemoChildrenUrlComponent,
],
imports: [
DemoModule,
diff --git a/src/platform/markdown-navigator/README.md b/src/platform/markdown-navigator/README.md
index da41a813ea..495afc0eeb 100644
--- a/src/platform/markdown-navigator/README.md
+++ b/src/platform/markdown-navigator/README.md
@@ -33,6 +33,7 @@ interface IMarkdownNavigatorItem {
markdownString?: string; // raw markdown
anchor?: string;
children?: IMarkdownNavigatorItem[];
+ childrenUrl?: string;
description?: string;
icon?: string;
footer?: Type;
diff --git a/src/platform/markdown-navigator/markdown-navigator.component.spec.ts b/src/platform/markdown-navigator/markdown-navigator.component.spec.ts
index acf1c4ffef..095c5340df 100644
--- a/src/platform/markdown-navigator/markdown-navigator.component.spec.ts
+++ b/src/platform/markdown-navigator/markdown-navigator.component.spec.ts
@@ -10,6 +10,8 @@ import { By } from '@angular/platform-browser';
import { Component, DebugElement, Type } from '@angular/core';
import { CovalentMarkdownNavigatorModule } from './markdown-navigator.module';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { HttpClientTestingModule, HttpTestingController, TestRequest } from '@angular/common/http/testing';
+import { HttpClient } from '@angular/common/http';
const RAW_MARKDOWN_HEADING: string = 'Heading';
const RAW_MARKDOWN: string = `# ${RAW_MARKDOWN_HEADING}`;
@@ -79,6 +81,15 @@ const ITEMS_WITH_FOOTERS: IMarkdownNavigatorItem[] = [
},
];
+const CHILDREN_URL: string = 'https://samplechildrenurl.com';
+
+const ITEMS_WITH_CHILDREN_URL: IMarkdownNavigatorItem[] = [
+ {
+ title: 'Children url',
+ childrenUrl: CHILDREN_URL,
+ },
+];
+
export const DEEPLY_NESTED_TREE: IMarkdownNavigatorItem[] = [
{
title: 'A',
@@ -288,11 +299,17 @@ class TdMarkdownNavigatorTestComponent {
}
describe('MarkdownNavigatorComponent', () => {
+ let httpClient: HttpClient;
+ let httpTestingController: HttpTestingController;
+
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TdMarkdownNavigatorTestComponent],
- imports: [NoopAnimationsModule, CovalentMarkdownNavigatorModule],
+ imports: [NoopAnimationsModule, CovalentMarkdownNavigatorModule, HttpClientTestingModule],
}).compileComponents();
+
+ httpClient = TestBed.inject(HttpClient);
+ httpTestingController = TestBed.inject(HttpTestingController);
}));
it('should render empty state when an empty array is passed into items', async(
@@ -361,6 +378,42 @@ describe('MarkdownNavigatorComponent', () => {
}),
));
+ it('should fetch childrenUrl and render', async(
+ inject([], async () => {
+ const itemATitle: string = 'fetched item A';
+ const itemBTitle: string = 'fetched item B';
+
+ const testData: IMarkdownNavigatorItem[] = [{ title: itemATitle }, { title: itemBTitle }];
+ const fixture: ComponentFixture = TestBed.createComponent(
+ TdMarkdownNavigatorTestComponent,
+ );
+
+ fixture.componentInstance.items = ITEMS_WITH_CHILDREN_URL;
+ await wait(fixture);
+
+ const markdownNavigator: TdMarkdownNavigatorComponent = fixture.debugElement.query(
+ By.directive(TdMarkdownNavigatorComponent),
+ ).componentInstance;
+
+ expect(markdownNavigator.showMenu).toBeTruthy();
+ expect(markdownNavigator.showTdMarkdown).toBeFalsy();
+
+ getItem(fixture, 0).click();
+ const req: TestRequest = httpTestingController.expectOne(CHILDREN_URL);
+ req.flush(testData);
+
+ await wait(fixture);
+ await wait(fixture);
+
+ expect(markdownNavigator.showMenu).toBeTruthy();
+ expect(markdownNavigator.showTdMarkdown).toBeFalsy();
+ expect(getItem(fixture, 0).textContent).toContain(itemATitle);
+ expect(getItem(fixture, 1).textContent).toContain(itemBTitle);
+
+ httpTestingController.verify();
+ }),
+ ));
+
it('should render one url item from GitHub', async(
inject([], async () => {
const fixture: ComponentFixture = TestBed.createComponent(
diff --git a/src/platform/markdown-navigator/markdown-navigator.component.ts b/src/platform/markdown-navigator/markdown-navigator.component.ts
index 235c2c8269..649965e23a 100644
--- a/src/platform/markdown-navigator/markdown-navigator.component.ts
+++ b/src/platform/markdown-navigator/markdown-navigator.component.ts
@@ -11,9 +11,12 @@ import {
Type,
Output,
EventEmitter,
+ SecurityContext,
} from '@angular/core';
import { removeLeadingHash, isAnchorLink, TdMarkdownLoaderService } from '@covalent/markdown';
import { ITdFlavoredMarkdownButtonClickEvent } from '@covalent/flavored-markdown';
+import { DomSanitizer } from '@angular/platform-browser';
+import { HttpClient } from '@angular/common/http';
export interface IMarkdownNavigatorItem {
title?: string;
@@ -22,6 +25,7 @@ export interface IMarkdownNavigatorItem {
markdownString?: string; // raw markdown
anchor?: string;
children?: IMarkdownNavigatorItem[];
+ childrenUrl?: string;
description?: string;
icon?: string;
footer?: Type;
@@ -145,6 +149,8 @@ export class TdMarkdownNavigatorComponent implements OnChanges {
constructor(
private _markdownUrlLoaderService: TdMarkdownLoaderService,
private _changeDetectorRef: ChangeDetectorRef,
+ private _sanitizer: DomSanitizer,
+ private _http: HttpClient,
) {}
@HostListener('click', ['$event'])
@@ -245,9 +251,14 @@ export class TdMarkdownNavigatorComponent implements OnChanges {
}
}
+ hasChildrenOrChildrenUrl(item: IMarkdownNavigatorItem): boolean {
+ return (item.children && item.children.length > 0) || !!item.childrenUrl;
+ }
+
reset(): void {
+ this.loading = false;
// if single item and no children
- if (this.items && this.items.length === 1 && (!this.items[0].children || this.items[0].children.length === 0)) {
+ if (this.items && this.items.length === 1 && !this.hasChildrenOrChildrenUrl(this.items[0])) {
this.currentMenuItems = [];
this.currentMarkdownItem = this.items[0];
} else {
@@ -259,10 +270,11 @@ export class TdMarkdownNavigatorComponent implements OnChanges {
}
goBack(): void {
+ this.loading = false;
if (this.historyStack.length > 1) {
const parent: IMarkdownNavigatorItem = this.historyStack[this.historyStack.length - 2];
this.currentMarkdownItem = parent;
- this.currentMenuItems = parent.children;
+ this.setChildrenAsCurrentMenuItems(parent);
this.historyStack = this.historyStack.slice(0, -1);
} else {
// one level down just go to root
@@ -273,11 +285,42 @@ export class TdMarkdownNavigatorComponent implements OnChanges {
handleItemSelected(item: IMarkdownNavigatorItem): void {
this.historyStack = [...this.historyStack, item];
- this.currentMenuItems = item.children;
+ this.setChildrenAsCurrentMenuItems(item);
this.currentMarkdownItem = item;
this._changeDetectorRef.markForCheck();
}
+ async setChildrenAsCurrentMenuItems(item: IMarkdownNavigatorItem): Promise {
+ this.currentMenuItems = [];
+ this.loading = true;
+ this._changeDetectorRef.markForCheck();
+
+ const itemToVerifyWith: IMarkdownNavigatorItem = this.historyStack[0];
+ let children: IMarkdownNavigatorItem[] = [];
+ if (item.children) {
+ children = item.children;
+ } else if (item.childrenUrl) {
+ children = await this.loadChildrenUrl(item);
+ }
+ if (this.historyStack[0] === itemToVerifyWith) {
+ this.currentMenuItems = children;
+ }
+
+ this.loading = false;
+ this._changeDetectorRef.markForCheck();
+ }
+
+ async loadChildrenUrl(item: IMarkdownNavigatorItem): Promise {
+ const sanitizedUrl: string = this._sanitizer.sanitize(SecurityContext.URL, item.childrenUrl);
+ try {
+ return await this._http
+ .get(sanitizedUrl, { ...item.httpOptions })
+ .toPromise();
+ } catch {
+ return [];
+ }
+ }
+
getTitle(item: IMarkdownNavigatorItem): string {
if (item) {
return (