Nacho Zve De La Torre
Nacho Zve De La Torre

Reputation: 364

Problem populating a modal dynamically with ThymeLeaf and Spring MVC

This is my HOME page.

enter image description here

When the user selects a Datacenter the page redirects and shows the list of FisicHost's available for that Datacenter.

Datacenter class

@Entity
@Transactional
public class Datacenter {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;

    @OneToMany(mappedBy = "datacenter")
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<FisicHost> fisicHostList;

  // I've cut the constructor and get/set to make it shorter
}

This is the view where the user is redirected when it chooses a Datacenter:

enter image description here

each row in the view represents a FiscHost object that is available for the chosen datacenter.

FisicHost class

@Entity
@Transactional
public class FisicHost {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch=FetchType.EAGER)
private Datacenter datacenter;

@OneToMany(mappedBy = "fisicHost")
@LazyCollection(LazyCollectionOption.FALSE)
private List<Credential> credentials;

private String name;
private String ip;
private String operatingSystem;
private String notes;
}

This is the controller method handling the second view (the one that shows the list of available FisicHost's for that datacenter):

@RequestMapping(value = "/chosenDatacenter", method = RequestMethod.POST)
public String datacenterPostHandler(@RequestParam("datacenterList") String name, ModelMap modelMap){
    List<Datacenter> allDatacenters = datacenterDao.getAllDatacenters();
    for (Datacenter dc : allDatacenters) {
        if (dc.getName().equals(name)) {
        modelMap.put("datacenter", dc);
        if(dc.getFisicHostList().size() != 0) {
            List<FisicHost> datacenterFisicHosts = dc.getFisicHostList();
            modelMap.put("datacenterFisicHosts", datacenterFisicHosts);
            for(FisicHost fh : datacenterFisicHosts){
                if(fh.getCredentials().size() != 0){
                    modelMap.put("fisicHostCredentialsList", credentialDao.getAllCredentialsByFisicHost(fh));
                }
            }
        }
        return "chosenDatacenter";
        }
    }
        return null;
}

If the user clicks on the "CREDENCIALES" button a modal pops up and show all the credentials available for that FisicHost.

Credential class:

@Entity
public class Credential {

    @Id
    private int id;

    @ManyToOne(fetch= FetchType.EAGER)
    private FisicHost fisicHost;

    private String user;
    private String password;
    private String notes;
    private String role;
}

enter image description here

All this is working fine, BUT here comes the problem ...

Whatever button is clicked, the modal is opened showing ALL the credentials for ALL the FisicHosts inside THAT Datacenter and I ONLY want to show the Credentials for the specific FisicHost that was clicked in the corresponding datacenter!

I know this logic in the controller:

 for(FisicHost fh : datacenterFisicHosts){
                if(fh.getCredentials().size() != 0){
                    modelMap.put("fisicHostCredentialsList", credentialDao.getAllCredentialsByFisicHost(fh));
                }

is only bringing back the last iteration of the loop, so it will always bring the credentials for that FisicHost no matter what ! And that's what happening, but I can't find a different way of doing it ...

Just in case, here is the getAllCredentialsByFisicHost() method from the CredentialDaoImpl class:

@Override
public List<Credential> getAllCredentialsByFisicHost(FisicHost fisicHost) {
    // Open a session
    Session session = sessionFactory.openSession();

    Criteria c = session.createCriteria(Credential.class).add(Restrictions.eq("fisicHost.id", fisicHost.getId()));

    List<Credential> allCredentials = c.list();

    // Close the session
    session.close();

    return allCredentials;
}

Please help cause I'm going crazy with this !!!

Thanks a lot to all :)

PS: This is the chosenDatacenter template that is being rendered with ThymeLeaf:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>Generic View</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap/bootstrap.min.css}" />
    <link rel="stylesheet" th:href="@{/css/choosenDatacenter.css}" />
</head>

<body>

<form id="form" action="/getJson" th:object="${datacenterFisicHosts}" method="post">

    <table>
        <tr class="row">
            <th class="tableHeader">Nombre</th>
            <th class="tableHeader">IP</th>
            <th class="tableHeaders">Sistema Operativo</th>
            <th class="tableHeaders">Notas</th>
        </tr>

        <th:block th:each="fh : ${datacenterFisicHosts}">
        <div id="fila">
            <tr class="row">
                <td id="fisicHostName" th:text="${fh.name}"></td>
                <td id="fisicHostIp" th:text="${fh.ip}"></td>
                <td id="fisicHostOS" th:text="${fh.operatingSystem}"></td>
                <td id="fisicHostNotes" th:text="${fh.notes}"></td>
                <td><button type="button" th:onclick="'javascript:openCredentialModal()'">CREDENCIALES</button></td>
            </tr>
        </div>
        </th:block>
    </table>

</form>


<!-- Modal -->
<div class="modal fade" id="modalCredenciales" tabindex="-1" role="dialog" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="modal-title">Credenciales</h5>
            </div>
            <div class="modal-body">
                <table>
                    <tr class="row">
                        <th class="tableHeader">Usuario</th>
                        <th class="tableHeader">Clave</th>
                        <th class="tableHeaders">Notas</th>
                    </tr>

                    <th:block th:each="credential : ${fisicHostCredentialsList}">
                        <tr class="row">
                            <td id="credentialUser" th:text="${credential.user}"></td>
                            <td id="credentialPassword" th:text="${credential.password}"></td>
                            <td id="credentialRole" th:text="${credential.notes}"></td>
                        </tr>
                    </th:block>
                </table>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">Cerrar</button>
            </div>
        </div>
    </div>
</div>

<script th:src="@{js/jquery-1.11.3.js}"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script th:src="@{js/chosenDatacenter.js}"></script>
</body>
</html>

Upvotes: 0

Views: 4954

Answers (1)

lgaleazzi
lgaleazzi

Reputation: 163

You can use Ajax to pass the id to your controller and have it return only the relevant cerdentials, as explained here.

In your controller you add a method that returns the correct list of credentials taking the id of the fisicHost as a parameter:

@RequestMapping("/fisicHost/{id}")
public String fisicHost credentials(@PathVariable("id") String id, ModelMap model) 
{
    //find credentials by fisicHost using your DAO and add them to model
    return "modal/credentials :: modalContents";
}

You'll need a 'modalContents' Thymeleaf fragment to display the credentials as added to model.

Then on the onClick event, you can use Ajax to call the url with the correct id and display the data. In your template, you'd have:

th:onclick="'javascript:openCredentialModal(\'' + ${fh.id} + '\');'"

The Ajax function just calls the url of your controller by passing th id along, and is returned the html code from the thymeleaf fragment. It then packs the html content in the modal.

Upvotes: 2

Related Questions