How to pass parameters to a modal using thymeleaf? - html

I just starting in a project where we're using thymeleaf and I'm new to the technology.
It's a simple modal to confirm an object to be deleted. So they want me to add the name of the item we're deleting on the message instead of a generic message like: "Are you sure you want to delete?"
They want: "Are you you want to delete Item_Name?"
So I need to pass this name as parameter.
That's the code I have the display the modal:
<button id="btnDelete" value="delete" type="button" class="btn-link" data-toggle="modal" data-object-id="12345" data-object-name="NNN" th:attr="data-object-id=''+${assignment.assignmentId}+'', data-object-name='/nonInstructionalWorkload/deleteAssignment?asssignmentId='+${assignment.assignmentId}+'', data-target='#deleteAssignmentModal'">
And that's the code I have on the modal html:
<form role="form" th:action="#{/deleteAssignment}"
name="assignmentDeleteForm" id="assignmentDeleteForm" method="post">
<div class="modal-header">
<h4 class="modal-title" id="deleteWorkItemabel">Confirm Assignment Delete</h4>
</div>
<div class="modal-body">
<div class="form-group">
<p>Assignment will be deleted, are you sure you want to proceed?</p>
<input type="hidden" id="deleteId" name="deleteId" value="nnnn"/>
</div>
</div>
<div class="modal-footer">
<button type="submit" id="btnDelConfirm" class="btn btn-primary">
Yes
</button>
<button type="button" id="btnDelCancel" class="btn btn-default" data-dismiss="modal">
No
</button>
</div>
</form>
At this point is where I need to add more information on the confirmation message about the assignment item being deleted.
Already tried some approached to get the parameters but didn't work so I'm looking for more option.
Thank you!

Thymeleaf is just template engine that takes your templeate and generate static html out of it. So passing dynamic values to your modal is a javascript work (unless you generate separate modal for each item, but this would be silly).
Using thymeleaf you have to generate a data- attribute containing desired item's name inside the button which opens modal, and that's all. You've already did such thing within th:attr:
th:attr="data-object-id=''+${assignment.assignmentId}+'', data-object-name='/nonInstructionalWorkload/deleteAssignment?asssignmentId='+${assignment.assignmentId}+'', data-target='#deleteAssignmentModal'"
The code above will generate attributes data-object-id,data-object-name and data-target inside the button. I assume that data-object-name is the one you want to use (however it looks more like an URL).
Now you can customize your modal's content using javascript. I can see, that you are using bootstrap as your frontend library, so you should take a look at this example, to have an idea how to accomplish that.
Javascript code below should work fine for you:
$('#deleteAssignmentModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var objectName = button.data('object-name') // Extract info from data-object-name attribute
// 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-body p').text('Do you want to delete ' + objectName + '?')
})

The sample project on GitHub you can clone and test it. Full video under the readme.
https://github.com/ibrahimkarayel/todoBoot/blob/master/src/main/resources/templates/home.html
<div class="modal modal-delete" th:id="modal-delete+${task.id }">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×
</button>
<h3 id="delModalLabel">Delete Confirmation</h3>
</div>
<div class="modal-body">
<p class="error-text"><strong>Are you sure you want to
delete this task ?</strong></p>
</div>
<div class="modal-footer">
<button class="btn " data-dismiss="modal" aria-hidden="true">
Cancel
</button>
<a th:href="#{/task/delete/{id}(id=${task.id})}">
<span class="btn btn-danger" value="delete">Delete</span></a>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!--end delete modal-->
<script>
$('#modal-delete').on('show.bs.modal', function (e) {
$(this).find('.btn-ok').attr('href', $(e.relatedTarget).data('href'));
$('#modal-deleteHiddenId').val($(this).find('.btn-ok').attr('href'));
});
</script>

Related

Closing Blazor modal with multiple modals

First of all, I've seen this Close Bootstrap Modal but of some reason it's not working for me.
I have a page, where one modal is called from like this
<button type="button" #onclick="#(()=>modal.Show<LandingPageHelpPopUp>())" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#myModal">Click here to get help</button>
That page's code look like this
<div class="modal-dialog" id="myModal" style="margin-left:-200px;margin-bottom:-550px;position:absolute;">
<div class="modal-content" style="background-color:gray;">
<div class="modal-body" style="color:black;">
<p>Here you can observe the controlling of the curtains by others. If the queue is empty, and you'll like the control, hit this button.</p>
<div class="modal-footer" style="float:right;border:none;margin-bottom:-25px;">
<label class="custom-close" #onclick="#(()=>modal.Show<LandingPageHelpPopUp2>())">Next page</label>
<button class="next-button" style="margin-left:-3px;"><i class="fa fa-angle-right"></i></button>
</div>
</div>
</div>
</div>
<img src="css/arrow-help.png" class="arrow-help">
From here, I'd like to see another modal. To do that, I guess I have close the first one first, in order to not create a double layer of modals - if that makes sense. That's where I have used the linked thread in the beginning, but somehow it doesn't work.
The second modal's code look like this
<div class="modal-dialog" id="myModal2" style="margin-left:-200px;margin-bottom:-550px;position:absolute;">
<div class="modal-content" style="background-color:gray;">
<div class="modal-body" style="color:black;">
<p>If other users is in the queue, click here to get in line.</p>
<div class="modal-footer" style="float:right;border:none;margin-bottom:-25px;">
<label #onclick="#(()=>modal.Show<LandingPageHelpPopUp>())">Previous page</label>
<button class="next-button" style="margin-left:-3px;margin-top:-2px;"><i class="fa fa-angle-right"></i></button>
</div>
</div>
</div>
</div>
<img src="css/arrow-help2.png" class="arrow-help2">
In my index.html I've these two scripts, that is meant to toggle the modals. That is if one modals is open, when the other one is shown, it should close.
<script>
$(function () {
$(".custom-close").on('click', function () {
$('#myModal').modal('hide');
});
});
</script>
<script>
$(function () {
$(".custom-close2").on('click', function () {
$('#myModal2').modal('hide');
});
});
</script>
Here's some screenshots, showing that the previous modal does not get closed, so it's just creating multiple layers of modals on top of each other. Here, Here, And here
Sorry for all the unnecessary code (styling, bad naming etc)
Doe any of you know why the previous modal is not getting closed, whenever the next is getting shown?

Vue's v-for does not show correct text for modal window (only displays the first item's data)

I'm using Vue (just started learning it) and Bootstrap to make a blog and I want a modal window (that shows the post's name/etc) to pop up when the user clicks on the comment button. However, right now the modal window only gets the post information from the latest blog post. This means that even if you click the 1st post, you would get the id information and post title of the latest one... Any suggestions or solutions? Thanks in advance!
It seems that the main problem with my code is that it makes n numbers of modals in vue if you have n posts. I have tried slots but the modals started displaying the first post instead of the last one. I wonder if all my modals are being displayed at once but I only the last one... Should I use an index instead?
Is there any way to make only one modal that gets and display the information of the post clicked?
Here's my code of the post component
Vue.component('posts', {
props: ['post', 'loggedUser'],
template: `
<div class='blog-post py-2'>
<h3> {{post.title}} </h3>
<h6> Posted by {{post.postedBy}} on {{formatCompat(post.createdAt)}} </h6>
<span class='comments'>
<i class='far fa-comment-dots ml-3' data-toggle="modal" data-target="#commentModal"></i>
{{post.comments.length}}
</span>
</div>
`
My modal component: (mostly from the bootstrap docs)
Vue.component('modal', {
props: ['post'],
template: `
<div>
<div class="modal fade" id="commentModal" tabindex="-1" role="dialog" aria-labelledby="commentModalLabel" 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="commentModalLabel">Comment on {{post.postedBy}}'s post! ({{post.title}})</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
`
})
Here, I'd like the {{posted.title}} and other information to reflect the post where the comment button is clicked, but it's showing the latest post.
Parent element:
const postComponent = new Vue({
el: '#posts',
data: {
posts: null
},
methods: { // mostly code unrelated to modal stuff
}
My pug file:
#posts
if user
posts(name=username, v-for='post in posts' v-bind:post='post' v-bind:key="post.id" v-on:like-post='like' logged-user=loggedUser v-on:comment-post='comment')
modal(v-for='post in posts' v-bind:post='post' v-bind:key="post.id")
You need to add a custom data property that reflects the selected post for the template to read.
data: {
...
selected: '',
...
}
Then, you need a method that will assign the selected property to whichever post is clicked.
methods: {
changeTitle(postId) {
const currentPost = posts.filter((post) => {
return post.id == postId;
});
this.selected = currentPost.id;
}
}
So now that you have a data property to represent the current selected title, and a method to change that property with a click, you need to assign the directive for the method to the post. So, add this to the html tag you want to trigger the method:
#click = "changeTitle(postId);"
This will trigger the method along with the post id from the post that called the method. The current title can now be rendered anywhere in the template that has access to the data, like this:
{{selected}}

Print html code with angular2

I'm trying to print a button in html passing it as a parameter in angular2 but angular2 never translate it.
modal.component.ts
this.footer = `<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>`
modal.component.html
<div class="modal-footer" [innerHTML]="footer"></div>
output html
<div class="modal-footer" ng-reflect-inner-h-t-m-l="Close">Close</div>
Should be innerHtml instead of innerHTML. It is case sensitive.
For example :
<div class="modal-footer" [innerHtml]="footer"></div>

pass expressions to modal view in angular js

</tr>
<tr ng-repeat="product in products">
<td>{{$index + 1}}</td>
<td><a ng-href="">{{product.productName}}</a> </td>
<td>{{product.shortDescription}}</td>
<td>{{product.url}}</td>
<td>{{product.likes}}</td>
<td><img src="img/trash.png" alt="Delete" data-toggle="modal" data-target="#myModal">
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">× </button>
<h4 class="modal-title">Delete Pitch</h4>
</div>
<div class="modal-body">
<p>Do you really want to delete the pitch?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" ng-click="closebtn(product.productName)">Delete</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button></td>
</div>
</div>
</div>
</div>
</tr>
Am creating a list of products from a service. Wen the user clicks on delete button in a particular row, i want to pass the corresponding product name as a parameter to the function. Have created a modal view to ensure the delete using bootstrap. The ng-click method picks only the first productname in the list whichever row am selecting. Please help to fix this.
Instead of using the Bootstrap javascript, you should use a directive like the modal of ui-bootstrap. See this
You add an ng-click to your image and pass the item to the modal. With the callback of the opened modal you can decide to delete your item or not.
try this:
<td><img src="img/trash.png" alt="Delete" data-toggle="modal" data-target="#myModal" ng-click="productToDelete = product"></td>
your button:
<button type="button" class="btn btn-default" data-dismiss="modal" ng-click="closebtn(productToDelete.productName)">Delete</button>
in the solution below you define productToDelete variable, that take value after clicking by img, further you can work with this variable
When the click event is fired the variable product used within the loop references to the same object because it's overwrittern each cycle and point to the last object.
try this way:
ng-click="closebtn(products[$index].productName)
First of all, use ui-bootstrap plugin instead of bootstrap's JavaScript. It has $uibModal service to manage modal windows with AngularJS style. Your code should be look like this:
Main view
<tr ng-repeat="product in products">
<td>{{$index + 1}}</td>
<td><a ng-href="">{{product.productName}}</a> </td>
<td>{{product.shortDescription}}</td>
<td>{{product.url}}</td>
<td>{{product.likes}}</td>
<td><img src="img/trash.png" alt="Delete" ng-click="delete(product)"></img></td>
</tr>
Click-handler in your controller
$scope.delete = function(product) {
$uibModal.open({
controller: 'your-modal-controller',
templateUrl: 'path-to-modal-template',
resolve: {
productToDelete: product
}
}).result.then(function(success){
// delete product from list
})
};
Don't forget to inject $uibModal. resolve property allows you to pass your product to controller named your-modal-controller. Then you can get any property of product. For example, it's name.
If you need only pass the product name, you can use this resolve block:
resolve {
productName: product.productName
}

MVC 4 Bootstrap Modal Edit \ Detail

Hoping someone might be able to help me with something I am experimenting with in MVC 4 using bootstrap.
I have a strongly-typed index view which displays items in a table along with edit and delete action icons in each line.
#model IEnumerable<Models.EquipmentClass>
....
#foreach (var item in Model)
{
<tbody>
<tr>
<td>
#item.ClassId
</td>
<td>
#item.ClassName
</td>
<td>
<a href=#Url.Action("Edit", "EquipmentClass", new { id = item.ClassId })>
<i class="icon-edit"></i>
</a>
<a href=#Url.Action("Delete", "EquipmentClass", new { id = item.ClassId })>
<i class="icon-trash"></i>
</a>
</td>
</tr>
</tbody>
} <!-- foreach -->
The EquipmentClass controller returns the Edit view for the selected item based on the id. All great and as expected at this point
public ViewResult Edit(int id)
{
return View(equipmentclassRepository.Find(id));
}
What I would like to know is how to open the edit form in a bootstrap modal dialog.
I could try and substitute the edit action in the table with the following and then have a modal div at the bottom of the view but how do I pass in the ID of the selected item and which html helper should I use in the modal section?
<!-- replaced table action -->
<a class="btn pull-right" data-toggle="modal" href="#myModal" >Details</a>
....
<!-- modal div -->
<div class="modal hide fade in" id="myModal" )>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3>Modal header</h3>
</div>
<div class="modal-body">
#Html.Partial("Edit")
</div>
<div class="modal-footer">
Close
Save changes
</div>
</div>
I'd greatly appreciate any advice, many thanks
I think that I have a solution to your problem. To make your MVC application work as you want it to you should make some changes to the code you provided:
1. Add a div representing a modal for editing an item at the bottom of your layout page:
<div id="editModalContainerID" class="modal hide fade" data-url='#Url.Action("Edit", "EquipmentClass")'>
<div id="editModalBodyID"></div>
</div>
Notice that this modal is strictly connected to the controller action responsible for editing an EquipmentClass item.
2. Add a jQuery function to your custom javaScript:
function showModal(modalContainerId, modalBodyId, id) {
var url = $(modalContainerId).data('url');
$.get(url, { id: id }, function (data) {
$(modalBodyId).html(data);
$(modalContainerId).modal('show');
});
}
As you can see this function takes id as one of its parameters. In general its purpose is to replace the empty modal body with what we will put in a separate partial view and than display whole container as a modal page.
3. Put your modal div in a separate partial view, and call it Edit (has to be the same as your controller action name). You will have to change your Edit partial name to sth else, for example EditBody.
The Edit partial view should now look sth like this:
#model EquipmentClass
<!-- modal div -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3>Modal header</h3>
</div>
<div class="modal-body">
#Html.Partial("EditBody", Model)
</div>
<div class="modal-footer">
Close
Save changes
</div>
4. Change the controller action so that it returns the partial view created in the previous step:
public PartialViewResult Edit(int id)
{
return PartialView(equipmentclassRepository.Find(id));
}
5. Change the edit 'a' anchor so that it calls created jQuery function:
#model IEnumerable<Models.EquipmentClass>
....
#foreach (var item in Model)
{
<tbody>
<tr>
<td>
#item.ClassId
</td>
<td>
#item.ClassName
</td>
<td>
<a data-toggle="modal" onclick="showModal('#editModalContainerID', '#editModalBodyID', #item.ClassId)">
<i class="icon-edit"></i>
</a>
<a href=#Url.Action("Delete", "EquipmentClass", new { id = item.ClassId })>
<i class="icon-trash"></i>
</a>
</td>
</tr>
</tbody>
} <!-- foreach -->
This way each time an 'a' anchor with edit icon is clicked the showModal function (with related id being passed) is fired and a bootstrap modal with related data is displayed.
I'm sure there is a better way to do it, but this way worked for me just fine :)
Hope this helps you a bit :)
Przemo answer worked for me, however do note that I only managed to get it to work when I changed the first block of code from
<div id="editModalContainerID" class="modal hide fade" data-url='#Url.Action("Edit", "EquipmentClass")'>
<div id="editModalBodyID"></div>
</div>
to
<div id="editModalContainerID" class="modal fade" data-url='#Url.Action("Edit", "EquipmentClass")'>
<div id="editModalBodyID"></div>
</div>
Notice that I removed the "fade" class from editModalContainerID. Otherwise the partial view does not load. Hope this helps anyone else with the same issue.