Many To one datatable spring mvc hibernate with ajax - spring-boot

I was trying to show the model with dataTable in Spring but how can i get the value from the #ManyToOne relationship ? Below is my code
Model file - I want to get
"private long usersId" from Users model and "private long roles_id" from Role model but i don't know how to get it out
package com.hospital.model;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity(name="users_roles")
public class Users_Roles implements Serializable{
private static final long serialVersionUID = -1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "users_roles_id", updatable = false, nullable = false)
private long users_roles_id;
#JsonIgnore
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "users_id", nullable = false, updatable = false, insertable = false, referencedColumnName = "users_id")
private Users users;
#JsonIgnore
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "roles_id", nullable = false, updatable = false, insertable = false, referencedColumnName = "roles_id")
private Role roles;
private boolean status;
public Users_Roles() {
}
public long getUsers_roles_id() {
return users_roles_id;
}
public void setUsers_roles_id(long users_roles_id) {
this.users_roles_id = users_roles_id;
}
public Users getUsers() {
return users;
}
public void setUsers(Users users) {
this.users = users;
}
public Role getRoles() {
return roles;
}
public void setRoles(Role roles) {
this.roles = roles;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
}
Index file - The error appear at DataTable calling ajax json[i][1] = json[i].usersId; and json[i][2] = json[i].roles_id;
<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layouts/main}">
<head>
<meta charset="ISO-8859-1">
<title>Role Assign to User</title>
<link rel="stylesheet" type="text/css" href="/static/assets/css/jquery.dataTables.min.css">
<link rel="stylesheet" type="text/css" href="/static/assets/css/dataTables.bootstrap4.min.css">
</head>
<body>
<div layout:fragment="content" style="margin-right: 10px; margin-left: 10px;">
<div class="row" style="margin-top: 20px;">
<div class="col-sm-4 col-5">
<h4 class="page-title">Account</h4>
</div>
<div class="col-sm-8 col-9 text-right m-b-20">
<a th:href="${'/admin/users_roles/create'}"
class="btn btn btn-primary btn-rounded float-right"><i
class="fa fa-plus"></i> Add New</a>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table
class="table table-border table-striped custom-table mb-0" id="dataTable">
<thead>
<tr>
<th>ID</th>
<th>Account ID</th>
<th>Role ID</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Disable confirm modal -->
<div class="modal fade" id="disableConfirm">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
×
<h4>Disable Record</h4>
</div>
<div class="modal-body">
<h4>Are you sure you want to disable this?</h4>
</div>
<div class="modal-footer">
Cancel
Confirm
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(loaddata);
function loaddata() {
$("#dataTable")
.DataTable(
{
"ajax" : {
"url" : "/admin/users_roles/list",
"type" : "GET",
"datatype" : "json",
"dataSrc" : function(json) {
for (var i = 0; i < json.length; i++) {
json[i][0] = json[i].users_roles_id;
json[i][1] = json[i].usersId;
json[i][2] = json[i].roles_id;
json[i][3] = json[i].status == 1 ? '<span class="custom-badge status-green">Active</span>' : '<span class="custom-badge status-red">Inactive</span>';
json[i][4] = "<a href='/admin/users_roles/update/"+json[i].users_roles_id+"' class='btn btn-primary btn-outline'><i class='fa fa-pencil'></i></a>"
+ " "
+ "<a href='#' onclick='DisableRecord("+ json[i].users_roles_id+")' class='btn btn-danger btn-outline'><i class='fa fa-trash'></i></a>";
}
return json;
}
},
"language" : {
"emptyTable" : "No data found, please add new"
}
});
}
//Disable
var id;
function DisableRecord(usersId) {
id = usersId;
$("#disableConfirm").modal("show");
}
function ConfirmDisable() {
$.ajax({
type : "POST",
url : "/admin/users/disable?users_roles_id=" + id,
success : function(result) {
window.location.href = "/admin/users_roles/index";
$("#disableConfirm").modal("hide");
}
})
}
</script>
</div>
</body>
</html>
Or do i have a way to get the name of the model instead of the ID ? Thank you.

Related

how to load data in table and bind the same to view Model class in .net core mvc (without refreshing the page)

I'm trying to add data in table via server but unable to succeed. I tried many things but nothing worked. I'm getting the data from the server but unable to populate that in table.. can someone please help me out?
I'm getting this :
"DataTables warning: table id=particlarsTable - Invalid JSON response. For more information about this error, please see http://datatables.net/tn/1"
Let me explain my code first:
(In View)
When I click on "Add New Particular" button, bootstrap modal will popup with input fields, those fields will send to the server then again back to view and populate the table with the same data without refreshing the whole page.
I'm stuck on the last stage, I'm getting the data on UI/View in ajax success handler but unable to load that data in table.
here is my view :
<form class="form-horizontal" method="post" id="createAdHocForm">
<div class="row">
<div class="col-md-3">
<div class="form-group">
<label>Select Flat</label>
<select asp-for="AdHocInvoice.FlatRid" asp-items="#(new SelectList(Model.Flats,"FlatRid","FlatNumber"))" class="form-control form-control-sm selectpicker" data-live-search="true">
<option selected disabled value="">Select One</option>
</select>
</div>
</div>
</div>
<table class="table table-sm table-responsive-md nowrap w-100" id="particlarsTable">
<thead class="thead-light">
<tr>
<th>Particulars</th>
<th>Amount</th>
<th></th>
</tr>
</thead>
<tbody class="bg-white">
#foreach (var item in Model.AdHocInvoice.FlatInvoiceItems)
{
<tr>
<td>#item.Particular</td>
<td>#item.Amount</td>
<td></td>
</tr>
}
</tbody>
</table>
<button class="btn btn-sm btn-outline-info" type="button" onclick="showParticularForm()">Add New Particular</button>
<hr />
<div class="row text-center">
<button class="btn btn-sm btn-outline-success mx-auto" type="submit">Submit</button>
</div>
</form>
bootstrap modal to fill the table :
<div class="modal fade" id="particularWindow">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Invoice Items</h4>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<form class="form-horizontal" method="post" id="particularForm">
<div class="row">
<div class="col-md-5">
<div class="form-group">
<label>Enter Particular</label>
<input id="particularName" name="particular" class="form-control form-control-sm" required />
</div>
</div>
<div class="col-md-5">
<label>Amount</label>
<input id="particularAmount" name="amount" class="form-control form-control-sm" required />
</div>
<div class="col-md-2">
<button class="btn btn-sm btn-outline-success mt-4" id="btnParticularSubmit" type="button" onclick="addParticular()">Add</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
Scripts:
<link rel="stylesheet" href="~/DataTables/datatables.min.css" />
<script type="text/javascript" src="~/DataTables/datatables.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#particlarsTable').DataTable();
});
function showParticularForm() {
$('#particularWindow').modal('show');
}
function addParticular() {
var particular = $('#particularName').val();
var amount = $('#particularAmount').val();
$.ajax({
url: '/FlatInvoice/AddParticular',
data: 'particular=' + particular + '&amount=' + amount,
success: function (response) {
$('#particlarsTable').DataTable().ajax.reload()
}
});
}
</script>
Action Method on controller:
public JsonResult AddParticular(string particular, decimal amount)
{
_flatInvoiceViewModel.AdHocInvoice.FlatInvoiceItems.Add(new FlatInvoiceItem { Particular = particular, Amount = amount });
return Json(_flatInvoiceViewModel);
}
Class/Model:
public class FlatInvoiceItem
{
public Guid FlatInvoiceItemRid { get; set; }
public Guid FlatInvoiceRid { get; set; }
public Guid FundRuleRid { get; set; }
public string Particular { get; set; }
public decimal Amount { get; set; }
}
NOTE: this code is in initial phase, I need that input data on server for further process(will add code later) so don't want to use $.('#table_body_id').append("<tr>..</tr>"); type of code.
1.Firstly,reload() is used to send request back to the method which display the DataTable initially(e.g. name this method Test).
2.Secondly,From your AddParticular method,you just add a data to the list but the lifetime is just one request,so when you reload to Test method,the list still contains the initial data without new data.
Conclusion: I suggest that you could save data to database.And get data from database.
Here is a working demo about how to use DataTabale:
1.Model:
public class Test
{
public int Id { get; set; }
public AdHocInvoice AdHocInvoice { get; set; }
}
public class AdHocInvoice
{
public int Id { get; set; }
public string Name { get; set; }
public List<FlatInvoiceItem> FlatInvoiceItems { get; set; }
}
public class FlatInvoiceItem
{
public int Id { get; set; }
public Guid FlatInvoiceItemRid { get; set; }
public Guid FlatInvoiceRid { get; set; }
public Guid FundRuleRid { get; set; }
public string Particular { get; set; }
public decimal Amount { get; set; }
}
public class ViewModel
{
public string Particular { get; set; }
public decimal Amount { get; set; }
}
2.View:
<form class="form-horizontal" method="post" id="createAdHocForm">
<table class="table table-sm table-responsive-md nowrap w-100" id="particlarsTable">
<thead class="thead-light">
<tr>
<th>Particulars</th>
<th>Amount</th>
<th></th>
</tr>
</thead>
#*<tbody class="bg-white">
#foreach (var item in Model.AdHocInvoice.FlatInvoiceItems)
{
<tr>
<td id="particular">#item.Particular</td>
<td id="amount">#item.Amount</td>
<td></td>
</tr>
}
</tbody>*# //DataTable no need to add this tbody
</table>
<button class="btn btn-sm btn-outline-info" type="button" onclick="showParticularForm()">Add New Particular</button>
<hr />
<div class="row text-center">
<button class="btn btn-sm btn-outline-success mx-auto" type="submit">Submit</button>
</div>
</form>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.20/css/jquery.dataTables.css">
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.js"></script>
<script>
$(document).ready(function () {
//$('#particlarsTable').DataTable();
$('#particlarsTable').DataTable({
ajax: {
type: 'GET',
dataType: 'JSON',
url: '#Url.Action("Test", "Home")',
},
columns: [
{ 'data': 'particular' },
{ 'data': 'amount' }
]
})
});
function showParticularForm() {
$('#particularWindow').modal('show');
}
function addParticular() {
var particular = $('#particularName').val();
var amount = $('#particularAmount').val();
$.ajax({
url: '/Home/AddParticular',
data: 'particular=' + particular + '&amount=' + amount
}).done(function (data) {
$('#particularWindow').modal('hide');
$('#particlarsTable').DataTable().ajax.reload();
});
}
</script>
3.Controller:
public class HomeController : Controller
{
private readonly MyDbContext _context;
public HomeController(MyDbContext context)
{
_context = context;
}
public IActionResult Index()
{
return View();
}
public JsonResult Test()
{
var _flatInvoiceViewModel = _context.Test.Include(i=>i.AdHocInvoice)
.ThenInclude(a=>a.FlatInvoiceItems).Where(i => i.Id == 1).FirstOrDefault();
var list = new List<ViewModel>();
foreach (var item in _flatInvoiceViewModel.AdHocInvoice.FlatInvoiceItems)
{
var model = new ViewModel() { Amount = item.Amount, Particular = item.Particular };
list.Add(model);
}
return Json(new { data = list });
}
public void AddParticular(string particular, decimal amount)
{
var _flatInvoiceViewModel = _context.Test.Include(i => i.AdHocInvoice)
.ThenInclude(a => a.FlatInvoiceItems).Where(i => i.Id == 1).FirstOrDefault();
_flatInvoiceViewModel.AdHocInvoice.FlatInvoiceItems.Add(new FlatInvoiceItem { Particular = particular, Amount = amount });
_context.SaveChanges();
}
4.Result:
Reference:
https://datatables.net/examples/data_sources/ajax.html
https://stackoverflow.com/a/59449895/11398810

Spring Boot+Thymeleaf: th not able to resolve a Spring EL expression

I am using spring boot+thymeleaf+neo4j. Everything is working fine except that thymeleaf is not able to resolve a few of the attributes of the 'product' variable used in the th:each block in the template product_grid.html, which includes th:src="${product.URL}", th:text="${Product.title}" and the th:action="#{/product/(${Product.getId()})}" expression in form tag. The th:text="${Product.Price}" is working. When I check the code produced in the browser the src tag is empty (src:""), the text attribute containing the title tag is not shown in the browser. The th:action works fine but when I click the button defined inside the form, the url changes to http://localhost:8080/product/?btn=View+Product
instead of the following code which is shown in the browser console
http://localhost:8080/product/?1
Note: I am trying to get the image url from a field which is stored in neo4j database. The project directory is:
project directory image
Template:product_grid.html
<html xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Products</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.bundle.min.js" integrity="sha384-feJI7QwhOS+hwpX2zkaeJQjeiwlhOP+SdQDqhgvvo1DsjtiSQByFdThsxO669S2D"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">Grada</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item ">
<a class="nav-link" href="#">Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link">My Best Products</a>
</li>
<li class="nav-item">
<a class="nav-link" th:href="#{/login}">Login</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<a class="btn btn-outline-success my-2 my-sm-0" href="file:///home/madhav/SPM/Grada/public_html/product.html">Search</a>
</form>
</div>
</nav>
<div class="container text-center">
<div class="row">
<div th:each="Product:${products}" class="col-lg-3 col-sm-12 col-md-6 my-2 p-auto">
<div class="card">
<div class="card-body">
<img src="http://via.placeholder.com/150x150/888/111" th:src="${Product.URL}" alt="img" class="card-img-top img-thumbnail img-fluid">
<div class="card-title lead" th:text="${Product.title}">Some product name</div>
<div class="card-text">Price: ₹<span th:text="${Product.Price}">400</span></div>
</div>
<form method="GET" action="/" th:action="#{/product/(${Product.getId()})}">
<input type="submit" name="btn" class="form-control btn btn-primary" value="View Product">
<input type="submit" name="btn" class="form-control btn btn-primary" value="Add to Cart">
</form>
</div>
</div>
</div>
</div>
</body>
</html>`
Product model:Product.html
package com.grada.ecommerce.Models;
import com.grada.ecommerce.Models.Seller;
import org.neo4j.ogm.annotation.*;
import java.util.HashSet;
import java.util.Set;
#NodeEntity(label = "Product")
public class Product
{
public Product()
{
}
public Product(String title, Double price, int quantity, float rating, String description, String url, String company)
{
this.title = title;
this.Rating = rating;
this.Description = description;
this.Price = price;
this.Quantity = quantity;
this.URL = url;
this.Company = company;
}
#Id
#GeneratedValue
private Long id;
#Property(name = "title")
public String title;
#Property(name = "Rating")
public float Rating;
#Property(name = "Description")
public String Description;
#Property(name = "Price")
public Double Price;
#Property(name = "Quantity")
public int Quantity;
#Property(name = "Company")
public String Company;
#Property(name = "URL")
public String URL;
#Override
public String toString()
{
return this.title;
}
public Long getId() {
return id;
}
public String getTitle()
{
return title;
}
#Relationship(type = "Sells", direction = Relationship.INCOMING)
public Seller Seller;
}
ProductController.java
package com.grada.ecommerce.Controllers;
import com.grada.ecommerce.Models.Product;
import com.grada.ecommerce.Models.Seller;
import com.grada.ecommerce.Services.ProductService;
import com.grada.ecommerce.Services.SellerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class ProductController
{
final ProductService productService;
final SellerService sellerService;
#Autowired
public ProductController(ProductService productService, SellerService sellerService)
{
this.productService = productService;
this.sellerService = sellerService;
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public String Index(Model model)
{
Iterable<Product> products = productService.products();
model.addAttribute("products", products);
return "product_grid";
}
#RequestMapping(value = "/product", method = RequestMethod.GET)
public String ShowProduct(#RequestParam(value = "id") Long id, Model model)
{
Product product = productService.findProductByID(id);
if(product == null)
return "redirect:/";
model.addAttribute("product", product);
return "productid";
}
#RequestMapping(value = "/add")
public String AddProduct(Model model)
{
model.addAttribute("product", new Product());
return "add";
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String AddProduct(#ModelAttribute Product product)
{
productService.addProduct(product);
return "redirect:/";
}
#RequestMapping(value = "/delete", method = RequestMethod.GET)
public String DeleteProduct(Model model)
{
model.addAttribute("product", new Product());
return "delete";
}
#RequestMapping(value = "/delete", method = RequestMethod.POST)
public String DeleteProduct(#ModelAttribute Product product)
{
productService.deleteProduct(product);
return "redirect:/";
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String LoginPage(Model model)
{
return "login";
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String Authenticate(Model model, String username, String password)
{
if (username.equalsIgnoreCase("seller#fake.com") && password.equals("fakeseller"))
{
Iterable<Product> products = productService.products();
model.addAttribute("products", products);
return "loggedin";
}
else
return "redirect:/login";
}
#RequestMapping(value = "/policy", method = RequestMethod.GET)
public String PolicyPage()
{
return "policies";
}
}
Welcome to SO.
Include setX methods for your variables in the Product class. Thymeleaf needs these to bind.
IMO, a great way to do this is to use Project Lombok and simply annotate your class with #Data. Then you won't even need to specify getters or setters (or your toString()) at all.
Use lower-case for your variables since by convention variables with a capital first letter refers to the class, not an instance variable.
As mentioned, use POST instead of GET in your form since you are submitting data.
Use the shorthand #GetMapping and #PostMapping to make it easier to read.

Cannot update entity

I'm trying to update an entity with a particular mapping :
#Entity
#Table(name = "obs_structure2")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Structure implements Serializable{
private String id;
private String tag;
private String description;
private Set<Version> parentVersions = new HashSet<>();
private List<StructureElement> children = new ArrayList<>();
private List<StructureElement> slaves = new ArrayList<>();
private PersistenceSignature signature = new PersistenceSignature();
#OneToMany(mappedBy = "parentStructure")
public List<StructureElement> getChildren() {
return children;
}
public void addChild(StructureElement se)
{
if(this.children.contains(se))
{
this.children.add(se);
}
}
and
#Entity
#Table(name = "obs_structure_element2")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class StructureElement implements Serializable{
private long id;
private String tag;
private String description;
private boolean repetitive = false;
private boolean optional = false;
private Integer position = 1;
private Structure parentStructure;
private Structure typeStructure;
private PersistenceSignature signature = new PersistenceSignature();
#ManyToOne
#JoinColumn(name = "parent_id")
#JsonIgnore
public Structure getParentStructure() {
return parentStructure;
}
and this is my controller :
#PutMapping("/update")
public StructureElement update(#RequestBody StructureElement se){
logger.info("Call to StructureElementController.update with se = " + se);
this.connectToDatabase();
StructureElement updatedSE;
try{
boolean exists = this.repository.exists(se.getId());
if(!exists){
logger.error("Could not find StructureElement to update. se = " + se);
return null;
}
updatedSE = this.repository.save(se);
logger.info("Updated SE = " + updatedSE);
}catch (Exception e){
logger.error("Could not update structure element. se = " + se, e);
return null;
}
return updatedSE;
}
When I try to update an element the parentStructure is overwritten to null.
If I delete the #JsonIgnore annotation I'm getting this StackOverflow error:
[ERROR] 2018-01-03 14:22:38.577 [http-nio-8080-exec-5] o.a.c.c.C.[.[.[.[dispatcherServlet] 181 - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause
java.lang.StackOverflowError: null
at java.util.AbstractCollection.toString(AbstractCollection.java:454) ~[?:1.8.0_151]
at java.lang.String.valueOf(String.java:2994) ~[?:1.8.0_151]
at java.lang.StringBuilder.append(StringBuilder.java:131) ~[?:1.8.0_151]
at be.groups.observatory.server.model.Structure.toString(Structure.java:147) ~[classes/:?]
at java.lang.String.valueOf(String.java:2994) ~[?:1.8.0_151]
at java.lang.StringBuilder.append(StringBuilder.java:131) ~[?:1.8.0_151]
at be.groups.observatory.server.model.StructureElement.toString(StructureElement.java:116) ~[classes/:?]
at java.lang.String.valueOf(String.java:2994) ~[?:1.8.0_151]
at java.lang.StringBuilder.append(StringBuilder.java:131) ~[?:1.8.0_151]
at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[?:1.8.0_151]
at java.lang.String.valueOf(String.java:2994) ~[?:1.8.0_151]
at java.lang.StringBuilder.append(StringBuilder.java:131) ~[?:1.8.0_151]
at be.groups.observatory.server.model.Structure.toString(Structure.java:147) ~[classes/:?]
at java.lang.String.valueOf(String.java:2994) ~[?:1.8.0_151]
at java.lang.StringBuilder.append(StringBuilder.java:131) ~[?:1.8.0_151]
at be.groups.observatory.server.model.StructureElement.toString(StructureElement.java:116) ~[classes/:?]
at java.lang.String.valueOf(String.java:2994) ~[?:1.8.0_151]
at java.lang.StringBuilder.append(StringBuilder.java:131) ~[?:1.8.0_151]
at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[?:1.8.0_151]
at java.lang.String.valueOf(String.java:2994) ~[?:1.8.0_151]
at java.lang.StringBuilder.append(StringBuilder.java:131) ~[?:1.8.0_151]
at be.groups.observatory.server.model.Structure.toString(Structure.java:147) ~[classes/:?]
and for those who know vue.js here is my component :
<template>
<div class="t-body">
<obs-sidebar></obs-sidebar>
<main class="t-content">
<div v-if="updated" class="c-notification c-notification--success" role="dialog" aria-label="first notification" aria-describedby="desc_1">
<p id="desc_1" class="c-notification__message">L'élément de structure à bien été mise à jour.</p>
</div>
<div v-if="errors && errors.length">
<div v-for="error of errors" class="c-notification c-notification--danger">
{{ error.message }}
</div>
</div>
<div class="l-row l-row--gutter">
<div class="l-col">
<h1>{{ msg }} - {{ element_id }}</h1>
</div>
</div>
<loader v-if="visible"></loader>
<div class="l-row l-row--gutter" v-else>
<div class="l-col-4">
<form class="c-form full-width" #submit.prevent="updateStructureElement">
<div class="l-row">
<fieldset class="c-form__fieldset">
<legend class="c-form__legend">Remplissez le formulaire</legend>
<div class="l-row nice-top">
<div class="l-col-3 l-justify--end nice-right">
<div class="c-form__field-group">
<label for="tag" class="c-form__label">Tag <span class="s-text s-text--danger">* </span></label>
</div>
</div>
<div class="l-col-7">
<div class="c-form__field-group full-width">
<input id="tag" class="c-form__field full-width" type="text" name="tag" v-model="element.tag"/>
</div>
</div>
</div>
<div class="l-row nice-top">
<div class="l-col-3 l-justify--end nice-right">
<div class="c-form__field-group">
<label for="description" class="c-form__label">Description <span class="s-text s-text--danger">* </span></label>
</div>
</div>
<div class="l-col-7">
<div class="c-form__field-group full-width">
<textarea id="description" class="c-form__field minimal-h" name="description" v-model="element.description"></textarea>
</div>
</div>
</div>
<div class="l-row nice-top">
<div class="l-col-6 l-justify--end nice-right">
<div class="c-form__field-group">
<label for="optional" class="c-form__label">Optional <span class="s-text s-text--danger">* </span></label>
</div>
</div>
<div class="l-col-6">
<div class="c-form__field-group">
<input id="optional" class="c-form__field" type="checkbox" name="optional" v-model="element.optional"/>
</div>
</div>
</div>
<div class="l-row nice-top">
<div class="l-col-6 l-justify--end nice-right">
<div class="c-form__field-group">
<label for="repetitive" class="c-form__label">Répétitif <span class="s-text s-text--danger">* </span></label>
</div>
</div>
<div class="l-col-6">
<div class="c-form__field-group full-width">
<input id="repetitive" class="c-form__field" type="checkbox" name="repetitive" v-model="element.repetitive"/>
</div>
</div>
</div>
</fieldset>
</div>
<div class="l-row nice-top">
<div class="l-col-offset-3 l-col-7">
<button class="c-btn c-btn--primary c-btn--raised c-btn--ripple c-form__button full-width s-text--center" type="submit">Soumettre</button>
</div>
</div>
</form>
</div>
</div>
</main>
</div>
</template>
<script>
import Loader from 'gso-loader';
import {state, show, hide} from 'gso-loader/store';
import {HTTP} from '../http-common';
import ObsSidebar from './parts/sidebar.vue';
export default{
name: 'update-structure-element',
props: ['element_id'],
data() {
return {
msg: 'Mise à jour de l\'élément',
element: [],
errors: [],
updated: false
};
},
computed: {
visible() {
return state.visible;
}
},
methods: {
updateStructureElement: function () {
let seToUpdate = this.element;
console.log('To update = ' + JSON.stringify(seToUpdate));
HTTP.put('structure-element/update', seToUpdate, {headers: {'Content-Type': 'application/json'}})
.then(response => {
console.log('response = ' + response);
this.element = response.data;
this.updated = true;
})
.catch(e => {
console.log('Error = ' + e);
this.errors.push(e);
});
}
},
components: {ObsSidebar, Loader},
created() {
show();
let elementId = this.$route.params.element_id;
HTTP.get('structure-element/' + elementId)
.then(response => {
this.element = response.data;
hide();
})
.catch(e => {
this.errors.push(e);
hide();
});
}
};
</script>
Well, I've looking in some articles and changed the way I update the entity:
#PutMapping("/update")
public StructureElement update(#RequestBody StructureElement se){
StructureElement databaseElement;
logger.info("Call to StructureElementController.update with se = " + se);
this.connectToDatabase();
try{
databaseElement = this.repository.findOne(se.getId());
if(databaseElement == null){
logger.error("Could not find StructureElement to update. se = " + se);
return null;
}
// Update
databaseElement.setDescription(se.getDescription());
databaseElement.setTag(se.getTag());
databaseElement.setOptional(se.isOptional());
databaseElement.setRepetitive(se.isRepetitive());
databaseElement.getSignature().setModificationDate(new Date());
databaseElement = this.repository.save(databaseElement);
logger.info("Updated SE = " + databaseElement);
}catch (Exception e){
logger.error("Could not update structure element. se = " + se, e);
return null;
}
return databaseElement;
}
Now this works.
Seems that Spring data JPA doesnt want to update an entity like a simple JPA EntityManager....

Can I have more than 1 form action(form inside form) in single jsp using hibernate

In this jsp, I have used 2 form actions, one to save the role(table:defining role), and other to call the drop list from other table(table: solutionList).
After clicking on submit, it is not doing anything.
If i remove this form(solutionMaster.html)
Im getting this error " Invalid property 'sMName' of bean class [com.mode;.definingrole]: Bean property 'sMName' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?.
Yes, I know the reason, Because the column 'sMName' was not the part of defining role table. what to do with this.
The Thing i want to know is,
Can we create form inside form?
2.Without creating another form, How can i get the column values of other table to defining role table?
Please help.
Thanks in advance.!!!
<div class="modal inmodal" id="myModalForRole" tabindex="-1"
role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content animated bounceInRight">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span><span class="sr-only">Close</span>
</button>
<i class="fa fa-laptop modal-icon"></i>
<h4 class="modal-title">Define Role</h4>
</div>
<div class="modal-body">
<form:form action="newRoleDetails.html" method="post"
commandName="deftemp" id="deftemp">
<div class="row">
<div class="form-group">
<form:form action="solutionName.html" method="post"
commandName="soltemp" id="soltemp">
<div class="col-sm-6">
<label>Solutions*</label><br>
<form:select path="sMName" class="form-control"
id="sMName">
<form:option value="" label="--select--"></form:option>
<c:forEach var="solutionList" items="${solutionList}"
varStatus="loop">
<form:option value="${solutionList}"
label="${solutionList}">
</form:option>
</c:forEach>
</form:select>
</div>
</form:form>
</div>
</div>
<div class="row">
<div class="form-group">
<div class="col-sm-6">
<label>Parent Role*</label><br>
<form:textarea path="ParentRole" id="ParentRole"
class="form-control" placeholder="Enter the Parent Role" />
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<div class="col-sm-6">
<label>Sub Role*</label><br>
<form:textarea path="SubRole" id="SubRole"
class="form-control" placeholder="Enter the Child role" />
</div>
</div>
</div>
<br>
<br>
<div class="modal-footer">
<button type="button" class="btn btn-white"
data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Submit
</button>
</div>
</form:form>
</div>
Models: (solutionlist.java)
package com.model;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table (name="solutionlist")
public class solutionlist implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="solutionId",nullable = false,columnDefinition = "UNSIGNED INT(4)")
Integer solutionId;
#Column(name="solutionName")
String solutionName;
#Column(name="solutionOwner")
String solutionOwner;
#Column(name="ownerMailId")
String ownerMailId;
#Column(name="additionDate")
String additionDate;
public Integer getSolutionId() {
return solutionId;
}
public void setSolutionId(Integer solutionId) {
this.solutionId = solutionId;
}
public String getSolutionName() {
return solutionName;
}
public void setSolutionName(String solutionName) {
this.solutionName = solutionName;
}
public String getSolutionOwner() {
return solutionOwner;
}
public void setSolutionOwner(String solutionOwner) {
this.solutionOwner = solutionOwner;
}
public String getOwnerMailId() {
return ownerMailId;
}
public void setOwnerMailId(String ownerMailId) {
this.ownerMailId = ownerMailId;
}
public String getAdditionDate() {
return new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.SSS")
.format(new Date());
}
public void setAdditionDate(String additionDate) {
this.additionDate = additionDate;
}
}
definingrole.java
package com.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="definingrole")
public class definingrole implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="SNo")
Integer SNo;
#Column(name="Solutions")
String Solutions;
#Column(name="ParentRole")
String ParentRole;
#Column(name="SubRole")
String SubRole;
public Integer getSNo() {
return SNo;
}
public void setSNo(Integer sNo) {
SNo = sNo;
}
public String getSolutions() {
return Solutions;
}
public void setSolutions(String solutions) {
Solutions = solutions;
}
public String getParentRole() {
return ParentRole;
}
public void setParentRole(String parentRole) {
ParentRole = parentRole;
}
public String getSubRole() {
return SubRole;
}
public void setSubRole(String subRole) {
SubRole = subRole;
}
}
Controller : newRoleDetails.html
#RequestMapping(value=NEWROLEDETAILS_PATH)
public String newRoleDetails(Map<String, Object> model, definingrole value,solutionlist sol) throws Exception {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName();
String nameOfUser=TemplateService.getEmpNameOfUser(name);
model.put("nameOfUser",nameOfUser);
String userid=loginService.getUserId();
String role=loginService.getRole();
TemplateService.newRoleDetails(value);
definingrole deftemp=new definingrole();
model.put("deftemp", deftemp);
solutionlist s = new solutionlist();
ArrayList<templateDetails> listOfTemplate=TemplateService.listTemplateDetails(role,userid);
model.put("listOfTemplate",listOfTemplate);
return TEMPLATESUMMARY;
}
controller : solutionName.html
#RequestMapping("/solutionlist.html")
public String solutionName(Map<String, Object> model,solutionlist sol) throws Exception {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName();
String nameOfUser=TemplateService.getEmpNameOfUser(name);
model.put("nameOfUser",nameOfUser);
solutionlist soltemp = new solutionlist();
model.put("soltemp", soltemp);
ArrayList<String> solutionList=TemplateService.getSolutionListForTemplate();
model.put("solutionList", solutionList);
return REDIRECT_TEMPLATESUMMARY_URL;
}
You are trying to populate list inside form under the tag of form. Which is wrong approach. You won't get the value from /solutionlist.html by your form. You have to call at least a GET if you want to use /solutionlist.html controller.
If i think So then you have to do the following
You don't need the '/solutionlist.html' controller.
Just bind the ArrayList solutionList into model in the controller method where the form page served. I mean the GET method of Controller where the given form is served.
ArrayList<String> solutionList=TemplateService.getSolutionListForTemplate();
model.put("solutionList", solutionList);
You will get that solutionList directly to your form as value. So, modify the select part of your form as follows
<select name="solutions"path="Solutions">
<c:forEach items="${solutionList}" var="solution">
<option value="${solution}">${solution}</option>
</c:forEach>
</select>

Springboot Thymeleaf : How to format row according to a condition

I have a page that displays the list of all the journals available. I want to write a thymeleaf expression language that highlights the already subscribed journals using there journal id . So for all the subscribed journals the text for the hyper-link href should be "Unsubscribe" and vice verse if its not subscribed.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<title>TBD</title>
<!--/*/ <th:block th:include="fragments/headinc :: head"></th:block> /*/-->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
</head>
<body>
<div class="container">
<h1 th:text="'Hello, ' + ${user.fullname} + '!'" />
<p>Manage your subscriptions here</p>
<form role="form" id="form-search" class="form-inline"
th:action="#{/subscriptions}" method="get">
<input type="text" class="form-control" id="filter" name="filter"
placeholder="Enter filter"></input>
<button type="submit" class="btn btn-default">
<span class="glyphicon glyphicon-search"></span> Search
</button>
<a th:href="#{/logout}" class="btn btn-link" role="button">Logout</a>
</form>
<div th:if="${not #lists.isEmpty(journals)}">
<form role="form" id="form-subscribe" th:action="#{/subscribe}"
method="post">
<input type="hidden" name="journalId" id="journalId" />
</form>
<table id="table" class="table">
<thead>
<tr>
<th>Subject</th>
<th>Filename</th>
<th>Tags</th>
<th>View</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="journal : ${journals}">
<td th:text="${journal.subject}">Id</td>
<td th:text="${journal.filename}">Product Id</td>
<td th:text="${journal.tags}">Description</td>
<td><a>View</a></td>
<td><a id="href"
th:href="'javascript:subscribe(\'' + ${journal.id} + '\');'">Subscribe</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
<script type="text/javascript">
function subscribe(journalId) {
$('#journalId').val(journalId);
$('#form-subscribe').submit();
}
</script>
<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
$(document).ready(function() {
var modelAttributeValue = [[${subscriptions}]];
console.log(modelAttributeValue);
alert(modelAttributeValue);
var array = modelAttributeValue.split(';');
console.log(array);
alert(array);
});
/*]]>*/
</script>
</html>
Controller
#Controller
public class SubscriptionController {
#Autowired
private SubscriberService subscriberService;
#RequestMapping(value = "/subscribe", method = RequestMethod.POST)
String subscribe(Model model, #RequestParam("journalId") Integer journalId) {
JournalToken token = (JournalToken) SecurityContextHolder.getContext().getAuthentication();
Account user = (Account) token.getCredentials();
model.addAttribute("user", user);
Journal journal = this.subscriberService.findJournalById(journalId);
this.subscriberService.subscribeJournalForSubscriber(journal, user);
return "redirect:subscriptions";
}
#RequestMapping(value = "/subscriptions", method = RequestMethod.GET)
String list(Model model) {
JournalToken token = (JournalToken) SecurityContextHolder.getContext().getAuthentication();
Account user = (Account) token.getCredentials();
model.addAttribute("user", user);
ArrayList<Journal> journals = this.subscriberService.FindAllJournals();
model.addAttribute("journals", journals);
StringBuilder sub = new StringBuilder();
ArrayList<Subscription> subscribed = this.subscriberService.getSubscribedJournalsForSubscriber(user);
model.addAttribute("subscriptions", subscribed);
return "subscriptions";
}
}
Model subscriptions
#Entity
#Table(uniqueConstraints={#UniqueConstraint(columnNames={"userId", "journalId"})})
public class Subscription {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Version
private Integer version;
private Integer userId;
private Integer journalId;
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return this.id;
}
public void setVersion(Integer version) {
this.version = version;
}
public Integer getVersion() {
return this.version;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getUserId() {
return this.userId;
}
public void setJournalId(Integer journalId) {
this.journalId = journalId;
}
public Integer getJournalId() {
return this.journalId;
}
}
you can change your arrayList subscribed to have only the ids of journals (more optimised).
So, in the controller you can have something like this
ArrayList<Integer> subscribed =
this.subscriberService.getSubscribedJournalsForSubscriber(user); //modify it so it returns the journals ids instead of the whole object(Subscription)
then in the thymeleaf change the anchor with something like this
<a id="href" th:href="'javascript:subscribe(\'' + ${journal.id} + '\');'">
<span th:if="${#lists.contains(subscriptions, journal.id) }" th:text="Unsubscribe"> Unsubscribe </span>
<span th:if="not ${#lists.contains(subscriptions, journal.id) }" th:text="Subscribe"> Subscribe </span>
</a>
Have a look at the documentation of thymeleaf http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html
/*
* Check if element or elements are contained in list
*/
${#lists.contains(list, element)}
${#lists.containsAll(list, elements)}

Resources