a suite of UI Components for development of web apps
If you have any questions, don't hesitate to contact us at support@lidorsystems.com
Advanced User Interface Controls and Components
Created: 30 Sep 2019
In most cases, data fields that you are using may be different from the ones used by the IntegralUI ListView component for Angular. To solve this, you need to map the names of your data objects to the ones that are already in use by the ListView. This articles presents a demo how to do that using a custom JSON data.
If you have any questions, don't hesitate to contact us at support@lidorsystems.com
In this example, the ListView shows items in a way similar to the Tools view in Acrobat Reader. Each item has an icon, title and a dropdown menu with different options. The LIstView is populated from a JSON file with data that includes items in whole: that is an icon, label and content of the dropdown menu.
When your data has different field names, prior populating the ListView you need to map the data fields with the ones that are already in use. This is only required field names that are already predefined, like id, text etc. For example, if your items use a 'name' field instead of 'text' field (both a related to displaying item label), than you need to map it.
Data binding is simple; you can use the dataFields property of the angular ListView component. This property accepts an object that replaces the default field names with your own. First, here is a list of fields that are already in use (as predefined):
dataFields = {
allowDrag: 'allowDrag',
allowDrop: 'allowDrop',
allowEdit: 'allowEdit',
allowFocus: 'allowFocus',
canSelect: 'canSelect',
enabled: 'enabled',
expanded: 'expanded',
icon: 'icon',
id: 'id',
selected: 'selected',
style: 'style',
text: 'text',
value: 'value',
visible: 'visible'
}
For most of these field names, you don't need a data binding. The most important ones are id, text and value. These fields are related to the item unique identifier, its label and custom object as its value. Text and value fields are also important for sorting.
In this example, we have a JSON data where the most used field names: id and text are changed with new names. As you can see from code, the listFields object replaces the id to itemId, text to label. There are also custom data fields, like dropdown that holds information about the dropdown menu.
public listFields: any = {
icon: 'icon',
id: 'itemId',
text: 'label'
}
<div class="app-block" #application>
<iui-listview [controlStyle]="ctrlStyle" [dataFields]="listFields" [items]="items" (selectionChanged)="itemSelected($event)" #listview>
<iui-listitem [controlStyle]="itemStyle" *ngFor="let item of items" [data]="item" [controlStyle]="itemStyle">
<div class="lview-dfjson-item-content">
<div class="lview-dfjson-item-top-content">
<div class="lview-dfjson-item-icon">
<span class="lview-dfjson-icons {{item.icon}}"></span>
</div>
<span class="lview-dfjson-item-label">{{item.label}}</span><br />
</div>
<div class="lview-dfjson-item-dropdown">
<iui-dropdown-button [controlStyle]="dropDownStyle" [direction]="dropDownDirection" [settings]="item.dropdown" (itemClick)="dropDownItemClicked($event, item)">{{item.dropdown.label}}</iui-dropdown-button>
</div>
</div>
</iui-listitem>
</iui-listview>
</div>
Note Note When a new field names are in use, you also need to update the item template to reflect the change. Template is based on the item object from your data source.
Once we have the data binding set up, you can load the data from the JSON file in the angular ListView. For this purpose, you can use the angular http service, like in this example.
The demo above presents a ListView component with a list of items where each item displays an icon, label and a dropdown menu at the bottom. All items are arranged in horizontal layout, which means scrolling is only horizontal. The dropdown menu is customizable, you can have a different one for each item or share it.
Note Note Once the data is retrieved from a local or remote JSON file, prior loading it in the ListView component it is a good practice to suspend any updates of the component layout. This increases the loading performance.
private loadFromJSON(){
let self = this;
// Use HTTP service to get data from the specified JSON file
self.http.get("./assets/file.json").subscribe((data: Array) => {
// Suspend the tree layout from updates, to increase performance
self.listview.suspendLayout();
// Load data into the list view
self.listview.loadData(data, self.listFields);
// Or , you can apply the new data to the items property directly (commented out)
// self.items = data;
self.items.map(item => {
if (item.dropdown){
item.dropdown.appRef = this.applicationRef;
}
});
// Resume and update the tree layout
self.listview.resumeLayout();
});
}
[
{ "itemId": 1, "label": "Comment", "icon": "notes", "dropdown": { "adjustment": { "top": 2, "left": 80 }, "label": "Open", "items": [{ "text": "Open" }, { "text": "Learn More" }] } },
{ "itemId": 2, "label": "Protect", "icon": "shield", "dropdown": { "adjustment": { "top": 2, "left": 86 }, "label": "Add", "items": [{ "text": "Add" }, { "text": "Learn More" }] } },
// . . .
//
// You can find the full content of this file in sample project on StackBlitz: https://stackblitz.com/edit/integralui-listview-data-fields-json
To load the data into the ListView, you can use the built-in loadData method or set the new data directly to the items property. At last, you need to update the component layout to reclect the changes. You can do this with updateLayout method or if the layout is previously suspended, to resume it use the resumeLayout method.
As a dropdown menu, in this case we are using the IntegralUI DropDown directive. This directive is attachable to any element or component and allows you to display a popup window with custom content: it can be a list or a panel that can contain any custom HTML elements arranged in layout defined by a template on your side.
The most important setting here is the appRef field of the dropdown object. This field must contain a reference to the top element in your app, so that the popup content appears on top of all other elements. As you can see from the code, you can get this reference by providing a variable name in the top div element and then use the angular ViewContainerRef to get a reference to it.
@ViewChild('application', {read: ViewContainerRef}) applicationRef: ViewContainerRef;
ngAfterViewInit(){
// Load data into the ListView from a JSON file
this.loadFromJSON();
this.dropDownSettings = {
adjustment: { top: 1, left: 30 },
appRef: this.applicationRef
}
}
dropDownItemClicked(e: any, obj: any){
console.log(e.item.text + " is clicked from item: ", obj);
}
<div class="app-block" #application>
<iui-listview [controlStyle]="ctrlStyle" [dataFields]="listFields" [items]="items" (selectionChanged)="itemSelected($event)" #listview>
<iui-listitem [controlStyle]="itemStyle" *ngFor="let item of items" [data]="item" [controlStyle]="itemStyle">
<div class="lview-dfjson-item-content">
<div class="lview-dfjson-item-top-content">
<div class="lview-dfjson-item-icon">
<span class="lview-dfjson-icons {{item.icon}}"></span>
</div>
<span class="lview-dfjson-item-label">{{item.label}}</span><br />
</div>
<div class="lview-dfjson-item-dropdown">
<iui-dropdown-button [controlStyle]="dropDownStyle" [direction]="dropDownDirection" [settings]="item.dropdown" (itemClick)="dropDownItemClicked($event, item)">{{item.dropdown.label}}</iui-dropdown-button>
</div>
</div>
</iui-listitem>
</iui-listview>
</div>
Data binding in IntegralUI ListView for Angular is simple. When your data source uses different names from the ones used by the list view, you can map your data fields by providing an object that matches the data names. This allows you to keep the format of your data intact and populate the ListView component from local or remote data source.
The ListView component is part of IntegralUI Web.