@microsoft/mgt
Version:
The Microsoft Graph Toolkit
135 lines • 5.36 kB
JavaScript
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/
import { html } from 'lit-element';
import { equals } from '../utils/Utils';
import { MgtBaseComponent } from './baseComponent';
import { TemplateHelper } from './templateHelper';
/**
* An abstract class that defines a templatable web component
*
* @export
* @abstract
* @class MgtTemplatedComponent
* @extends {MgtBaseComponent}
*/
export class MgtTemplatedComponent extends MgtBaseComponent {
constructor() {
super();
/**
* Collection of functions to be used in template binding
*
* @type {*}
* @memberof MgtTemplatedComponent
*/
this.templateConverters = {};
/**
* Holds all templates defined by developer
*
* @protected
* @memberof MgtTemplatedComponent
*/
this.templates = {};
this._renderedSlots = false;
this._renderedTemplates = {};
this._slotNamesAddedDuringRender = [];
this.templateConverters.lower = (str) => str.toLowerCase();
this.templateConverters.upper = (str) => str.toUpperCase();
}
/**
* Updates the element. This method reflects property values to attributes.
* It can be overridden to render and keep updated element DOM.
* Setting properties inside this method will *not* trigger
* another update.
*
* * @param _changedProperties Map of changed properties with old values
*/
update(changedProperties) {
this.templates = this.getTemplates();
this._slotNamesAddedDuringRender = [];
super.update(changedProperties);
}
/**
* Invoked whenever the element is updated. Implement to perform
* post-updating tasks via DOM APIs, for example, focusing an element.
*
* Setting properties inside this method will trigger the element to update
* again after this update cycle completes.
*
* * @param changedProperties Map of changed properties with old values
*/
updated(changedProperties) {
super.updated(changedProperties);
this.removeUnusedSlottedElements();
}
/**
* Render a <template> by type and return content to render
*
* @param templateType type of template (indicated by the data-type attribute)
* @param context the data context that should be expanded in template
* @param slotName the slot name that will be used to host the new rendered template. set to a unique value if multiple templates of this type will be rendered. default is templateType
*/
renderTemplate(templateType, context, slotName) {
if (!this.templates[templateType]) {
return null;
}
slotName = slotName || templateType;
this._slotNamesAddedDuringRender.push(slotName);
this._renderedSlots = true;
const template = html `
<slot name=${slotName}></slot>
`;
if (this._renderedTemplates.hasOwnProperty(slotName)) {
const { context: existingContext, slot } = this._renderedTemplates[slotName];
if (equals(existingContext, context)) {
return template;
}
this.removeChild(slot);
}
const templateContent = TemplateHelper.renderTemplate(this.templates[templateType], context, this.templateConverters);
const div = document.createElement('div');
div.slot = slotName;
div.dataset.generated = 'template';
if (templateContent) {
div.appendChild(templateContent);
}
this.appendChild(div);
this._renderedTemplates[slotName] = { context, slot: div };
this.fireCustomEvent('templateRendered', { templateType, context, element: div });
return template;
}
getTemplates() {
const templates = {};
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < this.children.length; i++) {
const child = this.children[i];
if (child.nodeName === 'TEMPLATE') {
const template = child;
if (template.dataset.type) {
templates[template.dataset.type] = template;
}
else {
templates.default = template;
}
}
}
return templates;
}
removeUnusedSlottedElements() {
if (this._renderedSlots) {
for (let i = 0; i < this.children.length; i++) {
const child = this.children[i];
if (child.dataset && child.dataset.generated && !this._slotNamesAddedDuringRender.includes(child.slot)) {
this.removeChild(child);
delete this._renderedTemplates[child.slot];
i--;
}
}
this._renderedSlots = false;
}
}
}
//# sourceMappingURL=templatedComponent.js.map