Creating an Accordion Menu with JSON Result as Title for Similar Rows in jQuery UI Autocomplete

238 views Asked by At

I'm trying to create an accordion menu using jQuery UI Autocomplete with the JSON result. The JSON object items contains data with label, name, and value properties. I want to group similar name values together and use one of them as the title for the accordion section.

Here is my HTML code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>CatComplete</title>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-4" id="all-list">
                <label for="search">Search:</label>
                <input id="search" class="form-control" />
                <div class="list-group panel" id="accordion"></div>
            </div>
        </div>
    </div>
</body>
</html>

And this is my JavaScript code:

var items = [
    {label: "TY2021H", name: "10-Yr T-Notes", value: "TY2021H"},
    {label: "TY2020Z-TY2021H", name: "10-Yr T-Notes Spread", value: "TY2020Z-TY2021H"},
    {label: "TY2021H-TY2021M", name: "10-Yr T-Notes Spread", value: "TY2021H-TY2021M"},
    {label: "TY2020Z-2*TY2021H+TY2021M", name: "10-Yr T-Notes Butterfly", value: "TY2020Z-2*TY2021H+TY2021M"}
];


var myUL = $("#accordion");
myUL.empty();
var currentName = "";
for (var i = 0; i <= items.length - 1; i++) {
    var label = items[i].label;
    if (items[i].name != currentName) {
        currentName = items[i].name;
        list +=
            '<a href="#demo' +
            i +
            '" class="list-group-item list-group-item-info" data-toggle="collapse" data-parent="#accordion">' +
            currentName +
            ' <span id="opnClsSign" class="glyphicon glyphicon-menu-down"></span></a>';
        list += '<div class="collapse in" id="demo' + i + '">';
    }

    list += '<a href="#" class="list-group-item">' + label + "</a>";

}
list += "</div>";
myUL.append(list);

The current implementation creates an accordion with the items from the JSON object. However, the accordion titles should be based on the unique name values, and each section should contain items with the same name. Currently, it doesn't group the items correctly.

Result I get now enter image description here

What I expect enter image description here

How can I modify the JavaScript code to achieve this behavior and create an accordion menu with the appropriate titles for each group? Any insights or suggestions would be greatly appreciated. Thank you!

2

There are 2 answers

0
RCode On BEST ANSWER

I was able to resolve the issue myself, and I've included the final source code here:

var items = [
    { label: "TY2021H", name: "10-Yr T-Notes", value: "TY2021H" },
    { label: "TY2022H", name: "10-Yr T-Notes", value: "TY2022H" },
    { label: "TY2023H", name: "10-Yr T-Notes", value: "TY2023H" },
    { label: "TY202H", name: "10-Yr T-Notes", value: "TY2024H" },
    { label: "TY2020Z-TY2021H", name: "10-Yr T-Notes Spread", value: "TY2020Z-TY2021H" },
    { label: "TY2021H-TY2021M", name: "10-Yr T-Notes Spread", value: "TY2021H-TY2021M" },
    { label: "TY2022H-TY2023M", name: "10-Yr T-Notes Spread", value: "TY2022H-TY2023M" },
    { label: "TY2020Z-2*TY2021H+TY2021M", name: "10-Yr T-Notes Butterfly", value: "TY2020Z-2*TY2021H+TY2021M" }]
let finalData = items;

$(function () {
    $.widget("custom.catcomplete", $.ui.autocomplete, {
        _renderMenu: function (ul, items) {
            var myUL = $("#accordion");
            myUL.empty();
            var currentName = "";
            var list = "";
            let tobeClosed = -1;
            let nto = 0;
            var closeDiv = [];

            for (var i = 0; i <= items.length - 1; i++) {
                var label = items[i].label;

                if (items[i].name != currentName) {
                    nto++;
                    currentName = items[i].name;
                    list +=
                        '<a href="#demo' +
                        i +
                        '" class="list-group-item list-group-item-info" data-toggle="collapse" data-parent="#accordion">' +
                        currentName +
                        ' <span id="opnClsSign" class="glyphicon glyphicon-menu-down"></span></a>';
                    list += '<div class="collapse in" id="demo' + i + '">';
                    list +=
                        '<a href="#" class="list-group-item">' + label + "</a>";
                } else {
                    list +=
                        '<a href="#" class="list-group-item">' + label + "</a>";

                    if (items[i + 1] && items[i + 1].name != currentName) {
                        if (i > 0) {
                            tobeClosed = i + nto;
                            if (tobeClosed == i + nto) {
                                list += "</div>";
                            }
                        }
                    }
                }
            }
            myUL.append(list);
        },
    });

    $("#search").catcomplete({
        delay: 0,
        minLength: 2,
        source: finalData,
        response: function (event, ui) {
            if (ui.content.length === 0) {
                $("#accordion").empty();
                $("#accordion").append(
                    '<div class="alert alert-danger">No Results!</div>'
                );
            }
        },
    });
});

$(document).ready(function () {
    $("#search").keyup(function () {
        if ($("#search").val() == "") {
            $("#accordion").empty();
        }
    });
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>CatComplete</title>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
  </head>
  <body>
    <div class="container">
      <div class="row">
        <div class="col-md-4" id="all-list">
          <label for="search">Search:</label>
          <input id="search" class="form-control" />
          <div class="list-group panel" id="accordion"></div>
        </div>
      </div>
    </div>
  </body>
</html>

Feel free to check it out! If you have any questions or need further assistance, don't hesitate to ask. Happy coding!

1
vqf On

Code indentation can help in a situation like this. Your last two lines should be inside the loop for the code to make sense. In every iteration, you must close the div and add the code to myUL:

var items = [
    {label: "TY2021H", name: "10-Yr T-Notes", value: "TY2021H"},
    {label: "TY2020Z-TY2021H", name: "10-Yr T-Notes Spread", value: "TY2020Z-TY2021H"},
    {label: "TY2021H-TY2021M", name: "10-Yr T-Notes Spread", value: "TY2021H-TY2021M"},
    {label: "TY2020Z-2*TY2021H+TY2021M", name: "10-Yr T-Notes Butterfly", value: "TY2020Z-2*TY2021H+TY2021M"}]


var myUL = $("#accordion");
myUL.empty();
var currentName = "";    
for (var i = 0; i <= items.length - 1; i++) {
  var label = items[i].label;
  var list = '';
  if (items[i].name != currentName) {
    currentName = items[i].name;
    list +=
        '<a href="#demo' +
        i +
        '" class="list-group-item list-group-item-info" data-toggle="collapse" data-parent="#accordion">' +
        currentName +
        ' <span id="opnClsSign" class="glyphicon glyphicon-menu-down"></span></a>';
    list += '<div class="collapse in" id="demo' + i + '">';
  }

  list += '<a href="#" class="list-group-item">' + label + "</a>";
  list += "</div>";
  myUL.append(list);
}
  
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="list-group panel" id="accordion"></div>

Also, you needed to define list.