Entity List Backing Bean

An EntityListBackingBean can be created for a PageableEntityList that can be MemoryEntityList or QueryCriteriaEntityList. All the entities of a MemoryEntityList are stored in memory, but only the entities in current page of a QueryCriteriaEntityList is retrieved from persistence.

The following example creates an EntityListBackingBean from a list of entities in memory:


	List<Employee> employess = ...;
	DataDescriptor dd = new DataDescriptor(Employee.class, true, true);
	MemoryEntityList<Employee> employeeList = new MemoryEntityList<Employee>(employees, dd);	
  	EntityDataSource<Employee> eds = new EntityDataSource<Employee>(employeeList);
  	EntityListBackingBean<Employee> employeeListBackingBean = ContainerBean.createEntityListBackingBean(
  		parentComponent, Employee.class, eds, viewConfig, 
  		manageMode, containerBean);

The following example creates an EntityListBackingBean from a QueryCriteria: full time employees hired after a certain date, ordering by employee id ascending.


	CriteriaElement[] propertyQueryElements = new CriteriaElement[]{
		DetachedCriteria.eq("type", Employee.Type.FULL_TIME),
		DetachedCriteria.ge("hiredDate", aDate),
		DetachedCriteria.asc("nid")
	};
	QueryCriteria<Employee, Employee> queryCriteria = new QueryCriteria<Employee, Employee>(Employee.class, propertyQueryElements);
  	EntityDataSource<Employee> eds = new EntityDataSource<Employee>(queryCriteria);
  	EntityListBackingBean<Employee> employeeListBackingBean = ContainerBean.createEntityListBackingBean(
  		parentComponent, Employee.class, eds, viewConfig, 
  		manageMode, containerBean);

Header/Footer Menu

Menu nodes can be added to header or footer menu by overriding the following method. For example,

	@Overrride
	protected void addMenuNodes(boolean groupQuery) throws SystemException {
  		super.addMenuNodes(groupQuery);
  		
  		// add upload menu node
  		if (isHasCreatePermission()) {
  			MenuBean menuBean = getMenuBean(COMMAND_UPLOAD, false);
  			if (menuBean != null) {
  				MenuNode uploadMenuNode = new MenuNode(menuBean,
  						COMMAND_UPLOAD, RenderStyle.COMMAND_BUTTON);
  				uploadMenuNode.setIcon(IconMap.UI_ICON_UPLOAD);
  				menuBean.add(uploadMenuNode);      
  			}
  		}
  		
	}
To handle menu node actions,

	@Override
	public PageNavigation clickMenuNode(MenuNode menuNode) throws SystemException {
		String command = menuNode.getCommand();
		if (command.equals(COMMAND_UPLOAD)) {
			...
			
			return null;
		}
		
		return super.clickMenuNode(menuNode);
  	}

Entity Row Commands

For an entity list, menu nodes can be added for each row, and they are called entity row commands. By default, view/edit/delete will be added to each row if current user has the corresponding permission. To add more menu nodes to entity rows, override the following methods in its EntityBackingBean (not EntityListBackingBean). For example,

	@Override
	protected void addRowCommandMenuNodes(EntityListBackingBean<T> entityListBackingBean,
			MenuBean menuBean) throws SystemException {
		super.addRowCommandMenuNodes(entityListBackingBean, menuBean);
  		
		MenuNode downloadMenuNode = new MenuNode(menuBean, COMMAND_DOWNLOAD, RenderStyle.COMMAND_LINK);
		downloadMenuNode.getPartialBehaviorSupport(true).disableActionAjax();
		menuBean.add(downloadMenuNode); 
	}
To handle row command menu node action:
  
	@Override
	protected PageNavigation clickEntityRowCommand(EntityListBackingBean<T> entityListBackingBean,
		T entity, EntityProperty<T> property, MenuNode menuNode) throws SystemException {
    
		String command = menuNode.getCommand();
		if (command.equals(COMMAND_DOWNLOAD)) {
 			// handle action
		}
    
		return super.clickEntityRowCommand(entityListBackingBean, entity, property, menuNode);
	}

In-Place Create/Edit

For an entity list, entities can be added or editted in place. Its EntityBackingBean must override the following methods to enable the following in-place actions:

In-place edit:


	public boolean isEntityListEditInPlace(EntityListBackingBean<T> entityListBackingBean)
In-place create by appending editable new rows:
 
	public boolean isEntityListCreateInPlace(EntityListBackingBean<T> entityListBackingBean)
In-place create by inserting editable new rows:

	public boolean isEntityListInsertBeforeEnabled(EntityListBackingBean<T> entityListBackingBean)
Change the order of child entities in the list:

	public boolean isEntityListMoveUpDownEnabled(EntityListBackingBean<T> entityListBackingBean) throws SystemException 
To maintain the order of child entities, the child entity type must include sequenceNo in persistence by annotation. For example,

	@Table("MyType")
	@Entity("MyType")
	public class MyType extends PersistenceEntityBase implements ChildEntity {
		...
		
		@Override
		@Column(nullable=false)
		public Integer getSequenceNo() {
			return sequenceNo;
		}
	}

Add Rows and Scan Barcode

The command "AddRows" will add a number of rows(uninitialized entities) to the entity list, and users can fill out the property values of the added entities in place. The viewConfig elements entityCountToAdd and askEntityCountToAdd control the behavior of the AddRows command. For example,
	<viewConfig>
		<viewConfig name="orderItems">
			<entityCountToAdd>1</entityCountToAdd>
			<askEntityCountToAdd>false</askEntityCountToAdd>
		</viewConfig>
	</viewConfig>
Similarily to "AddRows" command, "ScanBarcode" command can add one new entity to the entity list by scanning barcode, but the entity added can be merged to an existing entity if any. A dialog will be opened for user to fill out property values if necessary before adding the new entity.

Override the following method in the EntityListBackingBean to handle barcode scanning:


	@Override
	protected PageNavigation scanBarcode(String barcode) throws SystemException {
		super.scanBarcode(barcode);
		...
	}
Call the following static method of EntityListCommandHandler to open input dialog:

public static <E extends PersistenceEntity, I extends PersistenceEntity> boolean askValuesBeforeAddingChildEntity(
			final EntityBackingBean<E> parentEntityBean, final I childEntity, String childEntityListPropertyName,
			List<String> extraProperties, EntityPropertyInitializer<I> initializer,
			final ContainerBean containerBean)
The dialog listener must be configured to add the child entity if the askValues dialog is opened. For example,
	if (EntityListCommandHandler.askValueBeforeAddingChildEntity(...)) {
		DialogBaen dialogBean = containerBean.getDialogBean();
		dialogBean.setDialogListener(...)
	}
To enable barcode scanning, set parameter scan.barcode to true. The nested viewConfig name is "addEntity.askValues" for the child entity input bean. For example,
	<viewConfig>
		<viewConfig name="orderItems">
			<param name="scan.barcode" value="true"/>
			
			<viewConfig name="addEntity.askValues">
				<propertiesToShow>employee</propertiesToShow>
			</viewConfig>
		</viewConfig>
	</viewConfig>
If the childEntity to add is an EntityAttrValueSupport, and there is any entityAttrValue whose value is null, the dialog will be opened regardless of the nested viewConfig.

Column Headers

The default layout type for an entity list is TABLE if not specified. By default each top-level EntityProperty of an EntityListBackingBean is one column in the entity list table. But the column headers can be hierarchical, and a column header can have sub headers. Each header is called Node in the hierarchical tree. For example,

H1(H1.1, H1.2(H1.2.1, H1.2.2), H1.3), H2(H2.1, H2.2, H2.3)
The leaf header nodes must match the entity properties of EntityListBackingBean. Custom column headers can be set in ViewConfig:

	EntityListViewConfig viewConfig = new EntityListViewConfig(ViewType.ENTITY_LIST_WIDE);
	ColumnHeaders columnHeaders = new ColumnHeaders("H1(H1.1, H1.2(H1.2.1, H1.2.2), H1.3), H2(H2.1, H2.2, H2.3)");
	viewConfig.setColumnHeaders(columnHeaders);
A column header can have attributes such as style and class. For example,
Purchase[class="ui-title"](Quantity, Unit Price, Total[style="text-align:right"])
A special attribute "data-property" is used to associate a leaf header node with an entity property for the header node to be adaptive. That is, if the associated entity property is not visible, the header node will be removed. For example,
Product,UOM,Attributes[data-property="attributes"],
Purchase[class="ui-title"](Quantity[class="ui-align-right"], Unit Price[class="ui-align-right"], Total[class="ui-align-right"])

Alternatively, a ColumnHeaders can be created programmatically using ColumnHeaders Node API.


	ColumnHeaders columnHeaders = new ColumnHeaders();
		
	columnHeaders.addToTop("Product", "UOM");
	
	Node attributesNode = new Node("Attributes");
	attributesNode.setProperty("attributes");
	columnHeaders.addToTop(attributesNode);

	Node purchaseNode = new Node("Purchase",
			new String[]{"Quantity", "Unit Price", "Total"});
	purchaseNode.setStyleClasses("ui-title", "ui-align-right");
	columnHeaders.addToTop(purchaseNode);
	
	columnHeaders.finish();
To set top-level node priorities for mobile column toggle, set attribute data-priority or call Node API. For example,

	Product,UOM,Attributes[data-property="attributes",data-priority="2"]
or

	attributesNode.setPriority(2);

Row Expansion

If there are too many properties to show in entity list table, some properties can be moved to expansion row:

	EntityListViewConfig viewConfig = new EntityListViewConfig(ViewType.ENTITY_LIST_WIDE);
	viewConfig.setRowExpansionSupported(true);
	RowExpansion rowExpansion = new RowExpansion(new String[]{"hiredDate", "type"}, Layout.FLOW);
	viewConfig.setRowExpansion(rowExpansion);

Newspaper Columns

The number of newspaper columns is the number of entities to show per row. default is 1.

For example, 9 entities: 1, 2, 3, 4, 5, 6, 7, 8, 9. If newspaper columns is 1: one entity per row. If newspaper columns is 2(two entities per row), the 9 entities will shown as following:


horizontal orientation:
  1  2
  3  4
  5  6
  7  8
  9
vertical orientation:
  1  6
  2  7
  3  8
  4  9
  5   

RowEntityView

In rowEntityView, an EntityBackingBean will be created for each entity in the entity list of current page. To enable rowEntityView using ViewConfig, and layout the entities of current page in tab view:

	EntityListViewConfig viewConfig = new EntityListViewConfig(ViewType.ENTITY_LIST_WIDE);
	viewConfig.setLayoutType(LayoutType.ROW_ENTITY_VIEW);
	viewConfig.setRowEntityViewLayoutType(RowEntityViewLayoutType.TAB_VIEW);

List View

In list view, HTML UL and LI tags are used to display a list of entities with each list item for one entity.

	<ul>
		<li>Entity A</li>
		<li>Entity B</li>
	</ul>
The layout of entity properties on each list item can be specified with listItemLayoutCode of entity list viewConfig. For example,

	EntityListViewConfig viewConfig = new EntityListViewConfig(ViewType.ENTITY_LIST_WIDE);
	viewConfig.setLayoutType(LayoutType.LIST_VIEW);
	String listItemLayoutCode = "#{selected}" +
		"<span class=\"ui-li-column\">#{photos}</span>" +
		"<span class=\"ui-li-column ui-li-last-column\">" + 
			"#{nid} #{name}<br/>" + 
			"#{type}, #{hiredDate}<br/>" + 
			"#{department}<br/>" + 
			"#{rowCommands}" +
		"</span>";
	viewConfig.setListItemLayoutCode(listItemLayoutCode);

Table Reflow and Column Toggle

For mobile, entity list responsive table layout can be reflow or column toggle. In table reflow mode, when device width is less than a certain width(for example, 35em), the table will be shown in stacked style. In column toggle mode, a column will be shown or hidden depending on device width and its priority.

For column toggle mode, column priorities can be set in property descriptors in ViewConfig. For example,


	EntityListViewConfig viewConfig = entityListBackingBean.getViewConfig();
	PropertyDescriptor pd = viewConfig.getPropertyDescriptor("type", true, false);
	pd.setPriority(3);
Or configure property priorities in viewConfig XML for embedded objects. For example,

	<viewConfig>
		...
		<property name="type">
			<priority>3</priority>
		</property>
	</viewConfig>
To set priorities for custom headers, see Column Headers.

Valid priority is a number from 1 to 6, and a smaller number has a higher priority. By default, the first three columns are assigned to property 1 and every two subsequent columns will be assigned a different bigger priority number. For example,


	Column1(1)  Column(1)  Column3(1)  Column4(2)   Column5(2)   Column6(3)  ...
The numbers in parentheses are priority values. The entity selection column will be assigned the lowest priority. If the entity list is for entity selection, the row command column with select command will be assigned the highest priority(1).

When device width becomes larger, the columns with higher priorities(smaller numbers) will be visible before those with lower priorities become visible by CSS media query. If the resulting table is too wide and clipped by device screen, those columns with lower priorities will be hidden until all the table columns are fully visible.

To customize reflow breakpoint and column toggle responsiveness, write custom style classes using CSS media query. See jQuery mobile documentation for detail.

Pagination

Entity list pagination can be controlled by its ViewConfig:

	EntityListViewConfig viewConfig = new EntityListViewConfig(ViewType.ENTITY_LIST_WIDE);
	viewConfig.setPageable(true);
	viewConfig.setPageSize(30);
Show all entities in one page, not pageable:

	viewConfig.setPageable(false);
	viewConfig.setPageSize(null);
The paginator of an EntityListBackingBean will be enabled only if its entity list is pageable. Pagination can also be achieved by calling the following methods:

	EntityListBackingBean entityListBackingBean = ...
	entityListBackingBean.firstPage();
	entityListBackingBean.lastPage();
	entityListBackingBean.nextPage();
	entityListBackingBean.previousPage();
	entityListBackingBean.jumpToPage(5);
Every time pagination occurs, entities are added or deleted from the entity list, the EntityBackingBean.paginationChanged(...) will be called.
	
	public void paginationChanged(EntityListBackingBean<T> entityListBackingBean, 
		Integer pageCount, int currentPageIndex, PaginationChangeReason reason) throws SystemException;

Page Listener

After a page is loaded from persistence, the EntityListBackingBean will be notified by calling the following method of its EntityBackingBean.

	protected <Q> void pageRetrievedFromPersistence(EntityListBackingBean<T> entityListBackingBean, 
		QueryCriteria<Q, T> criteria, int pageIndex, Integer pageIndexBeforeChange, 
		PageableEntityList<T> pageableEntityList) throws SystemException;
For example, display the total expenses of each employee when showing a list of employees.

	@Override
	protected void pageRetrievedFromPersistence(EntityListBackingBean<Employee> entityListBackingBean, 
		QueryCriteria<Employee, Employee> criteria, int pageIndex, Integer pageIndexBeforeChange, 
		PageableEntityList<Employee> pageableEntityList) throws SystemException {
      
		List<Employee> employees = pageableEntityList.getPageEntityList();
		for (Employee employee : employees) {
			BigDecimal totalExpense = ...; // calculate expenses for employee 	     	
		}
  	}

Export To XML

All the entities of all pages can be exported as XML for download if enabled. The exported entities XML can be imported back to the same or a different instance(system or subsystem) if entity references can be resolved.

See Entity Export/Import for detail.

Export To Excel

The entity list of all the pages can be exported as Excel if user has the permission. Its access control can be described in XML ac.xml statically or in viewConfig dynamically. Note that: the Excel file can not be imported back to system.