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:
parent
a7b07defe1
commit
41fea84957
|
@ -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'">
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue