Create dual list in EJ2 JavaScript ListView Control

1 Mar 202519 minutes to read

The dual list configuration involves two ListView controls, allowing for list items to be transferred between lists using client-side events. This section explains how to integrate ListView controls to achieve a dual list.

Use cases

Dual lists can be utilized in scenarios such as:

  • Stock exchanges of two different countries.
  • Job applications (skill sets).

Integration of Dual List

To implement a dual list, two ListView controls are used to display items. The interface uses an ej2-button for transferring data between lists and a textbox for filtering support.

Key features of the dual list include:

  • Transferring all items from one list to another.
  • Transferring selected items from one list to another.
  • Filtering lists using input from a textbox.

In the ListView control, sorting is enabled using the sortOrder property, and the select event is triggered when an item is selected. The select event manages the enabling and disabling of buttons based on the item selection.

Manipulating data

Moving entire data from the first list to the second list (>>)

All items can be transferred from the first ListView to the second by clicking the designated button. When clicked, all items from the first list are concatenated with the second ListView’s data source. This button is active only when the first ListView has items.

Moving entire data From the second list to the first list (<<)

This button performs the reverse action, transferring all items from the second ListView to the first. It is active only when the second ListView has items.

Transferring selected items (> and <)

The Select event facilitates transferring selected items between lists. These buttons are enabled when an item is selected in either list.

Filtering method

A filtering method allows you to filter list items by typing characters into a textbox. This feature utilizes the dataManager to fetch and display filtered data in the ListView.

Sorting

Using the dual list, list items can be sorted in the ListView using the sortOrder property. Enabling sorting in one ListView allows the data to be transferred in the same order to the other ListView.

//Define an array of JSON data
var firstListData = [
    { text: 'Hennessey Venom', id: 'list-01' },
    { text: 'Bugatti Chiron', id: 'list-02' },
    { text: 'Bugatti Veyron Super Sport', id: 'list-03' },
    { text: 'SSC Ultimate Aero', id: 'list-04' },
    { text: 'Koenigsegg CCR', id: 'list-05' },
    { text: 'McLaren F1', id: 'list-06' },

];

var secondListData = [
    { text: 'Aston Martin One- 77', id: 'list-07' },
    { text: 'Jaguar XJ220', id: 'list-08' },
    { text: 'McLaren P1', id: 'list-09' },
    { text: 'Ferrari LaFerrari', id: 'list-10' },
];


// Initialize the ListView component
var listObj1 = new ej.lists.ListView({

    //Set the defined data to the dataSource property
    dataSource: firstListData.slice(),

    //Map the appropriate columns to the fields property
    fields: { text: 'text', id: 'id' },
    sortOrder: 'Ascending',
    select: onFirstListSelect

});

//Render the initialized ListView component
listObj1.appendTo('#list-1');

var listObj2 = new ej.lists.ListView({

    //Set the defined data to the dataSource property
    dataSource: secondListData.slice(),

    //Map the appropriate columns to the fields property
    fields: { text: 'text', id: 'id' },
    sortOrder: 'Ascending',
    select: onSeconListSelect

});

//Render the initialized ListView component
listObj2.appendTo('#list-2');

var btnobj1 = new ej.buttons.Button();
btnobj1.appendTo('#firstBtn');

var btnobj2 = new ej.buttons.Button({
    disabled: true
});
btnobj2.appendTo('#secondBtn');

var btnobj3 = new ej.buttons.Button({
    disabled: true
});
btnobj3.appendTo('#thirdBtn');

var btnobj4 = new ej.buttons.Button();
btnobj4.appendTo('#fourthBtn');


//Here, all list items are moved to the second list on clicking move all button
btnobj1.element.addEventListener('click', function () {
    listObj2.dataSource = Array.prototype.concat.call(listObj1.dataSource, listObj2.dataSource);
    listObj2.dataBind();
    updateFirstListData();
    listObj1.removeMultipleItems(Array.prototype.slice.call(listObj1.element.querySelectorAll('.e-list-item')));
    firstListData = firstListData.concat(listObj1.dataSource);
    secondListData = listObj2.dataSource.slice();
    btnobj1.disabled = true;
    onFirstKeyUp();
    setButtonState();
});

//Here, the selected list items are moved to the second list on clicking move button
btnobj2.element.addEventListener('click', function () {
    var selectedItem = listObj1.getSelectedItems();
    listObj2.dataSource = Array.prototype.concat.call(listObj2.dataSource, selectedItem.data);
    listObj2.dataBind();
    updateFirstListData();
    listObj1.removeItem(selectedItem.item);
    firstListData = firstListData.concat(listObj1.dataSource);
    secondListData = listObj2.dataSource.slice();
    onFirstKeyUp();
    btnobj2.disabled = true;
    setButtonState();
});

//Here, the selected list items are moved to the first list on clicking move button
btnobj3.element.addEventListener('click', function () {
    var selectedItem = listObj2.getSelectedItems();
    listObj1.dataSource = Array.prototype.concat.call(listObj1.dataSource, selectedItem.data);
    listObj1.dataBind();
    updateSecondListData();
    listObj2.removeItem(selectedItem.item);
    secondListData = secondListData.concat(listObj2.dataSource);
    firstListData = listObj1.dataSource.slice();
    onSecondKeyUp();
    btnobj3.disabled = true;
    setButtonState();

});

//Here, all list items are moved to the first list on clicking move all button
btnobj4.element.addEventListener('click', function () {
    listObj1.dataSource = Array.prototype.concat.call(listObj1.dataSource, listObj2.dataSource);
    listObj1.dataBind();
    updateSecondListData();
    listObj2.removeMultipleItems(Array.prototype.slice.call(listObj2.element.querySelectorAll('.e-list-item')));
    secondListData = secondListData.concat(listObj2.dataSource);
    firstListData = listObj1.dataSource.slice();
    onSecondKeyUp();
    setButtonState();

});

//Here, the ListView data source is updated to the first list
function updateFirstListData() {
    Array.prototype.forEach.call(listObj1.element.querySelectorAll('.e-list-item'), function (list) {
        firstListData.forEach(function (data, index) {
            if (list.innerText.trim() === data.text) {
                firstListData.splice(index, 1)
            }
        });
    });
    (document.getElementById("firstInput")).value = '';
    var ds = [];
    firstListData.forEach(function (data) {
        ds.push(data);
    })
    firstListData = ds;

}

//Here, the ListView dataSource is updated for the second list
function updateSecondListData() {
    Array.prototype.forEach.call(listObj2.element.querySelectorAll('.e-list-item'), function (list) {
        secondListData.forEach(function (data, index) {
            if (list.innerText.trim() === data.text) {
                secondListData.splice(index, 1)
            }
        });

    });
    document.getElementById("secondInput").value = '';
    var ds = [];
    secondListData.forEach(function (data) {
        ds.push(data);
    })
    secondListData = ds;

}
function onFirstListSelect() {
    btnobj2.disabled = false;
}
function onSeconListSelect() {
    btnobj3.disabled = false;
}
document.getElementById('firstInput').addEventListener('keyup', onFirstKeyUp);
//Here, filtering is handled using the dataManager for the first list
function onFirstKeyUp() {
    var value = document.getElementById("firstInput").value;
    var data = new ej.data.DataManager(firstListData).executeLocal(new ej.data.Query().where('text', 'startswith', value, true));
    if (!value) {
        listObj1.dataSource = firstListData.slice();
    } else {
        listObj1.dataSource = data;
    }
    listObj1.dataBind();

}
document.getElementById('secondInput').addEventListener('keyup', onSecondKeyUp);
//Here, filtering is handled using the dataManager for the second list
function onSecondKeyUp() {
    var value = document.getElementById("secondInput").value;
    var data = new ej.data.DataManager(secondListData).executeLocal(new ej.data.Query().where('text', 'startswith', value, true));
    if (!value) {
        listObj2.dataSource = secondListData.slice();
    } else {
        listObj2.dataSource = data;
    }
    listObj2.dataBind();
}

//Here, the state of the button is changed
function setButtonState() {
    if (listObj1.dataSource.length) {
        btnobj1.disabled = false;
    } else {
        btnobj1.disabled = true;
        btnobj2.disabled = true;
    }

    if (listObj2.dataSource.length) {
        btnobj4.disabled = false;
    } else {
        btnobj4.disabled = true;
        btnobj3.disabled = true;
    }

}
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Essential JS 2 for ListView </title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Essential JS 2 for ListView UI Control">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-base/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-lists/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-buttons/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-inputs/styles/material.css" rel="stylesheet">
    <script src="https://cdn.syncfusion.com/ej2/30.1.37/dist/ej2.min.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>

    <div id="container">
        <h3>Dual List</h3>
        <div class="list_container">
            <div id="list_container_1">
                <input class="e-input" type="text" id="firstInput" placeholder="  Filter" title="Type in a name">
                <div id="list-1"></div>
            </div>
            <div id="btn">
                <button id="firstBtn"> &gt;&gt; </button>
                <button id="secondBtn"> &gt; </button>
                <button id="thirdBtn">
                    &lt; </button>
                <button id="fourthBtn">
                    &lt;&lt; </button>
            </div>
            <div id="list_container_2">
                <input class="e-input" type="text" id="secondInput" placeholder="  Filter" title="Type in a name">
                <div id="list-2"></div>
            </div>
        </div>
    </div>

    <script>
        var ele = document.getElementById('container');
        if (ele) {
            ele.style.visibility = "visible";
        }   
    </script>
    <script src="index.js" type="text/javascript"></script>
    <style>
        .list_container {
            height: 398px;
            max-width: 485px;
            margin: auto;
        }

        #list_container_1,
        #list_container_2 {
            width: 200px;
        }

        #list-1,
        #list-2 {
            height: 362px;
            border: 1px solid #dddddd;
            border-radius: 3px;
        }

        #list_container_1,
        #list_container_2 {
            display: inline-block;
        }

        .e-btn {
            margin-bottom: 15px;
            width: 40px;
            height: 40px;
        }

        #btn {
            display: inline-block;
            width: 41px;
            margin: 0 15px;
            position: relative;
            top: -53%;
            transform: translateY(50%);
        }
    </style>
</body>

</html>
#container {
    visibility: hidden;
}

#loader {
  color: #008cff;
  height: 40px;
  width: 30%;
  position: absolute;
  font-family: 'Helvetica Neue','calibiri';
  font-size: 14px;
  top: 45%;
  left: 45%;
}