Not able to print associated role with users in thymeleaf page - spring

I am new to spring boot, can someone help please!!
I have a controller that displays the settings page.
#GetMapping("/setting")
public String settings(Model model){
List<User> user = userDao.findAll();
model.addAttribute("user", user);
return "settings";
}
My query
#Query(value = "SELECT * FROM users u left join user_role ur on u.id = ur.user_id",nativeQuery=true)
List<User> findAll();
On render, the setting page looks like this.
I need to display user role like (Admin/Moderator etc) along with role ids
The mapping of user with role is many to many.
#ManyToMany(cascade=CascadeType.MERGE)
#JoinTable(
name="user_role",
joinColumns={#JoinColumn(name="USER_ID", referencedColumnName="ID")},
inverseJoinColumns={#JoinColumn(name="ROLE_ID", referencedColumnName="ID")})
private List<Role> roles;
In the setting page i am not able to get the value of role.
<tbody>
<tr th:each="u,iterator : ${user}">
<!-- <td th:text="${u.id}"></td> -->
<td th:text="${iterator.index+1}"></td>
<td th:text="${u.name}"></td>
<td th:if="${u.isActive}"><span class="status text-success">•</span> Active</td>
<td th:unless="${u.isActive}"><span class="status text-warning">•</span> InActive</td>
<td>****need to get role here***</td>
</tr>
</tbody>

I would do something like this:
<td><span th:each="role : ${u.roles}" th:text="${role.name}+' '"></span></td>
According in the Role class you have a name field.
The space at the end is just a separator in case you have multiple roles.

Related

Laravel: How to display OneToMany in a View

Help Please.
Newbie here. I need to display the name of Patron and Item instead of displaying their id. I have 3 tables:
Patrons (id, name), Items (id, name), Transactions (patron_id, item_id, loaned, due, returned)
Patron model
public function transaction ()
{
return $this->hasMany(Transaction::class);
}
Item model
public function transaction ()
{
return $this->hasMany(Transaction::class);
}
Transactions model
public function item()
{
return $this->belongsTo(Item::class);
}
public function patrons()
{
return $this->belongsTo(Patron::class);
}
This is the part where I'm really confused. I don't know how to code the TransactionController and the View.
Transaction Controller: (Is this even right?)
$transactions = Transaction::paginate(10);
return view('transactions.index')->with(compact('transactions'))->with('patrons', Patron::all())->with('items', Item::all());
index.blade.php (I don't know how to code this)
#foreach($transactions as $transaction)
<tr role="row" class="odd">
<td class="sorting_1 dtr-control">{{ $transaction->patron_id }}</td>
<td>{{ $transaction->item_id }}</td>
<td>{{ $transaction->Loaned }}</td>
<td>{{ $transaction->Due }}</td>
</tr>
#endforeach
The View displays like this:
1 1 2020-09-21
2 5 2020-09-21
But I need it to display like this:
John Doe Harry Potter 2020-09-21
Mary Jane Game of Thrones 2020-09-21
The issue is coming from how you are pulling data from the database and how you are pushing it to the view.
For retrieving data, you can eager load your transactions model with all of its relationships in one go and paginate at the same time:
$transactions = Transaction::with('patron', 'item')->paginate(15);
Take a look at the docs on views, there are a number of ways of transferring data. Compact works pretty well and is easy to understand with multiple returns, so I'll give an example of that here:
return view('transactions.index', compact('transactions'));
And that's it - just remember to type the variable transactions within quotes and not put the actual variable inside the compact method.
Then, because you have eager loaded the relationship, in your view you can now call upon the relationship name instead of just the id number. For example:
<td>{{ $transaction->item->name }}</td>
Suggest you rename the relationship from patrons to patron as it is a belongsTo.

Neither BindingResult nor plain target object for bean name error

Return List of objects
#RequestMapping("/mvt")
public String showMvt(Model model){
model.addAttribute("counts", mouvementRepository.findAll());
return"mvt_";
}
Update one line controller
#RequestMapping(value="/updateMvt/{idmvt}",method = {RequestMethod.GET})
public String updateMvt(#PathVariable(value = "idmvt") int idcpn, #Valid #ModelAttribute("mvt") Mouvement mvt,BindingResult result) {
mouvementRepository.save(mvt);
return "redirect:/mvt";
}
I tried To edit lanes inside tr th:each like this
<tr th:each="count:${counts}">
<form action="#" th:action="#{/updateMvt/{idmvt}(idmvt=${count.idmvt})}" th:object="${count}" method="put">
<table border="0" cellpadding="10">
<tr>
<td>etat</td>
<td>
<select class="select-css" th:field="*{count.etat}">
<option th:value="Enregistrement">Enregistrement</option>
<option th:value="Embarquement">Embarquement</option>
<option th:value="Decollé">Decollé</option>
<option th:value="Annulé" selected>Annulé</option>
<option th:value="null" selected>Aucun</option>
</select>
</td>
</tr>
</table>
</form>
I'm new to spring,i know this solution looks bad,but i'm trying to do my best.
so I tried to do it this way, but I get the error :
Neither BindingResult nor plain target object for bean name 'count'
available as request attribute
Update --------------------------------------------------------------------
so far I managed to create a wrapper class Like this
public class mvtForm {
private int version;
private List<Mouvement> mouvements;//Getters and setters are included
And in my controller I set the movements attribute like this :
#ModelAttribute("wrapper")
#RequestMapping(value = "/mvtall")
public String processQuery(#ModelAttribute mvtForm wrapper, Model model) {
wrapper.setMouvements(mouvementRepository.findAll());
model.addAttribute("wrapper",wrapper);
return "mvt_all";
}
Now I got the view that I needed,
but Is there a way to submit PUT to each lane using JpaRepository ?
th:object must reference an object from Model, not from iteration. So you need to pass count object to model in controller before loading the page, like for example by defining this method in your controller:
#ModelAttribute("updateCount")
public Count count() {
return new Count();
}
class Count should have a field int version that will be unique for each Count object, this is important for updating. Don't forget getters, setters and default constructor - this is important for Thymeleaf.
#ModelAttribute("listOfCounts")
public List<Count> listOfCounts() {
return listOfCounts; //has to be predefined somewhere in class
//as it will be reused throughout application.
}
When you iterate you will be iterating over a listOfCounts. However when updating and pressing update button you will be binding the updateCount object. Make sure to have a hidden field with version in thymeleaf. With this when receiving the update request in your controller, you will receive the updateCount object with the correct version, you can find the correct Count object from the listOfCounts via version and update it.

Submit form with only selected model attributes inside table (Spring Boot + Thymeleaf)

This is what I'm trying to do:
I have a with a table where I present model attribute which is a list of objects. I present them in table rows using "th:each"
With every row, I present a checkbox, intending to mark some of the presented table rows
I want to submit the form and POST only the list of selected model attributes (only those in the selected table rows)
This is how I present the model attribute list of objects inside table rows (I skipped irrelevant parts of the code):
<form class="form-horizontal"
th:action="#{'/supplier/define'}"
th:object="${foundSuppliers}" th:method="POST">
.....
<tr th:each="supplier, iterStat : ${foundSuppliers.suppliersDTO}">
<td class="hide" th:text="${supplier.id}">ID</td>
<td th:text="${supplier.name}">Name</td>
<td><input th:id="'chk_' + ${supplier.id}"
type="checkbox" th:field="*{foundSuppliers.suppliersDTO}" th:value="${supplier}">
</td>
</tr>
When I submit this form, my "foundSuppliers.suppliersDTO" list is empty even though I check at least one row in my table.
My controller method behind specified th:action (of "form" tag) is:
public String defineSuppliers(#ModelAttribute SupplierListDTO foundSuppliers, Model model) {
...
}
What should I do to actually populate foundSuppliers.suppliersDTO with a list of objects that I marked with checkbox?
To clarify, "foundSuppliers" is a model attribute I pass from controller, and it contains a list of suppliers. The class that I pass as "foundSuppliers" looks like this:
public class SupplierListDTO {
private List<SupplierDTO> suppliersDTO;
.....
}
And I use the same one as th:object inside "form" tag, this is the list I want to pass to backend controller when form is submitted, except the list should contain only the objects inside table rows where I ticked the checkbox.
First, make sure your entire table is enclosed in the same form (mind you, none of this code has been tested):
<form action="/....." method="POST">
<tr th:each="supplier : ${foundSuppliers}">
<td class="hide" th:text="${supplier.id}">ID</td>
<td th:text="${supplier.name}">Name</td>
<td><input th:id="'chk_' + ${supplier.id}" type="checkbox"></td>
</tr>
</form>
Then, on the controller side, you need a custom data binder converting your list of IDs to your domain objects.
#Component
public class IdToSupplierConverterFactory
implements ConverterFactory<String, Supplier> {
private static class IdToSupplierConverter<Supplier>
implements Converter<String, Supplier> {
#PersistenceContext
private EntityManager em;
public Supplier convert(String id) {
return em.findById(id, Supplier.class);
}
}
#Override
public <Supplier> Converter<String, Supplier> getConverter(
Class<Supplier> targetType) {
return new IdToSupplierConverter();
}
}
Spring should do the rest and map your paramaters to:
#PostMapping("/......")
public YourType myControllerMethod(#RequestParam List<Supplier> suppliers) {
return ...;
}
You can do that either through javascript or Spring Boot. Maybe the easiest way is to to give the your checkbox field a name and then retrieve it through your controller. This way, you can easily check if the value of that name/checkbox is null or not. You should come up with something like this:
#RequestMapping(value = "/supplier" , method = RequestMethod. POST)
public void getSuppliers(#RequestParam(value = "nameOfCheckBoxInThymeleaf", required = false) String checkboxValue)
{
if(checkboxValue != null)
{
// do some logic here - get a list of selected suppliers for example
}
else
{
// do some logic here
}
}

How can I pass a list of objects from Controller to View, where data is retrieved from database using Linq in ASP.Net MVC5

I am trying to pass a list of Objects from controller to View ,where the attributes of the objects are retrieved from database using LINQ. The MODEL Code is given below:
public class Department
{
[Key]
public int DepartmentId { get; set; }
[Required(ErrorMessage = "Enter Department Name")]
[DisplayName("Department Name")]
public string DepartmentName { get; set; }
}
The Controller Code is :
public ActionResult ShowDepartments()
{
var departmentList = db.Deapartment.Select(x => new
{
x.DepartmentId,
x.DepartmentName
}).ToList();
return View(departmentList);
}
And the View Code is:
#model List<PractiseMVC11_17_2017.Models.Department>
#{
ViewBag.Title = "ShowDepartments";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Show Departments</h2>
<div>
<table class="table table-bordered table-hover">
<tbody>
#foreach (var department in Model)
{
<tr>
<td>
#department.DepartmentId
</td>
<td>
#department.DepartmentName
</td>
</tr>
}
</tbody>
</table>
</div>
}
But when I run the project, it shows the following exception:
Exception Details: System.InvalidOperationException: The model item passed into the dictionary is of type 'System.Collections.Generic.List1[<>f__AnonymousType32[System.Int32,System.String]]', but this dictionary requires a model item of type 'System.Collections.Generic.List`1[PractiseMVC11_17_2017.Models.Department]'.
Shyju answer works because the object you are passing to the View happens to be the same as the database object. This will not always be the case (it's, in fact, better if it is not).
The correct way to handle this is to create a named object:
var departmentList = db.Deapartment.Select(x => new Department
{
x.DepartmentId,
x.DepartmentName
}).ToList();
(I'd go with the LINQ syntax, but the lambda syntax works just as well)
var departmentList =
(from x in db.Deapartment
select new Department
{
x.DepartmentId,
x.DepartmentName
}).ToList();
Your view is strongly typed to a collection of Department class objects. But in your action method, you are creating a list of new anonymous objects with this code
db.Deapartment.Select(x => new
{
x.DepartmentId,
x.DepartmentName
})
Here you are creating an anonymous object with the DepartmentId and DepartmentName property, for each item in the db.Deapartment collection. You are passing the result of the above code, which is a list of anonymous objects to the view. Your view now getting a different type than it is strongly typed to , hence you are getting the exception.
So simply pass ToList() on db.Deapartment and pass that to the view.
public ActionResult ShowDepartments()
{
var departmentList = db.Deapartment.ToList();
return View(departmentList);
}
Here departmentList variable will be a collection of Deapartment objects.

requestmap in spring mvc

i want to create a form in which user can set name, age, birthday and department which is another object..
in jsp i already have the form with the inputs of name, age and birthday. For department i already create the select/option tag with the results from hibernate/db.
The problem is when i sumbit and post the the mployee i have a lot of erros
#RequestMapping(value = { "/new" }, method = RequestMethod.POST)
public String saveEmployee(#Valid #ModelAttribute Employee employee,
#PathVariable("department") int department, BindingResult result,
ModelMap model) {
jsp file
<tr>
<td>
<select name="department">
<c:forEach var="dep" items="${departments}">
<option value="${dep.id}">${dep.name}</option>
</c:forEach>
</select>
</td>
</tr>
i want to pass with post the employee info with department id to create the employee
Your BindingResult parameter needs to go directly after your Employee parameter.

Resources