MultiSelect with customized items

The MultiSelect allows you to customize the display of the items in the drop-down list. This sample applies custom HTML to each item in the drop-down, providing more information to the end user and the selection. The first input element with type="checkbox" in the item content will be used to change a checked state of the item.

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import * as wijmo from '@grapecity/wijmo'; import * as input from '@grapecity/wijmo.input'; import { getData } from './data'; // document.readyState === 'complete' ? init() : window.onload = init; // function init() { // define template for the details var template = '<div class="item">' + '<label><input type="checkbox"/>{name}</label><br/>' + '<b>{city}</b> ({state})<br/>' + '{address}<br/>' + 'Phone: <b>{phone}</b><br/>' + 'Fax: <b>{fax}</b><br/>' + 'Website: <a href="{site}" target="_blank">{site}</a><br/>' + '</div>'; // // show items in a MultiSelect let theCombo = new input.MultiSelect('#theMultiSelect', { displayMemberPath: 'name', headerPath: 'name', itemsSource: getData(), placeholder: 'Companies', formatItem: (sender, e) => { let html = wijmo.format(template, e.data, (data, name, fmt, val) => { return wijmo.isString(data[name]) ? wijmo.escapeHtml(data[name]) : val; }); e.item.innerHTML = html; }, checkedItemsChanged: (sender) => { let html = ''; sender.checkedItems.forEach((item) => { html += `<li>${item.name}</li>`; }); document.querySelector('#checkedItems').innerHTML = html; } }); // // toggle 'select all' checkbox document.querySelector('#selectAll').addEventListener('click', e => { theCombo.showSelectAllCheckbox = e.target.checked; }); } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity ComboBox with HTML Content</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div class="container-fluid"> <p> This MultiSelect uses a <b>formatItem</b> event to customize the display of the items in the drop-down list. </p> <div class="row"> <div class="col-xs-5"> <div class="form-group"> <div id="theMultiSelect"></div> </div> <div class="form-group"> <label> Show "Select All" box <input id="selectAll" type="checkbox"> </label> </div> </div> <div class="col-xs-7"> <p> <b>Checked Items:</b> </p> <ul id="checkedItems"> </ul> </div> </div> </div> </body> </html> // // some data to show in our accordion export function getData() { return [{ name: 'Electro Mart', city: 'Accident', state: 'Maryland', address: '8785 Windfall St.', phone: '(800) 555-1234', fax: '(800) 555-5678', site: 'https://www.electromartnot.com' }, { name: 'Sue\'s Depot', city: 'Big Arm', state: 'Montana', address: '77 Winchester Lane', phone: '(800) 555-2345', fax: '(800) 555-6789', site: 'https://www.suesdepotnot.com' }, { name: 'D&K Digital Locker', city: 'Chicken', state: 'Alaska', address: '787 Lakeview St. ', phone: '(800) 555-3456', fax: '(800) 555-7890', site: 'https://www.digilockernot.com' }, { name: 'Paul\'s Pub & Bistro', city: 'Coupon', state: 'Pennsylvania', address: '711 Old York Drive ', phone: '(800) 555-0987', fax: '(800) 555-6543', site: 'https://www.paulspubnot.com' }, { name: 'Amazing Deals Inc', city: 'Cut And Shoot', state: 'Texas', address: '91 Beech St.', phone: '(800) 955-2109', fax: '(800) 955-8765', site: 'https://www.amazingdealsnot.com' }]; } body { margin-bottom: 24pt; } .item { margin: 8px; font-size: 80%; } .item label { display: inline-flex; } .item input[type=checkbox] { margin: 0px; } .wj-listbox-item h1 { font-size: 12pt; font-weight: bold; margin: 4px -8px; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import * as wijmo from '@grapecity/wijmo'; import * as input from '@grapecity/wijmo.input'; // import { Component, enableProdMode, NgModule, Inject } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { FormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { WjInputModule } from '@grapecity/wijmo.angular2.input'; import { DataService } from './app.data'; // @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { data: any[]; // constructor(@Inject(DataService) private dataService: DataService) { this.data = dataService.getData(); } } // @NgModule({ imports: [WjInputModule, BrowserModule, FormsModule], declarations: [AppComponent], providers: [DataService], bootstrap: [AppComponent] }) export class AppModule { } // enableProdMode(); // Bootstrap application with hash style navigation and global services. platformBrowserDynamic().bootstrapModule(AppModule); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity ComboBox with HTML Content</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Polyfills --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.min.js"></script> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.js"></script> <script src="systemjs.config.js"></script> <script> // workaround to load 'rxjs/operators' from the rxjs bundle System.import('rxjs').then(function (m) { System.set(SystemJS.resolveSync('rxjs/operators'), System.newModule(m.operators)); System.import('./src/app.component'); }); </script> </head> <body> <app-component></app-component> </body> </html> <div class="container-fluid"> <p> This MultiSelect uses a <b>wjItemTemplate</b> directive to customize the display of the items in the drop-down list. </p> <div class="row"> <div class="col-xs-5"> <div class="form-group"> <wj-multi-select #theMultiSelect [placeholder]="'Companies'" [headerFormat]="'{count:n0} companies'" [displayMemberPath]="'name'" [headerPath]="'name'" [itemsSource]="data"> <ng-template wjItemTemplate let-item="item" let-itemIndex="itemIndex"> <div class="item"> <label><input type="checkbox"/> {{item.name}}</label><br/> <b>{{item.city}}</b> ({{item.state}})<br/> {{item.address}}<br/> Phone: <b>{{item.phone}}</b><br/> Fax: <b>{{item.fax}}</b><br/> Website: <a href="{{item.site}}" target="_blank">{{item.site}}</a><br/> </div> </ng-template> </wj-multi-select> </div> <div class="form-group"> <label> Show "Select All" box <input id="selectAll" type="checkbox" [(ngModel)]="theMultiSelect.showSelectAllCheckbox"> </label> </div> </div> <div class="col-xs-7"> <p> <b>Checked Items:</b> </p> <ul> <li *ngFor="let item of theMultiSelect.checkedItems"> {{ item.name }} </li> </ul> </div> </div> </div> import { Injectable } from '@angular/core'; // @Injectable() export class DataService { getData() { return [{ name: 'Electro Mart', city: 'Accident', state: 'Maryland', address: '8785 Windfall St.', phone: '(800) 555-1234', fax: '(800) 555-5678', site: 'https://www.electromartnot.com' }, { name: 'Sue\'s Depot', city: 'Big Arm', state: 'Montana', address: '77 Winchester Lane', phone: '(800) 555-2345', fax: '(800) 555-6789', site: 'https://www.suesdepotnot.com' }, { name: 'D&K Digital Locker', city: 'Chicken', state: 'Alaska', address: '787 Lakeview St. ', phone: '(800) 555-3456', fax: '(800) 555-7890', site: 'https://www.digilockernot.com' }, { name: 'Paul\'s Pub & Bistro', city: 'Coupon', state: 'Pennsylvania', address: '711 Old York Drive ', phone: '(800) 555-0987', fax: '(800) 555-6543', site: 'https://www.paulspubnot.com' }, { name: 'Amazing Deals Inc', city: 'Cut And Shoot', state: 'Texas', address: '91 Beech St.', phone: '(800) 955-2109', fax: '(800) 955-8765', site: 'https://www.amazingdealsnot.com' }]; } } body { margin-bottom: 24pt; } .item { margin: 8px; font-size: 80%; } .item label { display: inline-flex; } .item input[type=checkbox] { margin: 0px; } .wj-listbox-item h1 { font-size: 12pt; font-weight: bold; margin: 4px -8px; } <template> <div class="container-fluid"> <p> This MultiSelect uses a <b>formatItem</b> event to customize the display of the items in the drop-down list. </p> <div class="row"> <div class="col-xs-5"> <div class="form-group"> <wj-multi-select :displayMemberPath="'name'" :placeholder="'Countries'" :headerPath="'name'" :itemsSource="data" :initialized='initMultiSelect' :checkedItemsChanged='onCheckedItemsChanged' :format-item="formatItem"> </wj-multi-select> </div> <div class="form-group"> <label> Show "Select All" box <input id="selectAll" type="checkbox" v-model="theMultiSelect.showSelectAllCheckbox"> </label> </div> </div> <div class="col-xs-7"> <p> <b>Checked Items:</b> </p> <ul> <li v-for="item of checkedItems" :key="item"> {{ item.name }} </li> </ul> </div> </div> </div> </template> <script> import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import Vue from 'vue'; import '@grapecity/wijmo.vue2.core'; import '@grapecity/wijmo.vue2.input'; import * as wijmo from '@grapecity/wijmo'; import { getData } from './data'; let App = Vue.extend({ name: 'app', data: function () { return { data: getData(), theMultiSelect: {}, checkedItems: [], multiSelectTableItemTemplate: '<div class="item">' + '<label><input type="checkbox"/>{name}</label><br/>' + '<b>{city}</b> ({state})<br/>' + '{address}<br/>' + 'Phone: <b>{phone}</b><br/>' + 'Fax: <b>{fax}</b><br/>' + 'Website: <a href="{site}" target="_blank">{site}</a><br/>' + '</div>' } }, methods: { formatItem: function(sender, e){ let html = wijmo.format(this.multiSelectTableItemTemplate, e.data, (data, name, fmt, val) => { return wijmo.isString(data[name]) ? wijmo.escapeHtml(data[name]) : val; }); e.item.innerHTML = html; }, onCheckedItemsChanged: function(s){ this.checkedItems = s.checkedItems; }, initMultiSelect: function(multiSelect){ this.theMultiSelect = multiSelect; }, } }) let vm = new Vue({ render: h => h(App) }).$mount('#app'); </script> <style> body { margin-bottom: 24pt; } .item { margin: 8px; font-size: 80%; } .item label { display: inline-flex; } .item input[type=checkbox] { margin: 0px; } .wj-listbox-item h1 { font-size: 12pt; font-weight: bold; margin: 4px -8px; } </style> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity ComboBox with HTML Content</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app.vue'); </script> </head> <body> <div id="app"></div> </body> </html> // some data to show in our accordion export function getData() { return [{ name: 'Electro Mart', city: 'Accident', state: 'Maryland', address: '8785 Windfall St.', phone: '(800) 555-1234', fax: '(800) 555-5678', site: 'https://www.electromartnot.com' }, { name: 'Sue\'s Depot', city: 'Big Arm', state: 'Montana', address: '77 Winchester Lane', phone: '(800) 555-2345', fax: '(800) 555-6789', site: 'https://www.suesdepotnot.com' }, { name: 'D&K Digital Locker', city: 'Chicken', state: 'Alaska', address: '787 Lakeview St. ', phone: '(800) 555-3456', fax: '(800) 555-7890', site: 'https://www.digilockernot.com' }, { name: 'Paul\'s Pub & Bistro', city: 'Coupon', state: 'Pennsylvania', address: '711 Old York Drive ', phone: '(800) 555-0987', fax: '(800) 555-6543', site: 'https://www.paulspubnot.com' }, { name: 'Amazing Deals Inc', city: 'Cut And Shoot', state: 'Texas', address: '91 Beech St.', phone: '(800) 955-2109', fax: '(800) 955-8765', site: 'https://www.amazingdealsnot.com' }]; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './app.css'; // import * as React from 'react'; import * as ReactDOM from 'react-dom'; import * as wjInput from '@grapecity/wijmo.react.input'; import { getData } from './data'; // class App extends React.Component { constructor(props) { super(props); this.state = { data: getData(), showSelectAllCheckbox: false, checkedItems: [] }; } _changeShowSelectAll(value) { this.setState({ showSelectAllCheckbox: value }); } _onCheckedItemsChanged(sender) { this.setState({ checkedItems: sender.checkedItems }); } render() { return <div className="container-fluid"> <p> This MultiSelect uses a <b>wjItemTemplate</b> <i>render prop</i> to customize the display of the items in the drop-down list. </p> <div className="row"> <div className="col-xs-5"> <div className="form-group"> <wjInput.MultiSelect displayMemberPath="name" headerPath="name" placeholder="Countries" itemsSource={this.state.data} showSelectAllCheckbox={this.state.showSelectAllCheckbox} checkedItemsChanged={this._onCheckedItemsChanged.bind(this)} wjItemTemplate={(context) => (<div className="item"> <label><input type="checkbox"/>{context.item.name}</label> <br /> <b>{context.item.city}</b> ({context.item.state})<br /> {context.item.address}<br /> Phone: <b>{context.item.phone}</b><br /> Fax: <b>{context.item.fax}</b><br /> Website: <a href="{context.item.site}" target="_blank">{context.item.site}</a><br /> </div>)}> </wjInput.MultiSelect> </div> <div className="form-group"> <label htmlFor="selectAll">Show "Select All" box</label>{' '} <input id="selectAll" type="checkbox" defaultChecked={this.state.showSelectAllCheckbox} onChange={e => this._changeShowSelectAll(e.target.checked)}/> </div> </div> <div className="col-xs-7"> <p> <b>Checked Items:</b> </p> <ul> {this.state.checkedItems.map((item) => { return <li key={item.name}> {item.name} </li>; })} </ul> </div> </div> </div>; } } ReactDOM.render(<App />, document.getElementById('app')); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity ComboBox with HTML Content</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div id="app"></div> </body> </html> body { margin-bottom: 24pt; } .item { margin: 8px; font-size: 80%; } .item label { display: inline-flex; } .item input[type=checkbox] { margin: 0px; } .wj-listbox-item h1 { font-size: 12pt; font-weight: bold; margin: 4px -8px; } export function getData() { return [{ name: 'Electro Mart', city: 'Accident', state: 'Maryland', address: '8785 Windfall St.', phone: '(800) 555-1234', fax: '(800) 555-5678', site: 'https://www.electromartnot.com' }, { name: 'Sue\'s Depot', city: 'Big Arm', state: 'Montana', address: '77 Winchester Lane', phone: '(800) 555-2345', fax: '(800) 555-6789', site: 'https://www.suesdepotnot.com' }, { name: 'D&K Digital Locker', city: 'Chicken', state: 'Alaska', address: '787 Lakeview St. ', phone: '(800) 555-3456', fax: '(800) 555-7890', site: 'https://www.digilockernot.com' }, { name: 'Paul\'s Pub & Bistro', city: 'Coupon', state: 'Pennsylvania', address: '711 Old York Drive ', phone: '(800) 555-0987', fax: '(800) 555-6543', site: 'https://www.paulspubnot.com' }, { name: 'Amazing Deals Inc', city: 'Cut And Shoot', state: 'Texas', address: '91 Beech St.', phone: '(800) 955-2109', fax: '(800) 955-8765', site: 'https://www.amazingdealsnot.com' }]; }