Service layer doesn't delete entity? - spring-boot

I have a controller that must delete my entity:
#GetMapping ("/delete")
#PreAuthorize ("hasAuthority ('Admin')")
public String deleteStudent (Long studentId, String keyword) {
studentService.removeStudent(studentId);
return "redirect:/students/index?keyword="+keyword;
}
and HTML page that represent my entity:
<div class="container mt-3">
<div class="card-header">List of Students</div>
<div class="card-body">
<table class="table mt-3">
<thead>
<tr class="text-center">
<th>Student Id</th>
<th>Student First Name</th>
<th>Student Last Name</th>
<th>Student Level</th>
</tr>
</thead>
<tbody>
<tr class="text-center" th:each="student: ${list}">
<td th:text="${student.getStudentId()}"></td>
<td th:text="${student.getFirstName()}"></td>
<td th:text="${student.getLastName()}"></td>
<td th:text="${student.getLevel()}"></td>
<td>
<a onclick="confirm ('Are you sure')" class="btn btn-danger"
th:href="#{students/delete(studentId=${student.getStudentId()}, keyword=${keyword})}"> Delete </a>
</td>
</tr>
</tbody>
</table>
</div>
My Service
public interface StudentService {
void removeStudent (Long studentId);
I run application, open http://localhost:8071/students/index everything work okay, but when I delete my entity I'm getting:
ERROR PAGE There was an unexpected error (type=Not Found, status=404).
-> http://localhost:8071/students/students/delete?studentId=1&keyword=

You have students duplicated in the path, hence 404:
http://localhost:8071/students/students/delete
Your line
th:href="#{students/delete(studentId=${student.getStudentId()}, keyword=${keyword})}"
Should be:
th:href="#{delete(studentId=${student.getStudentId()}, keyword=${keyword})}"

Related

Perform conditions in ThymeLeaf in Spring Boot project

I am using Spring Boot Thymeleaf and wanted to take conditional based decision. If condition matches, then whole row should be green else red
<body>
<div class="container my-2">
<h1>Active Workflow Details</h1>
<div class="card">
<div class="card-body">
<div th:switch="${mdsAcives}" class="container my-5">
<div class="col-md-10">
<h2 th:case="null">No record found !!</h2>
<div th:case="*">
<table border="1" class="table table-striped table-responsive-md">
<thead>
<tr>
<th>Mapping Name</th>
<th>Type of Mappings</th>
<th>Table Names</th>
<th>System 1 Count </th>
<th>System 2 Count </th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr th:each="m : ${mdsAcives}">
<td th:text="${m.mappingName}"></td>
<td th:text="${m.type}"></td>
<td th:text="${m.tableName}"></td>
<td th:text="${m.system1Cnt}"></td>
<td th:text="${m.system2Cnt}"></td>
<td th:style="${m.system1Cnt} eq ${m.system2Cnt} ? 'color: red;' : 'color: green;'}}" th:text="TRUE or FALSE"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
You can do something like this:
<tr th:class="${your condition}? 'green' : 'red'">
I assume you have defined two CSS classes to make the row green or red.

How to create a template view table tag without repeating table tags on every file

I'm developing a system which has many tables so I have to repeat the writing of table tags on all the files which display a table
Here is what I'm doing on every file which have to display table
On Countries table:
<table class="table table-striped table-hover table-sm" id="table">
<thead class="text-uppercase text-center bg-primary">
<tr class="text-white">
<th scope="col">Name</th>
<th scope="col">Slug</th>
<th scope="col">Population</th>
<th scope="col">Region</th>
<th scope="col">Cities</th>
<th scope="col">Descriptions</th>
<th scope="col" >Actions</th>
</tr>
{{ csrf_field() }}
</thead>
<tbody>
#foreach ($countries as $country)
<tr>
<td class="text-left">{{$country->name}}</td>
<td class="text-center">{{$country->slug}}</td>
<td class="text-right">{{$country->population}}</td>
<td class="text-center">{{$country->region->name}}</td>
<td class="text-center">{{$country->city_count}}</td>
<td class="text-left">{{$country->desc}}</td>
<td class="text-center">
<div class="btn-group">
#can('country-update')
<a class="btn btn-primary btn-sm mr-2" href="{{route('location.countries.edit',$country)}}" title="Edit"><i class="fa fa-edit"></i></a>
#endcan
#can('country-delete')
<form class="form-delete" method="post" action="{{route('location.countries.destroy',$country)}}">
#method('DELETE')
#csrf
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('Are you sure?')"><i class="fa fa-trash-alt"></i></button>
</form>
#endcan
</div>
</td>
</tr>
#endforeach
</tbody>
</table>
then on the cities I'll do the same but with different table head names and table data
<table class="table table-striped table-hover table-sm" id="table">
<thead class="text-uppercase text-center bg-primary">
<tr class="text-white">
<th scope="col">Name</th>
<th scope="col">Slug</th>
<th scope="col">Country</th>
<th scope="col">Descriptions</th>
<th scope="col" >Actions</th>
</tr>
{{ csrf_field() }}
</thead>
<tbody>
#foreach ($cities as $city)
<tr>
<td class="text-left">{{$city->name}}</td>
<td>{{$city->slug}}</td>
<td class="text-center">{{$city->country->name}}</td>
<td class="text-left">{{$city->desc}}</td>
<td class="text-center">
<div class="btn-group">
#can('city-update')
<a class="btn btn-primary btn-sm mr-3" href="{{route('location.cities.edit',$city)}}" title="Edit"><i class="fa fa-edit"></i></a>
#endcan
#can('city-delete')
<form class="form-delete" method="post" action="{{route('location.cities.destroy',$city)}}">
#method('DELETE')
#csrf
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('Are you sure?')" title="delete"><i class="fa fa-trash-alt"></i></button>
</form>
#endcan
</div>
</td>
</tr>
#endforeach
</tbody>
</table>
but I wat to have a template where I'll only populate table head rows and table body something like this
<div class="table-responsive">
<table class="table table-striped table-hover table-sm" id="table">
<thead class="text-uppercase text-center">
<tr>
//Dynamic table heads
#if(!is_null($rows))
#foreach($rows as $row)
{{$row}}
#endforeach
#endif
</tr>
</thead>
<body>
//Dynamic table body
#if(!is_null($datas))
#foreach($datas as $data)
{{$data}}
#endforeach
#endif
</tbody>
</table>
<!-- end table -->
</div>
What is the best way to accomplish this
You can use Blade component for that. One of approaches in Laravel 7 is to use Blade class component. Link to official Blade components docs: https://laravel.com/docs/7.x/blade#components
You can create a generic table component using artisan command:
php artisan make:component Table
Component class
Your component could look like that:
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Table extends Component
{
/**
* Array of table heading strings
*
* #var array
*/
public $headings;
/**
* Table rows
*
* #var array
*/
public $rows;
/**
* Create the component instance.
*
* #param string $type
* #param string $message
* #return void
*/
public function __construct($headings, $rows)
{
$this->headings = $headings;
$this->rows = $rows;
}
/**
* Get the view / contents that represent the component.
*
* #return \Illuminate\View\View|string
*/
public function render()
{
return view('components.table');
}
}
Component view
Now when you have component class, you have to prepare the component view. You will found it in /resources/views/components/table.blade.php.
<div class="table-responsive">
<table class="table table-striped table-hover table-sm" id="table">
//Dynamic table heads
#if($headings)
<thead class="text-uppercase text-center">
<tr>
#if($rows))
#foreach($rows as $row)
<th>{{$row}}</th>
#endforeach
#endif
</tr>
</thead>
#endif
<tbody>
//Dynamic table body
#foreach($rows as $row)
<tr>
// Render each item from row
#foreach($row as $item)
<td>{{$item}}</td>
#endforeach
</tr>
#endif
</tbody>
</table>
<!-- end table -->
</div>
Now you can use your component in your views:
<x-table :headings="['foo', 'bar']"
:data="[['foo1', 'bar1'], ['foo2', 'bar2']]" class="mt-4"/>

Why <td th:each="i : ${#numbers.sequence(0, table_width)}" th:text="${rows[${i}]}"></td> not working

I am trying to Iterate through a list which contains a list of objects, i.e. List I am wondered why this is not working, tried with simply "i", but no luck.
List<Object[]> lists; // logic
model.addObject("lists", lists);
model.addObject("table_width", lists.get(0).length);
Thymeleaf Code Snippet
<table class="table table-responsive table-stripped table-collapsed table-bordered">
<tr th:each="rows,rowStat : ${lists}">
<td th:text="${rowStat.count}"></td>
<td th:each="i : ${#numbers.sequence(0, table_width)}" th:text="${rows[${i}]}"></td>
</tr>
</table>
I have found a way,
<td th:each="i : ${#numbers.sequence(0, table_width-1)}" th:text="${rows[__${i}__]}"></td>
This does the tricks
You can simply iterator over both lists. No need to use the #numbers helper.
<table class="table table-responsive table-stripped table-collapsed table-bordered">
<tr th:each="rows, rowStat : ${lists}">
<td th:text="${rowStat.count}"></td>
<td th:each="value: ${rows}" th:text="${value}"></td>
</tr>
</table>
If you are iterating a collection(list) of objects, try below example:
HTML:
<div th:if="${not #lists.isEmpty(counts)}">
<h2>Counts List</h2>
<table class="table table-striped">
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr th:each="count : ${counts}">
<td th:text="${count.id}"></td>
<td th:text="${count.name}"></td>
</tr>
</table>
</div>
Java:
public List<Count> listAll() {
List<Count> counts = new ArrayList<>();
countRepository.findAll().forEach(counts::add);
return counts;
}
Read more info in Thymeleaf Documentation - Iteration Basics section.

ng-repeat and the mouseover event

this seems like a scope problem, but i am not sure. my goal is to highlight a single row in a table. that implies that any previously highlighted row is returned to an unhighlighted state. the rows are created with the ng-repeat directive, like this:
<div id="myFedContents" style="height:320px" ng-controller="Controller2" class="scroller">
<table border="0" class="span12 table table-condensed" style="margin-left:0px" id="tblData">
<thead>
<tr><th>Year</th><th>Name</th><th>Useful Flag</th></tr>
</thead>
<tbody id="allRows">
<tr ng-repeat="item in itemlist | filter:thisText" ng-style="myStyle"> <td class="span1" valign="top"><a tabindex="-1" href="#">{{item.year}}</a></td>
<td id="{{item.id}}"> <a tabindex="-1" href="#" ng-click="myStyle={'background-color':'#cccccc'};">{{item.name}}</a>
</td> <td>
{{item.usefulflag}
</td> </tr>
</tbody>
</table>
</div>
i have code in a .js file that looks like this:
$("tr").mouseenter(function(){
alert("mouseenter");
});
the row in the table header reacts with the alert, but there is no reaction from the rows created by ng-repeat. how do i correct?
You can actually achieve this effect by using an ng-class in conjuction with ng-mouseenter and ng-mouseleave like so:
<div id="myFedContents" style="height:320px" ng-controller="Controller2" class="scroller">
<table border="0" class="span12 table table-condensed" style="margin-left:0px" id="tblData">
<thead>
<tr>
<th>Year</th>
<th>Name</th>
<th>Useful Flag</th>
</tr>
</thead>
<tbody id="allRows">
<tr ng-repeat="item in itemlist | filter:thisText" ng-style="myStyle" ng-class="highlightclass" ng-mouseenter="highlightclass='highlight'" ng-mouseleave="highlightclass=''">
<td class="span1" valign="top"><a tabindex="-1" href="#">{{item.year}}</a>
</td>
<td id="{{item.id}}"> <a tabindex="-1" href="#" ng-click="myStyle={'background-color':'#cccccc'};">{{item.name}}</a>
</td>
<td>
{{item.usefulflag}
</td>
</tr>
</tbody>
</table>
</div>
In this case you don't need the jquery syntax. If you haven't already you should also read https://stackoverflow.com/a/15012542/281335.

MVC3 ASP Replace null value with empty space on the view

I have the following view which returns some text if the POnumber is null.
What I think I need to have instead of the if(Model.Invoice.PONumber == null) is a check mechanism ( maybe multiple if statements ) that will check the fields LineNumber, Description, UnitOfMeasure, QtyOrdered and if any of them is null it will replace it with N/A or empty space but it will still allow the user to see the rest of information available.
Do you have any sugestions? I am new to MVC and any help will be apreciated.
Thank you in advance for your time and help,Bobby
<div class="contentWrapper2">
<div class="content2">
<div class="clr lfl w100">
<h1>Invoice Detail</h1>
<div class="return-btn">
<a class="btn btnStyleC btn-back-invoice" href="#Url.Action("InvoiceHistory", "Account")">
Back to Invoice List</a>
</div>
</div>
#if (Model.ErpError.Length > 0)
{
<div class="clr lfl w100 error">
#Html.Raw(Model.ErpError)
</div>
}
else
{
if(Model.Invoice.PONumber == null)
{
<div class="lfl w100 clr messaging">
<p>No information available at the moment for current invoice.
Please call our sales department for further assistance.
</p>
</div>
}
else
{
<div class="clr lfl w100">
<div class="order-number-date">
<table>
<tr>
<th class="col-1">
<h3>Invoice #:</h3>
</th>
<td class="col-2">
<h3>#Model.Invoice.InvoiceNumber</h3>
</td>
</tr>
<tr>
<th class="col-1">
<h3>Invoice Date:</h3>
</th>
<td class="col-2">
<h3>#Model.Invoice.InvoiceDate.ToShortDateString()</h3>
</td>
</tr>
</table>
</div>
<div class="order-number-date">
<table>
<tr>
<th class="col-1">
<h3>Order #:</h3>
</th>
<td class="col-2">
<h3>#Model.Invoice.OrderNumber</h3>
</td>
</tr>
<tr>
<th class="col-1">
<h3>PO #:</h3>
</th>
<td class="col-2">
<h3>#Model.Invoice.PONumber</h3>
</td>
</tr>
<tr>
<th class="col-1">
<h3>Due Date:</h3>
</th>
<td class="col-2">
<h3>#Model.Invoice.DueDate.ToShortDateString()</h3>
</td>
</tr>
</table>
</div>
</div>
<div class="clr lfl w100">
<div class="bill-ship">
<table>
<tr>
<th>
<h4>Billing Information</h4>
</th>
</tr>
<tr>
<td>#Model.Invoice.BTDisplayName
</td>
</tr>
<tr>
<td>
<#Html.Raw(Model.Invoice.BTAddress1)
</td>
</tr>
#if (!string.IsNullOrEmpty(Model.Invoice.BTAddress2))
{
<tr>
<td>#Html.Raw(Model.Invoice.BTAddress2)
</td>
</tr>
}
<tr>
<td>#Html.CityCommaStateZip(Model.Invoice.BTCity, Model.Invoice.BTState, Model.Invoice.BTZip)</td>
</tr>
<tr>
<td>#Model.Invoice.BTCountry
</td>
</tr>
<tr>
<td>#Model.Invoice.BTPhone1</td>
</tr>
<tr>
<td>#Model.Invoice.BTEmail
</td>
</tr>
</table>
</div>
</div>
if (Model.Invoice.InvoiceLines.Count > 0)
{
<div class="clr lfl w100 line-item-detail">
<table class="info-tbl">
<tr>
<th class="vid-item">Item #</th>
<th class="vid-desc">Description</th>
<th class="vid-um">
U/M
</th>
<th class="vid-qty">
Qty
</th>
<th class="vid-ship">
Ship Date
</th>
#if (Model.ShowPackslip)
{
<th class="vid-pack">Pack Slip</th>
}
<th class="vid-unit">Unit Price</th>
<th class="vid-ext">Ext Price</th>
</tr>
#foreach (var invoiceLine in Model.Invoice.InvoiceLines)
{
<tr>
<td class="vid-line">#invoiceLine.LineNumber</td>
<td class="vid-desc">#invoiceLine.Description</td>
<td class="vid-um">#invoiceLine.UnitOfMeasure</td>
<td class="vid-qty">#invoiceLine.QtyOrdered</td>
<td class="vid-ship">
#if (invoiceLine.ShipDate.ToShortDateString() == "1/1/0001")
{
}
else
{
#invoiceLine.ShipDate.ToShortDateString()
}
</td>
#if (Model.ShowPackslip)
{
<td class="vid-pack">
#invoiceLine.PackSlip
</td>
}
<td class="vid-unit">#invoiceLine.UnitPrice.ToCurrency()
</td>
<td class="vid-ext">#invoiceLine.ExtendedPrice.ToCurrency()
</td>
</tr>
}
</table>
</div>
}
<div class="clr lfl w100">
<table class="tbl-total">
<tr class="subtotal">
<th class="col-1">Subtotal</th>
<td class="col-2">#Model.Invoice.OrderSubTotal.ToCurrency()
</td>
</tr>
#if (Model.Invoice.DollarOffOrder > 0)
{
<tr>
<th class="col-1">Order Discount</th>
<td class="col-2">#Model.Invoice.DollarOffOrder.ToCurrency()</td>
</tr>
}
#if (Model.Invoice.ShippingAndHandling > 0)
{
<tr>
<th class="col-1">Shipping</th>
<td class="col-2">#Model.Invoice.ShippingAndHandling.ToCurrency()
</td>
</tr>
}
#if (Model.Invoice.MiscCharges > 0)
{
<tr>
<th class="col-1">Misc. Charges</th>
<td class="col-2">#Model.Invoice.MiscCharges.ToCurrency()</td>
</tr>
}
<tr>
<th class="col-1">Sales Tax</th>
<td class="col-2">#Model.Invoice.TotalTax.ToCurrency()</td>
</tr>
<tr>
<th class="col-1">Invoice Total</th>
<td class="col-2">#Model.Invoice.InvoiceTotal.ToCurrency()</td>
</tr>
</table>
</div>
<div class="clr lfl w100">
<a class="btn btnStyleB btn-print" href="javascript:window.print();">Print</a>
</div>
}
}
</div>
</div>
You could create a template called for example "nullcheck.cshtml" like:
#if (ViewBag.ValueToCheck == null) {
<div class="lfl w100 clr messaging">
<p>
No information available at the moment for #(ViewBag.Field).
Please call our sales department for further assistance.
</p>
</div>
}
else {
#Html.Partial(ViewBag.TargetTemplate, Model)
}
Then you call it from your main view:
#{
ViewBag.TargetTemplate = "okModel";
ViewBag.Field = "P.O.Number";
ViewBag.ValueToCheck = Model.Invoice.PONumber;
Html.RenderPartial("nullCheck", Model, ViewBag);
}
okModel.cshtml should be the part of your template you will display when the value is not null...
I haven't tested this myself but it should give you some ideas... contact me if things go wrong XD
Cheers!
This seems like something you should take care of in your controller.
public ActionResult YourControllerAction()
{
var myViewModel = SomeService.GetMyViewModel();
if (myViewModel.Invoice.PONumber == null)
{
myViewModel.Invoice.PONumber = "N/A";
}
//etc
}
This leaves your view clearer (my personal preference)
However in the view you could simply use the null coalescing operator like so:
#Model.Invoice.PONumber ?? "NA"

Resources