All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.fluorumlabs.disconnect.vaadin.Select Maven / Gradle / Ivy

The newest version!
package com.github.fluorumlabs.disconnect.vaadin;

import com.github.fluorumlabs.disconnect.core.annotations.WebComponent;
import com.github.fluorumlabs.disconnect.polymer.types.BooleanPropertyChangeEvent;
import com.github.fluorumlabs.disconnect.polymer.types.StringPropertyChangeEvent;
import com.github.fluorumlabs.disconnect.vaadin.elements.SelectElement;
import com.github.fluorumlabs.disconnect.vaadin.mixins.HasControlStateMixin;
import com.github.fluorumlabs.disconnect.vaadin.mixins.HasElementMixin;
import com.github.fluorumlabs.disconnect.vaadin.mixins.HasThemableMixin;
import com.github.fluorumlabs.disconnect.vaadin.renderers.SelectRenderer;
import com.github.fluorumlabs.disconnect.zero.component.*;
import com.github.fluorumlabs.disconnect.zero.observable.ObservableEvent;
import com.github.fluorumlabs.disconnect.zero.observable.ObservableValue;
import js.web.dom.ParentNode;

import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * <vaadin-select> is a Web Component for selecting idToValues from a list of itemToComponents.
 * The content of the
 * the select can be populated in two ways: imperatively by using renderer callback function and
 * declaratively by using Polymer's Templates.
 *
 * 

Rendering

* By default, the select uses the content provided by using the renderer callback function. *

* The renderer function provides root, select arguments. * Generate DOM content, append it to the root element and control the state * of the host element by accessing select. * *

<vaadin-select id="select"></vaadin-select>
 * 
*
const select = document.querySelector('#select');
 * select.renderer = function(root, select) {
 *   const listBox = document.createElement('vaadin-list-box');
 *   // append 3 <vaadin-item> elements
 *   ['Jose', 'Manolo', 'Pedro'].forEach(function(name) {
 *     const item = document.createElement('vaadin-item');
 *     item.textContent = name;
 *     listBox.appendChild(item);
 *   });
 *
 *   // update the content
 *   root.appendChild(listBox);
 * };
 * 
* Renderer is called on initialization of new select and on its opening. * DOM generated during the renderer call can be reused * in the next renderer call and will be provided with the root argument. * On first call it will be empty. * *

Polymer Templates

* Alternatively, the content can be provided with Polymer's Template. * Select finds the first child template and uses that in case renderer callback function * is not provided. You can also set a custom template using the template property. * *
<vaadin-select>
 *   <template>
 *     <vaadin-list-box>
 *       <vaadin-item label="foo">Foo</vaadin-item>
 *       <vaadin-item>Bar</vaadin-item>
 *       <vaadin-item>Baz</vaadin-item>
 *     </vaadin-list-box>
 *   </template>
 * </vaadin-select>
 * 
* Hint: By setting the label property of inner vaadin-itemToComponents you will * be able to change the visual representation of the selected value in the input part. * *

Styling

* The following shadow DOM parts are available for styling: * * * * * * * * *
Part nameDescription
toggle-buttonThe toggle button
* The following state attributes are available for styling: * * * * * * * * * * * * *
AttributeDescriptionPart name
openedSet when the select is open:host
invalidSet when the element is invalid:host
focusedSet when the element is focused:host
focus-ringSet when the element is keyboard focused:host
readonlySet when the select is read only:host
* <vaadin-select> element sets these custom CSS properties: * * * * * * * * *
Property nameDescriptionTheme for element
--vaadin-select-text-field-widthWidth of the select text * fieldvaadin-select-overlay
* See * ThemableMixin – how to apply styles for shadow parts *

* In addition to <vaadin-select> itself, the following internal * components are themable: * *

    *
  • <vaadin-select-text-field>
  • *
  • <vaadin-select-overlay>
  • *
* Note: the theme attribute value set on <vaadin-select> is * propagated to the internal themable components listed above. */ @WebComponent public class Select extends AbstractComponent implements HasElementMixin>, HasControlStateMixin>, HasThemableMixin>, HasSlots, HasStyle>, HasComponents, Component> { /** * Backing ListBox */ private ListBox backingListBox = new ListBox(); private Map idToValues = new HashMap<>(); private Map> itemToComponents = new HashMap<>(); private Function idExtractor = Object::toString; private Function> itemRenderer = item -> { String id = idExtractor.apply(item); return new Item().value(id).text(id); }; public Select() { super(SelectElement.TAGNAME()); renderer(() -> backingListBox); } public Select(String label) { this(); label(label); } public Select setItems(Iterable items, Function idExtractor) { removeAll(); this.idExtractor = idExtractor; items.forEach(this::add); return this; } public Select setItems(Iterable items) { removeAll(); items.forEach(this::add); return this; } public Select setItems(T[] items, Function idExtractor) { removeAll(); this.idExtractor = idExtractor; add(items); return this; } public Select setItems(T... items) { removeAll(); add(items); return this; } public Select setItemRenderer(Function> itemRenderer) { this.itemRenderer = itemRenderer; for (Map.Entry> renderedItem : itemToComponents.entrySet()) { Component newItem = this.itemRenderer.apply(renderedItem.getKey()); ParentNode parentNode = renderedItem.getValue().getRenderedNode().getParentNode(); if (parentNode != null) { parentNode.replaceChild(newItem.getRenderedNode(), renderedItem.getValue().getRenderedNode()); } } return this; } /** * It stores the the value property of the selected item, providing the * value for iron-form. * When there’s an item selected, it's the value of that item, otherwise * it's an empty string. * On change or initialization, the component finds the item which matches the * value and displays it. * If no value is provided to the component, it selects the first item without * value or empty value. * Hint: If you do not want to select any item by default, you can either set all * the idToValues of inner vaadin-itemToComponents, or set the vaadin-select value to * an inexistent value in the itemToComponents list. */ public ObservableValue value() { return createObservableValue( () -> idToValues.get(getNode().getValue()), (item) -> getNode().setValue(item == null ? null : idExtractor.apply(item)), valueChangedEvent()); } /** * Set to true if the value is invalid. */ public ObservableValue invalid() { return createObservableValue(getNode()::isInvalid, getNode()::setInvalid, invalidChangedEvent()); } /** * Set when the select is open */ public ObservableValue opened() { return createObservableValue(getNode()::isOpened, getNode()::setOpened, openedChangedEvent()); } /** * Custom function for rendering the content of the <vaadin-select>. * Receives two arguments: * *
    *
  • root The <vaadin-select-overlay> internal container * DOM element. Append your content to it.
  • *
  • select The reference to the <vaadin-select> element.
  • *
*/ @Nullable public SelectRenderer renderer() { return getNode().getRenderer(); } /** * Custom function for rendering the content of the <vaadin-select>. * Receives two arguments: * *
    *
  • root The <vaadin-select-overlay> internal container * DOM element. Append your content to it.
  • *
  • select The reference to the <vaadin-select> element.
  • *
*/ public Select renderer(Supplier> renderer) { getNode().setRenderer(((root, select) -> root.appendChild(renderer.get().getRenderedNode()))); return this; } /** * The error message to display when the select value is invalid */ @Nullable public String errorMessage() { return getNode().getErrorMessage(); } /** * The error message to display when the select value is invalid */ public Select errorMessage(String errorMessage) { getNode().setErrorMessage(errorMessage); return this; } /** * String used for the label element. */ @Nullable public String label() { return getNode().getLabel(); } /** * String used for the label element. */ public Select label(String label) { getNode().setLabel(label); return this; } /** * The current required state of the select. True if required. */ public boolean required() { return getNode().isRequired(); } /** * The current required state of the select. True if required. */ public Select required(boolean required) { getNode().setRequired(required); return this; } /** * The name of this element. */ @Nullable public String name() { return getNode().getName(); } /** * The name of this element. */ public Select name(String name) { getNode().setName(name); return this; } /** * A hint to the user of what can be entered in the control. * The placeholder will be displayed in the case that there * is no item selected, or the selected item has an empty * string label, or the selected item has no label and it's * DOM content is empty. */ @Nullable public String placeholder() { return getNode().getPlaceholder(); } /** * A hint to the user of what can be entered in the control. * The placeholder will be displayed in the case that there * is no item selected, or the selected item has an empty * string label, or the selected item has no label and it's * DOM content is empty. */ public Select placeholder(String placeholder) { getNode().setPlaceholder(placeholder); return this; } /** * When present, it specifies that the element is read-only. */ public boolean readonly() { return getNode().isReadonly(); } /** * When present, it specifies that the element is read-only. */ public Select readonly(boolean readonly) { getNode().setReadonly(readonly); return this; } /** * Manually invoke existing renderer. */ public void render() { getNode().render(); } /** * Returns true if value is valid, and sets the invalid flag appropriately. * * @return True if the value is valid and sets the invalid flag appropriately */ public boolean validate() { return getNode().validate(); } /** * Fired when the opened property changes. */ public ObservableEvent openedChangedEvent() { return createEvent("opened-changed"); } /** * Fired when the value property changes. */ public ObservableEvent valueChangedEvent() { return createEvent("value-changed"); } /** * Fired when the invalid property changes. */ public ObservableEvent invalidChangedEvent() { return createEvent("invalid-changed"); } public HasSlots.Container prefixSlot() { return slotted("prefix"); } @Override public Select add(Component component) { backingListBox.add(component); return this; } public Select add(T item) { idToValues.put(idExtractor.apply(item), item); return add(itemToComponents.computeIfAbsent(item, itemRenderer)); } @Override public Select add(Component... components) { backingListBox.add(components); return this; } public Select add(T... items) { for (T item : items) { add(item); } return this; } @Override public Select insert(Component... components) { backingListBox.insert(components); return this; } public Select insert(T... items) { for (int i = items.length - 1; i >= 0; i--) { idToValues.put(idExtractor.apply(items[i]), items[i]); insert(itemToComponents.computeIfAbsent(items[i], itemRenderer)); } return this; } @Override public Select insert(Component component) { backingListBox.insert(component); return this; } public Select insert(T item) { idToValues.put(idExtractor.apply(item), item); insert(itemToComponents.computeIfAbsent(item, itemRenderer)); return this; } @Override public Select replaceContent(Component component) { backingListBox.replaceContent(component); return this; } public Select replaceContent(T item) { return removeAll().add(item); } @Override public Select replaceContent(Component... components) { backingListBox.replaceContent(components); return this; } public Select replaceContent(T... items) { return removeAll().add(items); } @Override public Select remove(Component component) { backingListBox.remove(component); return this; } public Select remove(T item) { idToValues.remove(idExtractor.apply(item)); Component component = itemToComponents.get(item); if (component != null) { itemToComponents.remove(item); remove(component); } return this; } @Override public Select remove(Component... components) { backingListBox.remove(components); return this; } public Select remove(T... items) { for (T item : items) { remove(item); } return this; } @Override public Select removeAll() { backingListBox.removeAll(); idToValues.clear(); itemToComponents.clear(); return this; } @Override public Select stamp(Template template) { backingListBox.stamp(template); return this; } @Override public Select stamp(Template template, boolean deepClone) { backingListBox.stamp(template, deepClone); return this; } @Override public Select stampReplace(Template template) { backingListBox.stampReplace(template); return this; } @Override public Select stampReplace(Template template, boolean deepClone) { backingListBox.stampReplace(template, deepClone); return this; } @Override public Select stampInsert(Template template) { backingListBox.stampInsert(template); return this; } @Override public Select stampInsert(Template template, boolean deepClone) { backingListBox.stampInsert(template, deepClone); return this; } @Override public Select text(String text) { backingListBox.text(text); return this; } @Override public String text() { return backingListBox.text(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy