diff --git a/gallery/src/pages/components/ha-selector.ts b/gallery/src/pages/components/ha-selector.ts index 600176d024..c3855147ed 100644 --- a/gallery/src/pages/components/ha-selector.ts +++ b/gallery/src/pages/components/ha-selector.ts @@ -175,6 +175,12 @@ const SCHEMAS: { }, }, }, + { + name: "Multiples", + input: { + entity: { name: "Entity", selector: { entity: { multiple: true } } }, + }, + }, ]; @customElement("demo-components-ha-selector") diff --git a/src/components/ha-selector/ha-selector-entity.ts b/src/components/ha-selector/ha-selector-entity.ts index 566dfc0a45..36d0ce57ad 100644 --- a/src/components/ha-selector/ha-selector-entity.ts +++ b/src/components/ha-selector/ha-selector-entity.ts @@ -1,6 +1,8 @@ import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; -import { html, LitElement } from "lit"; +import { css, html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { repeat } from "lit/directives/repeat"; +import { fireEvent } from "../../common/dom/fire_event"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { subscribeEntityRegistry } from "../../data/entity_registry"; import { EntitySelector } from "../../data/selector"; @@ -23,14 +25,45 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) { @property({ type: Boolean }) public disabled = false; protected render() { - return html``; + if (!this.selector.entity.multiple) { + return html``; + } + + // For multiple, the value is a list. + const value = this._normalizedValue as string[]; + + return html` + ${this.label ? html`
${this.label}
` : ""} + ${repeat( + value, + (val) => val, + (entityId, index) => html` + + ` + )} + + `; } public hassSubscribe(): UnsubscribeFunc[] { @@ -48,6 +81,17 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) { ]; } + private get _normalizedValue() { + if (!this.selector.entity.multiple) { + return this.value; + } + + if (!this.value) { + return []; + } + return Array.isArray(this.value) ? this.value : [this.value]; + } + private _filterEntities = (entity: HassEntity): boolean => { if (this.selector.entity?.domain) { const filterDomain = this.selector.entity.domain; @@ -79,6 +123,43 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) { } return true; }; + + // this method is only used when multiple: true + private _valueChanged(ev: any) { + ev.stopPropagation(); + + // undefined = new value + const index = ev.target.index as number | undefined; + // undefined = remove + const newValue = ev.detail.value as string | undefined; + + let updatedValue: string[] | undefined; + + if (index === undefined) { + if (newValue) { + updatedValue = [...this._normalizedValue, newValue]; + } + ev.target.value = ""; + } else if (newValue) { + updatedValue = [...this._normalizedValue]; + updatedValue[index] = newValue; + } else { + updatedValue = this._normalizedValue.filter((_, i) => i !== index); + } + + if (updatedValue) { + fireEvent(this, "value-changed", { + value: updatedValue, + }); + } + } + + static styles = css` + ha-entity-picker + ha-entity-picker { + display: block; + margin-top: 16px; + } + `; } declare global { diff --git a/src/data/selector.ts b/src/data/selector.ts index c8cc87b36e..76f673b125 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -23,6 +23,7 @@ export interface EntitySelector { integration?: string; domain?: string | string[]; device_class?: string; + multiple?: boolean; }; }