Jon H
Jon H

Reputation: 434

Cascading dropdown from HashMap in Thymeleaf Template

I am creating a Spring Boot JPA application with Thymeleaf templates in the front end. The application is used to manage a set of user skills which are organised into categories.

I need to create a cascading dropdown in a form where a category (e.g. Programming Languages, Admin, Project Management) is selected from a first dropdown and then a second dropdown displays the skills associated with that category. So if 'Programming Languages' was selected in the first dropdown, the options in the second dropdown box may be Java, Python, C++, etc. for example. This form will eventually be used to perform a search of users that have those skills.

In my controller, I create a map where the key is the category as a String and the value is a list of associated skills, where the Skill class is a Java data object containing the skill name and id: -

Map<String, List<Skill>> skillsMap = new HashMap();

I populate this map with all the category and skill information and add it to my Model. It contains all the info that will be required in the form: -

model.addAttribute("skillsMap", skillsMap);

In my view within a Thymeleaf template, I then retrieve this map from the model and start to build a form with it. This select successfully displays the categories: -

<select id="category">
    <option value="NONE">----Select----</option>
    <option th:each="entry : ${skillsMap.entrySet()}" th:value="${entry.key}"
        th:text="${entry.key}">
    </option>
</select>

The behaviour I want is that after I have made the category selection in the first dropdown, a second dropdown is then displayed with the skills from that category as options.

To achieve this, I have attempted to capture the value of the category dropdown in a JavaScript variable. This is in a script section at the bottom of the template below the form: -

<script>
$(document).ready(function() {
    $("#category").change(function() {
        var cat = $("#category").val();
    });
});
</script>

I reference the value of this variable 'cat' in a second select field: -

<select id="skill">
    <option value="NONE">----Select----</option>
    <option th:each="skill : ${skillsMap.get(cat)}" th:value="${skill.id}"
        th:text="${skill.name}">
    </option>
</select>

This is not yet working and the second dropdown remains unpopulated.

When I hard-code the second dropdown with an actual category value, Admin in this case, it displays the values as expected:

<select id="skill">
    <option value="NONE">----Select----</option>
    <option th:each="skill : ${skillsMap.get('Admin')}" th:value="${skill.id}"
        th:text="${skill.name}">
    </option>
</select>

I therefore know that it is the way I am trying to set and reference the 'cat' variable where the issue lies. Of all the technologies used in this project, the JavaScript/JQuery side of things is by far my weakest and I am not sure if what I am trying to do is fundamentally the wrong approach or if I just have some syntax issues. I would be extremely grateful if anyone could point me in the right direction!

Upvotes: 0

Views: 1265

Answers (1)

sugars
sugars

Reputation: 1493

var data = {
  skill1: ['a', 'b'],
  skill2: ['c'],
  skill3: ['d']
}

$(document).ready(function() {
  $("#category").change(function() {
    var skill = $("#category").val();
    var optionList = "";
    var skillList = data[skill];
    for (var i = 0; i < skillList.length; i++) {
      optionList += "<option value=" + skillList[i] + ">" + skillList[i] + "</option>";
    }
    $("#skill").html(optionList);
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<select id="category">
  <option value="skill1">skill1</option>
  <option value="skill2">skill2</option>
  <option value="skill3">skill3</option>
</select>

<select id="skill">

</select>

You can replace all options with the .html() method for the second select when the first select changes.

Upvotes: 1

Related Questions