fix(aio): allow setting live-example title from content (#23960)

Previously, it was possible to set the live-example title as content in
the `<live-example>` element. This relied on our custom loader
functionality that extracted the content from the DOM element before
passing it to the Angular compiler and stored it on a property for later
retrieval.
Since we switched to custom elements (and got rid of the custom loader),
the property is no longer populated with the contents. As a result, many
live examples show the default title ("live example") instead of the one
specified as content.

This commit fixes it by projecting the content into an invisible node
for later retrieval  (similar to what we do in other components, such as
the `CodeExampleComponent`).

PR Close #23960
This commit is contained in:
George Kalpakas 2018-05-17 13:13:47 +03:00 committed by Matias Niemelä
parent a7b07defe1
commit 41fea84957
3 changed files with 18 additions and 17 deletions

View File

@ -1,3 +1,6 @@
<!-- Content projection is used to get the content HTML provided to the component. -->
<span #content style="display: none"><ng-content></ng-content></span>
<span [ngSwitch]="mode">
<span *ngSwitchCase="'disabled'">{{title}} <em>(not available on this device)</em></span>
<span *ngSwitchCase="'embedded'">

View File

@ -12,7 +12,6 @@ describe('LiveExampleComponent', () => {
let liveExampleComponent: LiveExampleComponent;
let fixture: ComponentFixture<HostComponent>;
let testPath: string;
let liveExampleContent: string|null;
//////// test helpers ////////
@ -41,12 +40,11 @@ describe('LiveExampleComponent', () => {
liveExampleDe = fixture.debugElement.children[0];
liveExampleComponent = liveExampleDe.componentInstance;
// Copy the LiveExample's innerHTML (content)
// into the `liveExampleContent` property as the DocViewer does
liveExampleDe.nativeElement.liveExampleContent = liveExampleContent;
// Trigger `ngAfterContentInit()`.
fixture.detectChanges();
liveExampleComponent.onResize(1033); // wide by default
// Ensure wide-screen by default.
liveExampleComponent.onResize(1033);
fixture.detectChanges();
testFn();
@ -64,7 +62,6 @@ describe('LiveExampleComponent', () => {
.overrideComponent(EmbeddedStackblitzComponent, {set: {template: 'NO IFRAME'}});
testPath = defaultTestPath;
liveExampleContent = null;
});
describe('when not embedded', () => {
@ -196,12 +193,12 @@ describe('LiveExampleComponent', () => {
});
it('should add title from <live-example> body', () => {
liveExampleContent = 'The Greatest Example';
setHostTemplate('<live-example title="ignore this title"></live-example>');
const expectedTitle = 'The Greatest Example';
setHostTemplate(`<live-example title="ignore this title">${expectedTitle}</live-example>`);
testComponent(() => {
const anchor = getLiveExampleAnchor();
expect(anchor.textContent).toBe(liveExampleContent, 'anchor content');
expect(anchor.getAttribute('title')).toBe(liveExampleContent, 'title');
expect(anchor.textContent).toBe(expectedTitle, 'anchor content');
expect(anchor.getAttribute('title')).toBe(expectedTitle, 'title');
});
});

View File

@ -1,5 +1,5 @@
/* tslint:disable component-selector */
import { Component, ElementRef, HostListener, Input, OnInit, AfterViewInit, ViewChild } from '@angular/core';
import { AfterContentInit, AfterViewInit, Component, ElementRef, HostListener, Input, ViewChild } from '@angular/core';
import { Location } from '@angular/common';
import { CONTENT_URL_PREFIX } from 'app/documents/document.service';
@ -54,7 +54,7 @@ const zipBase = CONTENT_URL_PREFIX + 'zips/';
selector: 'live-example',
templateUrl: 'live-example.component.html'
})
export class LiveExampleComponent implements OnInit {
export class LiveExampleComponent implements AfterContentInit {
// Will force to embedded-style when viewport width is narrow
// "narrow" value was picked based on phone dimensions from http://screensiz.es/phone
@ -71,6 +71,9 @@ export class LiveExampleComponent implements OnInit {
zip: string;
zipName: string;
@ViewChild('content')
private content: ElementRef;
constructor(
private elementRef: ElementRef,
location: Location ) {
@ -111,11 +114,9 @@ export class LiveExampleComponent implements OnInit {
this.stackblitz = `${liveExampleBase}${exampleDir}/${this.stackblitzName}stackblitz.html${urlQuery}`;
}
ngOnInit() {
// The `liveExampleContent` property is set by the DocViewer when it builds this component.
// It is the original innerHTML of the host element.
ngAfterContentInit() {
// Angular will sanitize this title when displayed so should be plain text.
const title = this.elementRef.nativeElement.liveExampleContent;
const title = this.content.nativeElement.textContent;
this.title = (title || this.attrs.title || 'live example').trim();
this.onResize(window.innerWidth);
}