vendredi 1 janvier 2021

Spring Boot Modals won't work after sorting table

I was building database of customers with Spring Boot with all CRUD operations, paginating, sorting and search function. Because I'm new to web developing, I was following two Youtube tutorials. For implementing Modals for CRUD operations I was following this:

https://www.youtube.com/watch?t=1747&v=lIgFe20dYq4&feature=youtu.be\

for implementing pagination and sorting I was following this:

https://www.youtube.com/watch?v=Aie8n12EFQc

And everythink works great! But...

After implementing sorting my modals stopped working. After clicking on header of the column, URL gets parameters for sorted filed and sorting order, but then modals won't work. When I don't have parameters in the URL it works. I won't to be able to use modals after sorting and later when I implement searching. I belive modals are very user friendly, I really want them. But i don't know how to deal with this problem, I would be happy and grateful if you help me.

Here is customer_list.html file

<!DOCTYPE html>

<html xmlns:th = "http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>List of customers</title>
        <meta name = "author" content="Miloš Savić">
        <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT" crossorigin="anonymous"></script>
        <script type="text/javascript" src = "/webjars/jquery/2.2.3/jquery.min.js"></script>
        
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
        
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
        <script type="text/javascript" th:src = "@{js/main.js}" src = "../static/js/main.js"></script>
    </head>
    <body>

        <h1 align = "center">List of Customers</h1>
        <div align = "center" class = "container-fluid" >

            <br />
            <!-- <a th:href = "@{/newcustomer}" class = "btn btn-primary btn-sm mb-3">Add Customer</a> -->
            <button class = "btn btn-success" id = "nBtn">New Customer</button>
            <br />
            <br />
            <br />
            <table id = "customers" border = "1" class = "table table-striped table-responsive-xl">
                <thead>
                    <tr>
                        <!-- <th>ID</th> -->
                        <th>
                            <a th:href = "@{'/page/' + ${currentPage} + '?sortField=paypalUsername&sortDirection=' + ${reverseSortDirection}}">
                            PayPal Username</a>
                        </th>
                        <th>
                            <a th:href = "@{'/page/' + ${currentPage} + '?sortField=paypalAddress&sortDirection=' + ${reverseSortDirection}}">
                            PayPal Adress</a>
                        </th>
                        <th>
                            <a th:href = "@{'/page/' + ${currentPage} + '?sortField=ingameName&sortDirection=' + ${reverseSortDirection}}">
                            In-game Name</a>
                        </th>
                        <th>Game</th>
                        <th>Platform</th>
                        <th>Login Email</th>
                        <th>Login Password</th>
                        <th>Kingdom/State</th>
                        <th>Activity</th>
                        <th>Date</th>
                        <th>Currency</th>
                        <th>Old/Other Username</th>
                        <th>Charge Back?</th>
                        <th>Notes</th>
                    </tr>
                </thead>
                <tbody>
                    <tr th:each = "customerDTO : ${listOfCustomers}">
                        <!-- <td th:text = "${customerDTO.idCustomer}"></td> -->
                        <td th:text = "${customerDTO.paypalUsername}"></td>
                        <td th:text = "${customerDTO.paypalAddress}"></td>
                        <td th:text = "${customerDTO.ingameName}"></td>
                        <td th:text = "${customerDTO.game}"></td>
                        <td th:text = "${customerDTO.platform}"></td>
                        <td th:text = "${customerDTO.loginEmail}"></td>
                        <td th:text = "${customerDTO.loginPassword}"></td>
                        <td th:text = "${customerDTO.kingdom}"></td>
                        <td th:text = "${customerDTO.active}"></td>
                        <td th:text = "${customerDTO.date}"></td>
                        <td th:text = "${customerDTO.currency}"></td>
                        <td th:text = "${customerDTO.oldOtherUsername}"></td>
                        <td th:text = "${customerDTO.chargeBack}"></td>
                        <td th:text = "${customerDTO.notes}"></td>
                        <td><a href = "#" th:href = "@{/findById(id=${customerDTO.idCustomer})}" class="btn btn-primary btn-lg" id = "eBtn" th:data = "${customerDTO.idCustomer}">Edit</a></td>
                        <td><a href = "#" th:href = "@{/deleteCustomer(id=${customerDTO.idCustomer})}" class="btn btn-danger btn-lg" id = "delBtn" th:data = "${customerDTO.idCustomer}">Delete</a></td>
                    </tr>
                </tbody>
            </table>
            
            <div th:if = "${totalPages > 1}">
                <div class = "row col-sm-10">
                    <div class = "col-sm-2">
                        Total Customers: [[${totalItems}]]
                    </div>
                    <div class = "col-sm-1">
                        <span th:each = "i: ${#numbers.sequence(1, totalPages)}">
                            <a th:if = "${currentPage != i}" th:href = "@{'/page/' + ${i} + '?sortField=' + ${sortField} + '&sortDirection=' + ${sortDirection}}">[[${i}]]</a>
                            <span th:unless = "${currentPage != i}">[[${i}]]</span> &nbsp; &nbsp;
                        </span>
                    </div>
                    <div class = "col-sm-1">
                        <a th:if = "${currentPage < totalPages}" th:href = "@{'/page/' + ${currentPage + 1} + '?sortField=' + ${sortField} + '&sortDirection=' + ${sortDirection}}">Next</a>
                        <span th:unless = "${currentPage < totalPages}">Next</span>
                    </div>
                    <div class = "col-sm-1">
                        <a th:if = "${currentPage < totalPages}" th:href = "@{'/page/' + ${totalPages} + '?sortField=' + ${sortField} + '&sortDirection=' + ${sortDirection}}">Last</a>
                        <span th:unless = "${currentPage < totalPages}">Last</span>
                    </div>
                </div>
            </div>
            
            
        </div>
        
        <!-- Modal for update -->
        
            <div class = "myModalFormEdit">
            <form th:action = "@{/savecustomer}" method = "POST">
                <div class="modal fade" id="exampleModalEdit" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
                    <div class="modal-dialog" role="document">
                        <div class="modal-content">
                            <div class="modal-header">
                                <h5 class="modal-title" id="exampleModalLabel">Update Customer</h5>
                                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                                </button>
                            </div>
                            <div class="modal-body">
                                 <div class="form-group">
                                    <!-- <label for="idCustomer" class="col-form-label">ID:</label> -->
                                    <input type = "hidden" class = "form-control" id="idCustomer" name = "idCustomer" />
                                </div>
                                <div class="form-group">
                                <label for="paypalUsername" class="col-form-label">PayPal Username:</label>
                                <input type="text" maxlength="32" class="form-control" id="paypalUsername" name = "paypalUsername" />
                                </div>
                                <div class="form-group">
                                    <label for="paypalAddress" class="col-form-label">PayPal Address:</label>
                                    <input type = "email" maxlength="32" class="form-control" id="paypalAddress" name = "paypalAddress"  />
                                </div>
                                <div class="form-group">
                                    <label for="game" class="col-form-label">Game:</label>
                                    <input type = "text" maxlength="4" class="form-control" id="game" name = "game" />
                                </div>
                                <div class="form-group">
                                    <label for="ingameName" class="col-form-label">In-game Name:</label>
                                    <input type = "text" maxlength="32" class="form-control" id="ingameName" name = "ingameName"  />
                                </div>
                                <div class="form-group">
                                    <label for="platform" class="col-form-label">Platform:</label>
                                    <input type = "text" maxlength="32" class="form-control" id="platform" name = "platform"  />
                                </div>
                                <div class="form-group">
                                    <label for="loginEmail" class="col-form-label">Login Email:</label>
                                    <input type = "email" maxlength="32" class="form-control" id="loginEmail" name = "loginEmail"  />
                                </div>
                                <div class="form-group">
                                    <label for="loginPassword" class="col-form-label">Login Password:</label>
                                    <input type = "text" maxlength="32" class="form-control" id="loginPassword" name = "loginPassword"  />
                                </div>
                                <div class="form-group">
                                    <label for="kingdom" class="col-form-label">Kingdom/State:</label>
                                    <input type = "text" maxlength="32" class="form-control" id="kingdom" name = "kingdom"  />
                                </div>
                                <div class="form-group">
                                    <label for="active" class="col-form-label">Activity:</label>
                                    <select class="form-control" id="active" name = "active" >
                                        <option value="true" selected>Active</option>
                                        <option value="false">Inactive</option>
                                    </select>
                                </div>
                                <div class="form-group">
                                    <label for="date" class="col-form-label"> <i class="fa fa-calendar"></i>&nbsp;&nbsp;Date:</label>
                                    <input type = "date" class="form-control" id="date" name = "date"/>
                                </div>
                                <div class="form-group">
                                    <label for="currency" class="col-form-label">Currency:</label>
                                    <input type = "text" maxlength="4" class="form-control" id="currency" name = "currency"  />
                                </div>
                                <div class="form-group">
                                    <label for="oldOtherUsername" class="col-form-label">Old/Other Username:</label>
                                    <input type = "text" maxlength="32" class="form-control" id="oldOtherUsername" name = "oldOtherUsername"  />
                                </div>
                                <div class="form-group">
                                    <label for="chargeBack" class="col-form-label">Charge Back?</label>
                                    <select class="form-control" id="chargeBack" name = "chargeBack" >
                                        <option value="true" selected>No</option>
                                        <option value="false">Yes</option>
                                    </select>
                                </div>
                                <div class="form-group">
                                    <label for="notes" class="col-form-label">Notes:</label>
                                    <textarea class="form-control" maxlength="512" id="notes" name = "notes"></textarea>
                                </div>
                        </div>
                        
                        <div class="modal-footer">
                            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                            <button type="submit" class="btn btn-primary" value = "">Save</button>
                        </div>
                    </div>  

                        
                    </div>
                </div>
            </form>
        </div>
        
        <!-- Modal for Insert New-->
        
        <div class = "myModalFormInsertNew">
            <form th:action = "@{/savecustomer}" method = "POST">
                <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
                    <div class="modal-dialog" role="document">
                        <div class="modal-content">
                            <div class="modal-header">
                                <h5 class="modal-title" id="exampleModalLabel">New Customer</h5>
                                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                                <span aria-hidden="true">&times;</span>
                                </button>
                            </div>
                            <div class="modal-body">
                                <div class="form-group">
                                <label for="paypalUsername" class="col-form-label">PayPal Username:</label>
                                <input type="text" class="form-control" id="paypalUsername" name = "paypalUsername" />
                                </div>
                                <div class="form-group">
                                    <label for="paypalAddress" class="col-form-label">PayPal Address:</label>
                                    <input type = "email" class="form-control" id="paypalAddress" name = "paypalAddress"  />
                                </div>
                                <div class="form-group">
                                    <label for="game" class="col-form-label">Game:</label>
                                    <input type = "text" class="form-control" id="game" name = "game" />
                                </div>
                                <div class="form-group">
                                    <label for="ingameName" class="col-form-label">In-game Name:</label>
                                    <input type = "text" class="form-control" id="ingameName" name = "ingameName"  />
                                </div>
                                <div class="form-group">
                                    <label for="platform" class="col-form-label">Platform:</label>
                                    <input type = "text" class="form-control" id="platform" name = "platform"  />
                                </div>
                                <div class="form-group">
                                    <label for="loginEmail" class="col-form-label">Login Email:</label>
                                    <input type = "email" class="form-control" id="loginEmail" name = "loginEmail"  />
                                </div>
                                <div class="form-group">
                                    <label for="loginPassword" class="col-form-label">Login Password:</label>
                                    <input type = "text" class="form-control" id="loginPassword" name = "loginPassword"  />
                                </div>
                                <div class="form-group">
                                    <label for="kingdom" class="col-form-label">Kingdom/State:</label>
                                    <input type = "text" class="form-control" id="kingdom" name = "kingdom"  />
                                </div>
                                <div class="form-group">
                                    <label for="active" class="col-form-label">Activity:</label>
                                    <select class="form-control" id="active" name = "active" >
                                        <option value="true" selected>Active</option>
                                        <option value="false">Inactive</option>
                                    </select>
                                </div>
                                <div class="form-group">
                                    <label for="date" class="col-form-label"> <i class="fa fa-calendar"></i>&nbsp;&nbsp;Date:</label>
                                    <input type = "date" class="form-control" id="date" name = "date"/>
                                </div>
                                <div class="form-group">
                                    <label for="currency" class="col-form-label">Currency:</label>
                                    <input type = "text" class="form-control" id="currency" name = "currency"  />
                                </div>
                                <div class="form-group">
                                    <label for="oldOtherUsername" class="col-form-label">Old/Other Username:</label>
                                    <input type = "text" class="form-control" id="oldOtherUsername" name = "oldOtherUsername"  />
                                </div>
                                <div class="form-group">
                                    <label for="chargeBack" class="col-form-label">Charge Back?</label>
                                    <select class="form-control" id="chargeBack" name = "chargeBack" >
                                        <option value="true" selected>No</option>
                                        <option value="false">Yes</option>
                                    </select>
                                </div>
                                <div class="form-group">
                                    <label for="notes" class="col-form-label">Notes:</label>
                                    <textarea class="form-control" id="notes" name = "notes"></textarea>
                                </div>
                        </div>
                        
                        <div class="modal-footer">
                            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                            <button type="submit" class="btn btn-primary" value = "">Save</button>
                        </div>
                    </div>  

                        
                    </div>
                </div>
            </form>
        </div>
        
        
        <!-- ModalDelete -->
        <div class="modal fade" id="myModalDelete" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
          <div class="modal-dialog">
            <div class="modal-content">
              <div class="modal-header">
                <h5 class="modal-title" id="staticBackdropLabel">Delete Customer</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">&times;</span>
                </button>
              </div>
              <div class="modal-body">
                <p class = "alert alert-danger">Are you sure you want to delete this customer?</p>
              </div>
              <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                <a href = "" class="btn btn-danger" id = "delRef">Delete</a>
              </div>
            </div>
          </div>
        </div>
        
    </body>
</html>

Javascript main.js for modals:

$(document).ready(function(){
    $('#nBtn, .table #eBtn').on('click', function(event){
        event.preventDefault();
        var href = $(this).attr('href');
        var text = $(this).text();
        var date = new Date();
        if(text == 'Edit')
        {
            $.get(href, function(customerDTO, status){
            $('.myModalFormEdit #idCustomer').val(customerDTO.idCustomer);
            $('.myModalFormEdit #paypalUsername').val(customerDTO.paypalUsername);
            $('.myModalFormEdit #paypalAddress').val(customerDTO.paypalAddress);
            $('.myModalFormEdit #game').val(customerDTO.game);
            $('.myModalFormEdit #ingameName').val(customerDTO.ingameName);
            $('.myModalFormEdit #platform').val(customerDTO.platform);
            $('.myModalFormEdit #loginEmail').val(customerDTO.loginEmail);
            $('.myModalFormEdit #loginPassword').val(customerDTO.loginPassword);
            $('.myModalFormEdit #kingdom').val(customerDTO.kingdom);
            $('.myModalFormEdit #active').val(customerDTO.active);
            $('.myModalFormEdit #date').val(customerDTO.date);
            $('.myModalFormEdit #currency').val(customerDTO.currency);
            $('.myModalFormEdit #oldOtherUsername').val(customerDTO.oldOtherUsername);
            $('.myModalFormEdit #chargeBack').val(customerDTO.chargeBack);
            $('.myModalFormEdit #notes').val(customerDTO.notes);
            $('.myModalFormEdit #exampleModalEdit').modal('show');
            
        });
            
        }
        else
        {

            $('.myModalFormInsertNew #exampleModal').modal('show');
        };

    });
            $('.table #delBtn').on('click', function(event){
        
            event.preventDefault();
            var href = $(this).attr('href');
            $('#myModalDelete #delRef').attr('href', href);
            $('#myModalDelete').modal('show');
        });
    });

Controller Java class:

package com.mitogames.controllers;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.mitogames.dto.CustomerDTO;
import com.mitogames.services.ICustomerService;

@Controller
public class MitogamesController
{
    
    Logger log = LoggerFactory.getLogger(this.getClass());
    
    @Autowired
    ICustomerService customerService;
    
    @GetMapping("/index")
    public String homePage()
    {
        return "index";
    }
    
    @PostMapping("/savecustomer")
    public String saveCustomer(@ModelAttribute CustomerDTO customerDTO)
    {
        //CustomerDTO emptyCustomer = new CustomerDTO();
        //ModelAndView modelAndView = new ModelAndView();
        try
        {
            customerService.saveCustomer(customerDTO);
        } catch (Exception e)
        {
            log.error("Unabel to save the customer" + e);
            e.printStackTrace();
            return "error";
        }
        //modelAndView.addObject("customerDTO", emptyCustomer);
        //modelAndView.setViewName("newcustomer");
        //return modelAndView;
        return "redirect:/customer_list";
    }
    
    @GetMapping("/customer_list")
    public String customerList(Model model)
    {
            
            return findPaginated(1, "paypalUsername", "asc",  model);
    }
    
    
    @GetMapping("/findById")
    @ResponseBody
    public CustomerDTO findById(int id)
    {
         CustomerDTO customerDTO = new CustomerDTO();
         customerDTO = customerService.getCustomerById(id);
         
         return customerDTO;
    }
    
    @GetMapping("/deleteCustomer")
    public String deleteCustomerById(int id)
    {
        customerService.deleteCustomer(id);
        
        return "redirect:/customer_list";
    }
    
    @GetMapping("/page/{pageNumber}")
    public String findPaginated(@PathVariable (value = "pageNumber") int pageNumber, @RequestParam("sortField") String sortField,
            @RequestParam("sortDirection") String sortDirection ,Model model)
    {
        int pageSize = 5;
        
        Page<CustomerDTO> page = customerService.findPaginated(pageNumber, pageSize, sortField, sortDirection);
        List<CustomerDTO> listOfCustomers = page.getContent();
        
        model.addAttribute("currentPage", pageNumber);
        model.addAttribute("totalPages", page.getTotalPages());
        model.addAttribute("totalItems", page.getTotalElements());
        model.addAttribute("listOfCustomers", listOfCustomers);
        model.addAttribute("sortField", sortField);
        model.addAttribute("sortDirection", sortDirection);
        model.addAttribute("reverseSortDirection", sortDirection.equals("asc") ? "desc" : "asc");
        
        return "customer_list";
    }
    
}

DAO Class

package com.mitogames.dao;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;

import com.mitogames.dto.CustomerDTO;

@Component
public class CustomerDAO implements ICustomerDAO
{
    @Autowired
    ICustomerRepository customerRepository;
    
    @Override
    public void saveCustomer(CustomerDTO customerDTO) throws Exception
    {
        customerRepository.save(customerDTO);

    }

    @Override
    public List<CustomerDTO> getAllCustomers() throws Exception
    {
        return customerRepository.findAll();
    }

    @Override
    public CustomerDTO getCustomerById(int id)
    {
        Optional<CustomerDTO> optional = customerRepository.findById(id);
        CustomerDTO customerDTO = null;
        
        if (optional.isPresent())
        {
            customerDTO = optional.get();
        }
        else
        {
            throw new RuntimeException("Customer not found for id: " + id);
        }
        
        return customerDTO;
        
    }

    @Override
    public void deleteCustomer(int id)
    {
        customerRepository.deleteById(id);
        
    }

    @Override
    public Page<CustomerDTO> findPaginated(int pageNumber, int pageSize, String sortField, String sortDirection)
    {
        Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortField).ascending() :
            Sort.by(sortField).descending();
        Pageable pageable = PageRequest.of(pageNumber - 1, pageSize, sort);
        return this.customerRepository.findAll(pageable);
    }
    

}

I have a Service class, but in this case it just passes arguments to DAO object. For CRUD operations, my Interface customerRepository extends JpaRepository.




Aucun commentaire:

Enregistrer un commentaire