com.github.fluorumlabs.disconnect.polymer.DomRepeat Maven / Gradle / Ivy
Show all versions of disconnect-polymer Show documentation
package com.github.fluorumlabs.disconnect.polymer;
import com.github.fluorumlabs.disconnect.core.annotations.WebComponent;
import com.github.fluorumlabs.disconnect.polymer.elements.DomRepeatElement;
import com.github.fluorumlabs.disconnect.polymer.elements.TemplateInstanceBase;
import com.github.fluorumlabs.disconnect.polymer.mixins.HasOptionalMutableData;
import com.github.fluorumlabs.disconnect.polymer.types.IntPropertyChangeEvent;
import com.github.fluorumlabs.disconnect.zero.component.AbstractComponent;
import com.github.fluorumlabs.disconnect.zero.component.Component;
import com.github.fluorumlabs.disconnect.zero.component.HasComponent;
import com.github.fluorumlabs.disconnect.zero.component.Template;
import com.github.fluorumlabs.disconnect.zero.observable.ObservableEvent;
import js.lang.Any;
import js.util.collections.Array;
import js.util.function.IntKeyPredicate;
import js.util.function.JsComparator;
import js.web.dom.Event;
import js.web.dom.HTMLElement;
import javax.annotation.Nullable;
/**
* The <dom-repeat>
element will automatically stamp and binds one instance of template content to
* each object in a user-provided array.
* dom-repeat
accepts an items
property, and one instance of the template
* is stamped for each item into the DOM at the location of the dom-repeat
element. The item
* property will be set on each instance's binding scope, thus templates should bind to sub-properties of
* item
.
*
* Example:
*
*
<dom-module id="employee-list">
*
* <template>
*
* <div> Employee list: </div>
* <dom-repeat items="{{employees}}">
* <template>
* <div>First name: <span>{{item.first}}</span></div>
* <div>Last name: <span>{{item.last}}</span></div>
* </template>
* </dom-repeat>
*
* </template>
*
* </dom-module>
*
* With the following custom element definition:
*
* class EmployeeList extends PolymerElement {
* static get is() { return 'employee-list'; }
* static get properties() {
* return {
* employees: {
* value() {
* return [
* {first: 'Bob', last: 'Smith'},
* {first: 'Sally', last: 'Johnson'},
* ...
* ];
* }
* }
* };
* }
* }
*
* Notifications for changes to items sub-properties will be forwarded to template instances, which will update via the
* normal structured data notification system.
*
* Mutations to the items
array itself should be made using the Array mutation API's on the PropertyEffects
* mixin (push
, pop
, splice
,
* shift
, unshift
), and template instances will be kept in sync with the
* data in the array.
*
* Events caught by event handlers within the dom-repeat
template will be decorated with a
* model
property, which represents the binding scope for each template instance. The model should be used
* to manipulate data on the instance, for example event.model.set('item.checked', true);
.
*
* Alternatively, the model for a template instance for an element stamped by a dom-repeat
can be obtained
* using the modelForElement
API on the
* dom-repeat
that stamped it, for example
* this.$.domRepeat.modelForElement(event.target).set('item.checked', true);
.
* This may be useful for manipulating instance data of event targets obtained by event handlers on parents of the
* dom-repeat
(event delegation).
*
* A view-specific filter/sort may be applied to each dom-repeat
by supplying a
* filter
and/or sort
property. This may be a string that names a function on
* the host, or a function may be assigned to the property directly. The functions should implemented following the
* standard Array
filter/sort API.
*
* In order to re-run the filter or sort functions based on changes to sub-fields of items
, the
* observe
property may be set as a space-separated list of
* item
sub-fields that should cause a re-filter/sort when modified. If
* the filter or sort function depends on properties not contained in items
, the user should observe
* changes to those properties and call render
to update the view based on the dependency change.
*
* For example, for an dom-repeat
with a filter of the following:
*
*
isEngineer(item) {
* return item.type == 'engineer' || item.manager.type == 'engineer';
* }
*
* Then the observe
property should be configured as follows:
*
* <dom-repeat items="{{employees}}" filter="isEngineer"
* observe="type manager.type">
*
*
* @param - the type parameter
*/
@WebComponent
public class DomRepeat
-
extends AbstractComponent
>
implements HasOptionalMutableData, DomRepeat- >,
HasComponent
, DomRepeat- , Template> {
/**
* Instantiates a new Dom repeat.
*/
public DomRepeat() {
super(DomRepeatElement.TAGNAME());
}
/**
* Instantiates a new Dom repeat.
*
* @param components the components
*/
public DomRepeat(Component>... components) {
this();
Template template = new Template();
template.add(components);
setContent(template);
}
/**
* An array containing items determining how many instances of the template to stamp and that that each template
* instance should bind to.
*
* @return the array
*/
@Nullable
public Array
- items() {
return getNode().getItems();
}
/**
* An array containing items determining how many instances of the template to stamp and that that each template
* instance should bind to.
*
* @param items the items
*
* @return the dom repeat
*/
public DomRepeat
- items(ITEM... items) {
getNode().setItems(items);
return this;
}
/**
* Items dom repeat.
*
* @param items the items
*
* @return the dom repeat
*/
public DomRepeat
- items(Array
- items) {
getNode().setItems(items);
return this;
}
/**
* The name of the variable to add to the binding scope for the array element associated with a given template
* instance.
*
* @return the string
*/
@Nullable
public String as() {
return getNode().getAs();
}
/**
* The name of the variable to add to the binding scope for the array element associated with a given template
* instance.
*
* @param as the as
*
* @return the dom repeat
*/
public DomRepeat
- as(String as) {
getNode().setAs(as);
return this;
}
/**
* The name of the variable to add to the binding scope with the index of the instance in the sorted and filtered
* list of rendered items. Note, for the index in the
this.items
array, use the value of the
* itemsIndexAs
property.
*
* @return the string
*/
@Nullable
public String indexAs() {
return getNode().getIndexAs();
}
/**
* The name of the variable to add to the binding scope with the index of the instance in the sorted and filtered
* list of rendered items. Note, for the index in the this.items
array, use the value of the
* itemsIndexAs
property.
*
* @param indexAs the index as
*
* @return the dom repeat
*/
public DomRepeat- indexAs(String indexAs) {
getNode().setIndexAs(indexAs);
return this;
}
/**
* The name of the variable to add to the binding scope with the index of the instance in the
*
this.items
array. Note, for the index of this instance in the sorted and filtered list of rendered
* items, use the value of the indexAs
property.
*
* @return the string
*/
@Nullable
public String itemsIndexAs() {
return getNode().getItemsIndexAs();
}
/**
* The name of the variable to add to the binding scope with the index of the instance in the
* this.items
array. Note, for the index of this instance in the sorted and filtered list of rendered
* items, use the value of the indexAs
property.
*
* @param itemsIndexAs the items index as
*
* @return the dom repeat
*/
public DomRepeat- itemsIndexAs(String itemsIndexAs) {
getNode().setItemsIndexAs(itemsIndexAs);
return this;
}
/**
* A function that should determine the sort order of the items. This property should either be provided as a
* string, indicating a method name on the element's host, or else be an actual function. The function should
* match
* the sort function passed to
Array.sort
. Using a sort function has no effect on the underlying
* items
array.
*
* @return the js comparator
*/
@Nullable
public JsComparator- sort() {
return getNode().getSort();
}
/**
* A function that should determine the sort order of the items. This property should either be provided as a
* string, indicating a method name on the element's host, or else be an actual function. The function should
* match
* the sort function passed to
Array.sort
. Using a sort function has no effect on the underlying
* items
array.
*
* @param sort the sort
*
* @return the dom repeat
*/
public DomRepeat- sort(JsComparator
- sort) {
getNode().setSort(sort);
return this;
}
/**
* A function that can be used to filter items out of the view. This property should either be provided as a
* string, indicating a method name on the element's host, or else be an actual function. The function should
* match
* the sort function passed to
Array.filter
. Using a filter function has no effect on the underlying
* items
array.
*
* @return the int key predicate
*/
@Nullable
public IntKeyPredicate- > filter() {
return getNode().getFilter();
}
/**
* A function that can be used to filter items out of the view. This property should either be provided as a
* string, indicating a method name on the element's host, or else be an actual function. The function should
* match
* the sort function passed to
Array.filter
. Using a filter function has no effect on the underlying
* items
array.
*
* @param filter the filter
*
* @return the dom repeat
*/
public DomRepeat- filter(IntKeyPredicate
- > filter) {
getNode().setFilter(filter);
return this;
}
/**
* When using a
filter
or sort
function, the observe
property should be set
* to a space-separated list of the names of item sub-fields that should trigger a re-sort or re-filter when
* changed. These should generally be fields of item
that the sort or filter function depends on.
*
* @return the string
*/
@Nullable
public String observe() {
return getNode().getObserve();
}
/**
* When using a filter
or sort
function, the observe
property should be set
* to a space-separated list of the names of item sub-fields that should trigger a re-sort or re-filter when
* changed. These should generally be fields of item
that the sort or filter function depends on.
*
* @param observe the observe
*
* @return the dom repeat
*/
public DomRepeat- observe(String observe) {
getNode().setObserve(observe);
return this;
}
/**
* When using a
filter
or sort
function, the delay
property determines a
* debounce time in ms after a change to observed item properties that must pass before the filter or sort is
* re-run. This is useful in rate-limiting shuffling of the view when item changes may be frequent.
*
* @return the double
*/
public double delay() {
return getNode().getDelay();
}
/**
* When using a filter
or sort
function, the delay
property determines a
* debounce time in ms after a change to observed item properties that must pass before the filter or sort is
* re-run. This is useful in rate-limiting shuffling of the view when item changes may be frequent.
*
* @param delay the delay
*
* @return the dom repeat
*/
public DomRepeat- delay(double delay) {
getNode().setDelay(delay);
return this;
}
/**
* Count of currently rendered items after
filter
(if any) has been applied. If "chunking
* mode" is enabled, renderedItemCount
is updated each time a set of template instances is
* rendered.
*
* @return the int
*/
public int renderedItemCount() {
return getNode().getRenderedItemCount();
}
/**
* Defines an initial count of template instances to render after setting the items
array, before the
* next paint, and puts the dom-repeat
into "chunking mode". The remaining items will be
* created and rendered incrementally at each animation frame therof until all instances have been rendered.
*
* @return the int
*/
public int initialCount() {
return getNode().getInitialCount();
}
/**
* Defines an initial count of template instances to render after setting the items
array, before the
* next paint, and puts the dom-repeat
into "chunking mode". The remaining items will be
* created and rendered incrementally at each animation frame therof until all instances have been rendered.
*
* @param initialCount the initial count
*
* @return the dom repeat
*/
public DomRepeat- initialCount(int initialCount) {
getNode().setInitialCount(initialCount);
return this;
}
/**
* When
initialCount
is used, this property defines a frame rate (in fps) to target by throttling the
* number of instances rendered each frame to not exceed the budget for the target frame rate. The framerate is
* effectively the number of requestAnimationFrame
s that it tries to allow to actually fire in a given
* second. It does this by measuring the time between rAF
s and continuously adjusting the number of
* items created each rAF
to maintain the target framerate. Setting this to a higher number allows
* lower latency and higher throughput for event handlers and other tasks, but results in a longer time for the
* remaining items to complete rendering.
*
* @return the double
*/
public double targetFramerate() {
return getNode().getTargetFramerate();
}
/**
* When initialCount
is used, this property defines a frame rate (in fps) to target by throttling the
* number of instances rendered each frame to not exceed the budget for the target frame rate. The framerate is
* effectively the number of requestAnimationFrame
s that it tries to allow to actually fire in a given
* second. It does this by measuring the time between rAF
s and continuously adjusting the number of
* items created each rAF
to maintain the target framerate. Setting this to a higher number allows
* lower latency and higher throughput for event handlers and other tasks, but results in a longer time for the
* remaining items to complete rendering.
*
* @param targetFramerate the target framerate
*
* @return the dom repeat
*/
public DomRepeat- targetFramerate(double targetFramerate) {
getNode().setTargetFramerate(targetFramerate);
return this;
}
/**
* Forces the element to render its content. Normally rendering is asynchronous to a provoking change. This is done
* for efficiency so that multiple changes trigger only a single render. The render method should be called if, for
* example, template rendering is required to validate application state.
*/
public void render() {
getNode().render();
}
/**
* Returns the item associated with a given element stamped by this
dom-repeat
.
*
* Note, to modify sub-properties of the item,
* modelForElement(el).set('item.<sub-prop>', value)
* should be used.
*
* @param el Element for which to return the item.
*
* @return Item associated with the element.
*/
public ITEM itemForElement(HTMLElement el) {
return getNode().itemForElement(el);
}
/**
* Returns the inst index for a given element stamped by this dom-repeat
. If sort
is
* provided, the index will reflect the sorted order (rather than the original array order).
*
* @param el Element for which to return the index.
*
* @return Row index associated with the element (note this may not correspond to the array index if a user
* sort
is applied).
*/
public int indexForElement(HTMLElement el) {
return getNode().indexForElement(el);
}
/**
* Returns the template "model" associated with a given element, which serves as the binding scope for
* the
* template instance the element is contained in. A template model should be used to manipulate data associated
* with
* this template instance.
*
* Example:
*
* let model = modelForElement(el); if (model.index < 10) { model.set('item.checked', true); }
*
* @param el Element for which to return a template model.
*
* @return Model representing the binding scope for the element.
*/
public TemplateInstanceBase modelForElement(HTMLElement el) {
return getNode().modelForElement(el);
}
/**
* Fired whenever DOM is added or removed by this template (by default, rendering occurs lazily). To force
* immediate rendering, call
* render
.
*
* @return the observable event
*/
public ObservableEvent domChangeEvent() {
return createEvent("dom-change");
}
/**
* Fired when the renderedItemCount
property changes.
*
* @return the observable event
*/
public ObservableEvent renderedItemCountChangedEvent() {
return createEvent("rendered-item-count-changed");
}
}