How do I load an object in a Bootstrap modal using Spring Boot / Thymeleaf? - spring-boot

I have a table filled with tasks:
<table class="table" id="tasksTable">
<thead class="thead-inverse">
<tr>
<th>ID</th>
<th>Title</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr data-th-each="task : ${tasks}">
<td data-th-text="${task.id}">Task ID</td>
<td data-th-text="${task.title}">Task Title</td>
<td><a th:href="#{/tasks/delete/{id}(id=${task.id})}"
class="btn btn-danger">Delete</a> -
<button class="btn btn-warning" data-toggle="modal"
data-th-id="${task.id}" data-target="#updateTaskModal">Update</button></td>
</tr>
</tbody>
</table>
The list is sent from a controller like this:
#GetMapping(path = "/")
public String getAllUsersView(Model model) {
List<User> users = new ArrayList<>();
List<Task> tasks = new ArrayList<>();
User user = new User();
Task task = new Task();
userRepository.findAll().forEach(users::add);
taskRepository.findAll().forEach(tasks::add);
model.addAttribute("users", users);
model.addAttribute("tasks", tasks);
model.addAttribute("user", user);
model.addAttribute("task", task);
return "view";
}
I would like to pick one task from the table, and send it to a modal. For instance, let's say I have 10 tasks. I want to pick task #5 and be able to update it. When I click Update, I can open a modal, but I don't know how to fill the form with the data from that specific task, it all comes blank.
This is my modal:
<div id="updateTaskModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Update Task</h4>
</div>
<div class="modal-body">
<form id="updateNewTask" action="#" th:action="#{/tasks/update}"
th:object="${task}" method="put">
<input type="text" class="form-control" name="title" id="title"
th:field="*{title}" placeholder="Task Title" />
<hr />
<button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-success pull-right">Update</button>
</form>
</div>
</div>
</div>
</div>
What would be the best practice to achieve this? Is it possible to send the entire object thru a button? If not, how can I load my object into the modal? I can retrieve a JSON version of the object via /tasks/{taskId}, but I don't know how to call it from the modal.

You can load content into existing modal with Javascript. "Best" way to to this is by rendering your object on server into some HTML with thymleaf and then fetching this response via Ajax and injecting into your modal box into some div tag.

Related

How to update a table row by passing data from a Bootstrap modal form

I'm fresh in web development and I'm facing some problems
I have an html page that displays a table. Each row contains data and an "edit" button.
What I want is the following:
I already could invoke the modal form and make it pop up with data corresponding to the row's data (through the button "edit") before I add this code to my form tag th:action="#{/countries/update/{id} (id =${countryToUpdate.id})}" and hence I get this following error:
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'id' cannot be found on null
I know that the passed model attribute countryToUpdateis null
I'm asking if it's possible to pass a model attribute to a the bootstrap modal form
That's my html table:
<table class="table">
<tr>
<th>Id</th>
<th>Description</th>
<th>Capital</th>
<th>Code</th>
<th>Actions</th>
</tr>
<tr th:each="country:${countries}">
<td th:text="${country.id}"></td>
<td th:text="${country.description}"></td>
<td th:text="${country.capital}"></td>
<td th:text="${country.code}"></td>
<td>
<!--Edit button to invoke the bootstrap form-->
<div class="btn-group">
<a th:href="#{/countries/findById/{id} (id=${country.id})}" class="btn btn-primary editModalBtn" data-toggle="modal" data-target="#editModal">Edit</a>
</div>
</td>
</tr>
</table>
The bootstrap form:
<div class="modal fade" id="editModal" 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 message</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<!--the action attribute of the from indicates to where the form is gonna be submitted-->
<form th:action="#{/countries/update/{id} (id =${countryToUpdate.id})}" method="post" th:object="${countryToUpdate}">
<div class="form-group">
<label for="descriptionEdit" class="col-form-label">Description</label>
<!--name should correspond to the fields in the modal class-->
<input
type="text"
class="form-control"
id="descriptionEdit"
name="description"
>
</div>
<div class="form-group">
<label for="capitalEdit" class="col-form-label">Capital</label>
<input type="text"
class="form-control"
id="capitalEdit"
name="capital"
>
</div>
<div class="form-group">
<label for="codeEdit" class="col-form-label">Code</label>
<input type="text"
class="form-control"
id="codeEdit"
name="code"
>
</div>
<div class="form-group">
<label for="continentEdit" class="col-form-label">Continent</label>
<input type="text"
class="form-control"
id="continentEdit"
name="continent"
>
</div>
<div class="form-group">
<label for="nationalityEdit" class="col-form-label">Nationality</label>
<input type="text"
class="form-control"
id="nationalityEdit"
name="nationality"
>
</div>
<div class="modal-footer">
<!--submit type button should be within the form to execute the query-->
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Update</button>
</div>
</form>
</div>
</div>
</div>
</div>
My controller:
#GetMapping("countries")
public String findAll(Model model){
List<Country> listOfCountries = countryService.findAll();
model.addAttribute("countries", listOfCountries);
return "country";
}
#GetMapping("countries/findById/{id}")
#ResponseBody
public Country findById(#PathVariable int id, Model mod)
{
Country country = countryService.findById(id).get();
//I want to create a countryToUpdate attribute to use it in the modal form
mod.addAttribute("countryToUpdate", country);
return country;
}
#GetMapping("countries")
public String findAll(Model model){
List<Country> listOfCountries = countryService.findAll();
model.addAttribute("countries", listOfCountries);
return "country";
}
#PostMapping(value="countries/update/{id}")
public String update(#ModelAttribute("countryToUpdate") Country country, #PathVariable int id) {
//Get the country object from database through the passed id
Optional<Country> c = countryService.findById(id);
c.get().setDescription(country.getDescription());
c.get().setContinent(country.getContinent());
c.get().setCode(country.getCode());
c.get().setCapital(country.getCapital());
c.get().setNationality(country.getNationality());
System.out.println("this country description is " + country.getDescription());
countryService.save(c.get());
return "redirect:/countries";
}
Any help would be appreciated.

How to send a list of data from controller to a modal popup in razor

I'm implementing asp.net core 3.1 project. I have a razor view and in razor, I'm showing some data that are getting from the Index method in my controller which its name is RequestorsController. In razor, for each row there is a link which is called "Details" and I want when the user clicks on the Details button for each row, the related id for that row passes to a method called "Details" in RequestorsController and a list of related data returns back to the razor view and displays on a Modal popup. Now I could implement the Modal popup, but my problem is I couldn't fetch the data from the controller to show on modal. I appreciate if anyone solves my problem.
<div id="tablecontainer" class="my-5 col-sm-12 d-flex justify-content-center">
<table id="myDummyTable" class="table m-table mytable table-striped mb-4 col-12 dataTable table-bordered px-0 mx-0" style="box-sizing:content-box;">
<thead>
<tr id="headerrow">
<th>
requestor name
</th>
<th>
items requested
</th>
<th>
operations
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.HiddenFor(modelItem => item.applicantID)
#Html.DisplayFor(modelItem => item.requestorName)
</td>
<td>
#Html.DisplayFor(modelItem => item.requesteditemCount)
</td>
<td>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-id="#item.applicantID">Details</button>
</td>
</tr>
}
</tbody>
</table>
</div>
<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 message</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form method="post">
<div class="modal-body">
<div class="form-group">
<label for="recipient-apiname" class="col-form-label">name:</label>
<input type="text" class="form-control" id="recipient-apiname" name="apiname">
<input type="hidden" id="recipient-id" name="id" />
</div>
<div class="form-group">
<label for="recipient-status" class="col-form-label">status:</label>
<input type="text" class="form-control" id="recipient-status" name="status">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-primary" value="Save" />
</div>
</form>
</div>
</div>
</div>
#section scripts{
<script>
#{
if (ViewBag.ModalState == null)
{
ViewBag.ModalState = "hide";
}
}
$('#exampleModal').modal('#ViewBag.ModalState');
$('#exampleModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);
var id = button.data('id');
var modal = $(this);
modal.find('.modal-body input[name="id"]').val(id);
$.get('#Url.Action("Details", "Requestors")/' + id, function (data) {
modal.find('.modal-body input[name="name"]').val(data.itemName);
modal.find('.modal-body input[name="status"]').val(data.requestStatus);
});
});
</script>
}
public async Task<IActionResult> Details(int? id)
{
List<ItemDTO> al = new List<ItemDTO>();
ItemDTO apDTO;
var myquery = (from t in _context.Items
where t.ApplicantId == id
select new { ItemName = t.ItemName, requestStatus = t.LastRequestStatus }).ToList();
foreach (var index in myquery)
{
apDTO = new ItemDTO();
apDTO.itemName = index.itemName;
apDTO.requestStatus = index.requestStatus;
al.Add(apDTO);
}
return View(al);
}
Now I could implement the Modal popup, but my problem is I couldn't
fetch the data from the controller to show on modal.
As mentioned in your comment, when you click on the Details button, a 500 error occurs,I did reproduce this mistake.
This is because the Details action returns the View instead of the json data that needs to be returned in ajax, and because there is no Details view, a 500 error occurs.
To solve it, you only need to change the content of the Details action returned to Json data, as shown below:
public async Task<IActionResult> Details(int? id)
{
List<ItemDTO> al = new List<ItemDTO>();
ItemDTO apDTO;
var myquery = (from t in _context.Items
where t.ApplicantId == id
select new { ItemName = t.ItemName, requestStatus = t.LastRequestStatus }).ToList();
foreach (var index in myquery)
{
apDTO = new ItemDTO();
apDTO.itemName = index.ItemName;// here is ItemName(case sensitive)
apDTO.requestStatus = index.requestStatus;
al.Add(apDTO);
}
return Json(al);
}
My doubt is that if the ApplicantId is the key, then the count of data obtained from the Items table must be one, without the need for a list collection, but because you return a collection data, then in ajax, you need to pass data[0] to bind the corresponding input value/
And you need to change input[name="name"] to input[name="apiname"].
Here is ajax code:
$.get('#Url.Action("Details", "Requestors")/' + id, function (data) {
modal.find('.modal-body input[name="apiname"]').val(data[0].itemName);
modal.find('.modal-body input[name="status"]').val(data[0].requestStatus);
});

Spring MVC Controller not receiving atribute from Template with Thymeleaf

I have a template which represents a list of notes that are retrieved from a database
<tr th:unless="${#lists.isEmpty(allNotes)}"
th:each="note : ${allNotes}">
<td>
<form action="#" method="POST" th:action="#{/home/editNote}"
th:object="${note}">
<input type="hidden" id="noteId" name="noteId" th:value="*{noteId}">
<button type="button" class="btn btn-success"
onclick="editNoteModal('updateNote', this.getAttribute('data-noteId'),
this.getAttribute('data-noteTitle'),
this.getAttribute('data-noteDescription'))">Edit
</button>
</form>
<form action="#" method="POST" th:action="#{/home/deleteNote}">
<input type="hidden" name="noteId" th:value="*{note.noteId}">
<a class="btn btn-danger">Delete</a>
</form>
</td>
<th scope="row" th:text="${note.noteTitle}">Example Note Title</th>
<td th:text="${note.noteDescription}">Example Note Description</td>
</form>
</tr>
</tbody>
In the GUI It looks like this
This is my modal code which should open after I click on the edit button:
<div class="modal fade" id="editNoteModal" tabindex="-1" role="dialog" aria-labelledby="noteModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editnoteModalLabel">Note</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="note-title" class="col-form-label">Title</label>
<input type="text" name="noteTitle" class="form-control" id="editNoteTitle"
maxlength="20" required>
</div>
<div class="form-group">
<label for="note-description" class="col-form-label">Description</label>
<textarea class="form-control" name="noteDescription" id="editNoteDescription"
rows="5" maxlength="1000" required></textarea>
</div>
<button id="editNoteSubmit" type="submit" class="d-none"></button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="$('#editNoteModal').click();">
Save
changes
</button>
</div>
</div>
</div>
</div>
</div>
In the GUI it looks like this:
I want to be able to edit given note and then send the edited id to the controller so I can update this change within the database. I have correct database logic for the update, I just don't know the way how to send the given notes id and changed information to my controller.
#PostMapping("/editNote")
public String editNote(#ModelAttribute(value = "note") Note note,
#ModelAttribute(value = "noteId") NoteIdModel noteIdModel, Model model,
Authentication authentication) {
System.out.println("noteid " + note.getNoteId());
System.out.println("noteidHidden " + noteIdModel.getNoteIdHidden());
System.out.println("notedesc" + note.getNoteDescription());
noteService.editNote(note, authentication);
return "result";
}
However, the incoming noteId is null. I have checked the database and the note with correct id is indeed in the database and is also retrieved from the database. It's just not sent to the controller.
Try this one:
HTML fragment
<tr th:unless="${#lists.isEmpty(allNotes)}"
th:each="note : ${allNotes}">
<td>
<button type="button" class="btn btn-success"
th:data-noteId="${note.noteId}"
th:data-noteTitle="${note.noteTitle}"
th:data-noteDescription="${note.noteDescription}"
onclick="editNoteModal('updateNote', this.getAttribute('data-noteId'),this.getAttribute('data-noteTitle'),this.getAttribute('data-noteDescription'))">Edit
</button><br/>
<a class="btn btn-danger">Delete</a>
</td>
<td scope="row" th:text="${note.noteTitle}"></td>
<td th:text="${note.noteDescription}"></td>
</tr>
JS fragment
/**
* Fill edit modal with current information
*/
function editNoteModal(modal, noteId, noteTitle, noteDescription) {
$('#editnoteModalLabel').text("Note " + noteId);
$('#editNoteId').val(noteId);
$('#editNoteTitle').val(noteTitle);
$('#editNoteDescription').val(noteDescription);
$('#editNoteModal').modal("show");
}
/**
* Save to backend edit information
*/
function save() {
var noteId = $('#editNoteId').val();
var noteTitle = $('#editNoteTitle').val();
var noteDescription = $('#editNoteDescription').val();
$.ajax({
url : "./editNote",
method : "POST",
headers : {
'Content-Type' : 'application/json'
},
data : JSON.stringify({
noteId : noteId,
noteTitle : noteTitle,
noteDescription : noteDescription
}),
success : function(result) {
$('#editNoteModal').modal("hide");
alert(result);
}
})
}
Backend
#PostMapping(path = "/editNote", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> editNote(#RequestBody Note note) {
System.out.println("noteid " + note.getNoteId());
System.out.println("noteidTitle " + note.getNoteTitle());
System.out.println("notedesc" + note.getNoteDescription());
//Save in database
return ResponseEntity.ok("OK");
}
This is how I did while I was trying to pass the id to open a modal by finding details using that id:
<a href="#" class="btn btn-sm btn-primary"
th:data-parameter1="${user.useruuid}"
onclick="openUserModal(this.getAttribute('data-parameter1'));">Details</a>
And then somewhere in your JavaScript, you can something (similar) like this:
<script type="text/javascript" th:fragment="includeModalScript">
function openUserModal(id) {
$.ajax({
url: "/findOnebyId?id="+ id,
success: function(data){
alert(id);
.......
</script>
And my controller looked like this:
#GetMapping("/findOnebyId")
#ResponseBody
public AppUser findOneByUUID(String id) {
....
}
You can take a look here, here and here for a working demo similar to your issue/requirement.

Trying to delete data using modal popup, not getting correct id of selected item

I have a table view with many records and I want to have a delete button for each record, which will prompt a modal box for the user to confirm a delete. I am able to have the correct buttons (viewed from the table) to prompt the modal, but the button within the modal, which is the button to confirm a delete doesnt pass the right id. For example, I have 3 records in my table that is shown, with an ID of 1, 2 and 3. But the way I have code my table (will show code below) makes it where the user clicks any of the delete button on the desired record, the modal box pops up, with the "Delete(confirm)" button with an ID of the newest amongst all records. In this situation would be an ID of 3. I want it to pass the correct ID. Meaning if I want to delete record 1 it will pass ID 1 and record 2 and so on
I have tried researching what I did wrongly with my JavaScript but it seems ok and nothing seems to help for now. I have tried putting the whole modal into my table but it still has the same problem...
<!-- DataTables Example -->
<div class="card mb-3">
<div class="card-header">
<i class="fas fa-table"></i>
Advertisements
<div></div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Image</th>
<th>Status</th>
<th>Sort No.</th>
<th>Updated By</th>
<th>Expired At</th>
<th>Updated At</th>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
#foreach ($advertisements as $advertisement)
<tr>
<td>{{ $advertisement->media->title }}</td>
<td>{{ $advertisement->media->description }}</td>
<td><img src="{{asset('/storage/uploads/images/').'/'.$advertisement->image}}" height="65" width="100"></td>
#php
if ($advertisement->media->status == 1){
$current_status = 'Active';
} elseif ($advertisement->media->status == 0){
$current_status = 'Inactive';
}
#endphp
<td>{{ $current_status }}</td>
<td>{{ $advertisement->media->sort}}</td>
<td>{{ $advertisement->media->admin->username}}</td>
<td>{{ $advertisement->expired_at}}</td>
<td>{{ $advertisement->media->updated_at}}</td>
<td><a href="/advertisements/{{$advertisement->id}}/edit" class="btn btn-success">Edit</td>
<td>
<button class="btn btn-danger delete-record" data-toggle="modal" data-target="#deleteModal" data-id="{{$advertisement->id}}" data-url="/advertisements/{{$advertisement->id}}">Delete , {{$advertisement->id}}</button>
</td>
</tr>
#endforeach
</tbody>
</table>
</div>
</div>
<div class="card-footer small text-muted">Updated yesterday at 11:59 PM</div>
</div>
Above code is the table view showing my data, and each record will have a delete button next to it.
<form action="" method="post" id="deleteForm">
#method('DELETE')
#csrf
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Are you sure you want to delete this record?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="delete" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
</div>
</form>
The code above is my modal box code, with a form that creates a delete request.
The code below is the javascript that is handling the delete and the passing of id and the action:-
$(document).ready(function () {
$('.delete-record').click(function () {
var url = $(this).attr('data-url');
$("#deleteForm").attr("action", url);
});
});
I want it to pass the correct ID. Meaning if I want to delete record 1 it will pass ID 1 and record 2 and so on.
You try to send your form via POST method, but there is no post data such as advertising id in it.
Can you please show your web.php route file ?
Because if it's POST method here, you should to add hidden input in your form.
Try with this,
Instead of url you should use route,
<button class="btn btn-danger delete-record" data-toggle="modal" data-target="#deleteModal" data-id="{{$advertisement->id}}" data-action="{{ route('advertisements.destroy', $advertisement->id) }}">Delete , {{$advertisement->id}}</button>
In your JS code
$("#deleteForm").attr("action", $(this).data('action'));
And if you don't put your modal code outside foreach then put it in at end of file
Hope this helps :)

Retrieving table row information using ajax and pdo to display in bootstrap modal

Im trying to retrieve information from a table which is populated by a PDO array into a html table. I want to grab the row information when a user clicks on the 'delete button' for that row into a modal which i have for the delete confirmation.
I'm not sure how to go about doing this because the information returned is from the database and not hard-coded in.
<table class="table table-bordered table-hover" id="tab_logic">
<thead>
<tr >
<th class="text-center">
Course Code
</th>
<th class="text-center">
Course Title
</th>
</tr>
</thead>
<tbody>
<?php foreach ($courses as $row) {
echo "<tr><td>";
echo $row['course_code'];
echo "</td><td>";
echo $row['course_title'];
echo "</td><td>";
echo '<p data-placement="top"
data-toggle="tooltip"
style="margin-left:18px"
title="Delete">';
echo '<button class="btn btn-danger btn-xs"
data-title="Delete"
data-toggle="modal"
data-target="#delete">';
echo '<span class="glyphicon glyphicon-trash" />';
echo '</button></p>';
echo "</tr>"; }
?>
this is the code for the modal:
<div id="delete" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Delete Record</h4>
</div>
<div class="modal-body">
<p class="text-danger"><small>Are you sure you would like to delete this record?</small></p>
<p class="text-danger"><small>You will not be able to un-do this action</small></p>
<div class="form-group">
<input class="form-control " type="text" placeholder="Course Title">
</div>
</div>
<div class="modal-footer">
<button id="can" type="button" class="btn btn-warning" data-dismiss="modal">Cancel</button>
<button id= "upd" type="submit" class="btn btn-danger">Delete</button>
</form>
</div>
</div>
</div>
</div>
I know i will need AJAX to do this dynamically. Does anyone have any ideas of a solution? thanks
Here's the solution.
http://getbootstrap.com/javascript/#modals-related-target
You should add a new data attribute here:
'<button class="btn btn-danger btn-xs"
data-title="Delete"
data-index="yourItemIndex" <----- here
data-toggle="modal"
data-target="#delete">';
Your script should be something like this:
$('#exampleModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var recipient = button.data('whatever') // Extract info from data-* attributes
// If necessary, you could initiate an AJAX request here (and then do the updating in a callback).
// Update the modal's content. We'll use jQuery here, but you could use a data binding library or other methods instead.
var modal = $(this)
modal.find('.modal-title').text('New message to ' + recipient)
modal.find('.modal-body input').val(recipient)
})
Best regards.

Resources