Thymeleaf Set Binding for Neo4j insert - spring-mvc

I have been working on an Spring MVC application with a Thymeleaf UI. For Neo4j handling entities, I use Set that contains NeoImages that Belong to the class posts:
#Data
#NodeEntity
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class NeoPost {
#Id
#GeneratedValue
Long postId;
#NotNull
#NotBlank
#Size(min = 1, max = 600)
String question;
/**
* Images that are involved in that post
*/
#NotEmpty
#Size(min = 2)
#Relationship(type = "STARES", direction = Relationship.OUTGOING)
Set<Neoimage> neoimageSet = new HashSet<>();
/**
* User that made this post
*/
#Relationship(type = "OWNS", direction = Relationship.INCOMING)
NeoUser user;
/**
* Users that somehow in a way possible described in Userinteractiontype enum
* with this current post.
*/
#Relationship(type = "INTERACTED_WITH", direction = Relationship.INCOMING)
Set<NeoInteraction> incomingInteractions = new HashSet<>();
}
Here the class of the NeoImage type:
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#NodeEntity
public class Neoimage {
#Id
#GeneratedValue
Long imageId;
//For testing purposes use this type of information
#ImageUrlValidator
String imageFull;
}
Do not get me wrong I know that I want to use a Set to store the Neoimages in the Neopost class. The Problem is not the persistence or anything, but I want to delivery input results from a thymeleaf form.
<form autocomplete="off" action="#" th:action="#{/postQuestion}"
th:object="${neoPost}" method="post" role="form">
<div class="form-group">
<div class="col-sm-12">
<label th:if="${#fields.hasErrors('question')}" th:errors="*{question}"
class="validation-message"></label>
<input type="text" th:field="*{question}" placeholder="Question"
class="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="text" th:field="*{neoimageSet[0].imageFull}"
placeholder="Image 1" class="form-control" /> <label
th:if="${#fields.hasErrors('neoimageSet[0].imageFull')}" th:errors="*{neoimageSet[0].imageFull}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="text" th:field="*{neoimageSet[1].imageFull}"
placeholder="Image 1" class="form-control" /> <label
th:if="${#fields.hasErrors('neoimageSet[1].imageFull')}" th:errors="*{neoimageSet[1].imageFull}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-outline-secondary my-2 my-lg-0 loginButton">Upload Post</button>
</div>
</div>
<span th:utext="${successMessage}"></span>
</form>
When I then access the post request, the question is filled in the model as expected, but the neoimageset does not hold the two strings from the two input fields. I have heard that databinding is somehow not possible to a set with thymeleaf. I can fully understand if you need any further elaborations, thank you for helping.

I have solved this issue using a wrapper method within:
/**
* Wrapper method since set elements cannot be accessed by index which is needed in thymeleaf
*/
#Transient
AutoPopulatingList<Neoimage> neoImageWrapperList = new AutoPopulatingList(Neoimage.class);
public AutoPopulatingList<Neoimage> getNeoImageWrapperList() {
//Copy content to neoimageset
this.neoImageWrapperList.forEach(neoimage -> neoimageSet.add(neoimage));
return this.neoImageWrapperList;
}
Now I just call the neoImageWrapperList instead of the actual set.

Related

Send list object from thymeleaf to controller

I have a big problem about saving an Object list from Thymeleaf to the controller. Object List in thymeleaf is generated by Jquery. but I don't know how to get the data to Controller, that Object list doesn't know the size. Because users can add it anytime.
Please help me to send a list object in thymeleaf to controller.
I’ve Created a new class with 1 properties: ArrayList loaiDoans;
"LoaiDoan" is a Object that i want to save.
And using that class is an object to Save List "LoaiDoan" from thymeleaf to controller.
But List don't know the size first.because that genarated in thymeleaf. The first time i load the Model, the Model contain List is empty,so that list is not display in screen.
This is my class
public class ListLoaiDoan {
private ArrayList<LoaiDoan> loaiDoans;
//Getter Setter
}
My controller bind list object from controller to thymeleaf
#RequestMapping("/luunhieuobject")
public String LoadNhieuObjectCungLuc(Model model) {
ListLoaiDoan listLoaiDoanAAA = new ListLoaiDoan();
model.addAttribute("listLoaiDoan111",listLoaiDoanAAA);
return "/MHtrangchu/LuuNhieuObjCungLuc";
}
//This is the method save list Object from thymeleaf to controller
#PostMapping("/luunhieuobject")
public String processQuery(#ModelAttribute("listLoaiDoan111") ListLoaiDoan listLoaiDoan) {
System.out.println(listLoaiDoan.getLoaiDoans() != null ? listLoaiDoan.getLoaiDoans().size() : "List Empty");
System.out.println("--");
return "/MHtrangchu/LuuNhieuObjCungLuc";
}
LuuNhieuObjCungLuc.html
<form th:object="${listLoaiDoan111}" method="post" th:action="#{/luunhieuobject}">
<!--INPUT FIELDS-->
<div class="row">
<div class="col">
<div id="movieList">
<div class="row">
<div style="margin-left:100px;" class="col-4 form-group">tenloaidoan</div>
<div style="margin-left:100px;" class="col-4 form-group">madoan</div>
</div>
<div class="row item" th:each="row, stat : ${listLoaiDoan111.loaiDoans}">
<div class="col-lg-6 form-group">
<input th:field="*{loaiDoans[__${stat.index}__].tenloaidoan}" type="text" class="form-control"/>
</div>
<div class="col-lg-6 form-group">
<input th:field="*{loaiDoans[__${stat.index}__].madoan}" type="text" class="form-control"/>
</div>
</div>
</div>
</div>
</div>
<!--ADD NEW ROW BUTTON-->
<div class="row">
<div class="col">
<button type="button" class="btn btn-success" onclick="addRow()">Add row</button>
</div>
</div>
<!--SUBMIT FORM BUTTON-->
<div class="row text-right">
<div class="col">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
That not display annything in the screen, i know that because "listLoaiDoanAAA" is the empty and "th:each" in thymeleaf have nothing to show, how to generate "input" tag and save to controller help me !
I solved this problem !
Set a size for ArrayList before bind it to thymeleaf !
I save my day. thanks Stackoverflow.
i fix my controller like this
#GetMapping("/luunhieuobject")
public String LoadNhieuObjectCungLuc(Model model) {
ListLoaiDoan listLoaiDoanAAA = new ListLoaiDoan();
ArrayList<LoaiDoan> LDD = new ArrayList<LoaiDoan>(10);
listLoaiDoanAAA.setLoaiDoans(LDD);
model.addAttribute("listLoaiDoan111", listLoaiDoanAAA);
return "/MHtrangchu/LuuNhieuObjCungLuc";
}

Creating a new User Account Spring data rest framework

I have been trying to create a new user for my webApp. I am using spring-data-rest. At the front end, a prospective user submits his information and then the app is supposed to create back-end information. The codes are as below.
User.java
public class User {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
private String name;
private String email;
private String password;
private String address;
//getters and setters
}
UserRepository.java
#RepositoryRestResource(collectionResourceRel = "user", path = "user")
public interface UserRepository extends PagingAndSortingRepository<User, Long>{
}
Is it okay to have view as below? Do I need to worry about id? It is supposed to be generated by backend, so it does not make any sense to put id field in view.
registration.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
</head>
<body>
<h3>Welcome, Enter The User Details</h3>
<form:form action="#" th:action="#{/user}" th:object="${user}" method="post">
<div><label> User Name : <input type="text" th:field="*{username}"> </label></div>
<div><label> Password: <input type="password" th:field="*{password}"/> </label></div>
<div><label> Email: <input type="email" th:field="*{email}"/> </label></div>
<div><label> Address: <input type="text" th:field="*{address}"/> </label></div>
<div><input type="submit" value="Submit"/></div>
</form:form>
</body>
</html>
I don't know about thymeleaf, but answer for your question is it is ok.
You don't need to worry about id in view, it is automatically created by your dao framework. By #GeneratedValue(strategy= GenerationType.AUTO)
You can use this kind of thing since it's a Spring MVC
<form:hidden path="id"/>

How to use input radio button with thymeleaf and Spring MVC

I would like to get a destination address from a input radio button list. The DestinationAddress class is the following:
public class DestinationAddress {
private Integer destinationAddressId;
private String name;
private Location location;
private User owner;
public DestinationAddress(String name, Location location, User owner) {
this.name = name;
this.location = location;
this.owner = owner;
}
public DestinationAddress() {
}
// getter and setter
}
The controller who handles the get and post is the following:
#PreAuthorize("hasRole('USER')")
#GetMapping(value = "/select-address")
public String selectAddress(Principal principal, Model model) {
List<DestinationAddress> addresses = destinationAddressService.getAllByUsername(principal.getName());
model.addAttribute("destinationAddresses", addresses);
model.addAttribute("destinationAddress", new DestinationAddress());
return "purchase/select-address";
}
#PreAuthorize("hasRole('USER')")
#PostMapping(value = "/select-address")
public String selectAddress(#ModelAttribute DestinationAddress destinationAddress, Principal principal) {
Purchase purchase = purchaseService.addPurchase(principal.getName(), destinationAddress);
return "redirect:/purchases/pay/" + purchase.getPurchaseId();
}
And the html page is the following:
<form th:object="${destinationAddress}" method="post">
<fieldset>
<legend>Your addresses</legend>
<ul>
<li th:each="destinationAddress : ${destinationAddresses}">
<input type="radio" th:field="*{destinationAddressId}" th:value="${destinationAddress.destinationAddressId}" />
<label th:for="${#ids.prev('destinationAddress.destinationAddressId')}" th:text="${destinationAddress}"></label>
</li>
</ul>
</fieldset>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
The error message is the following:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'destinationAddressId' available as request attribute
I don't know what's the problem here. I don't know which type will the form return to the controller. So I don't know which variable pass to the model and which one to get from the post controller method. Integer or DestinationAddress? I cannot find anything googling it, just small pieces of code without any explanations. Any suggestions?
I found a solution to my problem. I changed the html page, now it looks like this:
<form th:object="${address}" method="post">
<fieldset>
<legend>Your addresses</legend>
<ul>
<li th:each="destinationAddress : ${destinationAddresses}">
<input type="radio" th:field="${address.destinationAddressId}" th:value="${destinationAddress.destinationAddressId}" />
<label th:for="${destinationAddress.destinationAddressId}" th:text="${destinationAddress}"></label>
</li>
</ul>
</fieldset>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
I changed the name of the object inside the model because it was the same as the name of the temp destinationAddress of the loop. I also replaced '{#ids.prev(' because it was giving me an error:
Cannot obtain previous ID count for ID ...
Now it works fine.

ASP.NET core label taghelper. How to append custom text

When we write
<label asp-for="Email"></label>
it generates the following HTML:
<label for="Email">Email Address</label>
It works fine. The question is whether it's possible to extend tag helper to support custom text to be added? For example, if I write
<label asp-for="Email" asp-postfix=":"></label>
it generates the following HTML:
<label for="Email">Email Address:</label>
Please see that colon is added now to the label text. And colon could be replaced with any other text.
If you're planning on extending the current aspnet tag helper, you can't. You will need to create your own tag helper. Both the aspnet and your one will run.
[HtmlTargetElement("label", Attributes = _textAttributeName)]
public class PostfixTagHelper : TagHelper
{
private const string _textAttributeName = "postfix-text";
[HtmlAttributeName(_textAttributeName)]
public string Text { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
base.Process(context, output);
output.Content.Append(Text);
}
public override int Order
{
get
{
return 100; // Needs to run after aspnet
}
}
}
To use it:
<label asp-for="Email" postfix-text=":"></label>
in tag helper if you have static content in source and want to append text then refer below link. https://github.com/aspnet/Razor/issues/341. for reference added same example over here.
Source File
<my-tag-helper>
Content in source
</my-tag-helper>
Tag helper file.
public void Process(TagHelperContext context, TagHelperOutput output)
{
var nl = Environment.NewLine;
var br = "<br />" + nl;
output.PreElement.Append("This will appear before source element" + br);
output.PreContent.Append(nl + "This will appear before source content" + br);
output.PostContent.Append(br + "This will appear after source content" + nl);
output.PostElement.Append(br + "This will appear after source element");
}
Output.
This will appear before source element<br />
<my-tag-helper>
This will appear before source content<br />
Content in source<br />
This will appear after source content
</my-tag-helper><br />
This will appear after source element
This works nicely:
<form method="post" class="container mt-3 backgroundwhite w-100">
<div class="form-group row">
<label class="col-4 text-right pr-1" style="" asp-for="ServiceToBeAdded.Name"></label><span>: </span>
<input class="form-control col-6" asp-for="ServiceToBeAdded.Name" type="text" />
</div>
<div class="form-group row">
<label class="col-4 text-right pr-1" asp-for="ServiceToBeAdded.Price"></label><span>: </span>
<input class="form-control col-6" asp-for="ServiceToBeAdded.Price" type="text" />
</div>
</form>

Spring MCV 3 showErrors doesn't display anything

I try to validate a simple form. The validation is well executed but the result page doesn't display the errors.
I use velocity to render the page.
I've used as example the PetClinic project from spring website.
Here is my controller when I hit the "post form" button:
#Controller
#RequestMapping("/subscription")
public class SubscriptionController {
#RequestMapping(value = "/newCustomer", method = RequestMethod.POST)
public String processSubmit(#ModelAttribute Customer customer, BindingResult result, SessionStatus status) {
new CustomerValidator().validate(customer, result);
if (result.hasErrors()) {
return "subscription";
}
else {
status.setComplete();
return "redirect:/admin";
}
}
}
When I go in debug, I see the errors. I'm successfully redirected on the subscription page but the errors are not displayed.
My webpage (simplified):
...
#springBind("customer")
#springShowErrors("<br/>" "")
<form class="form-horizontal" method="post" action="#springUrl("/subscription/newCustomer/")">
....
<!-- Button -->
<div class="controls">
<button class="btn btn-primary">#springMessage("website.subscription.signup")</button>
</div>
</form>
...
if you need anything else, don't hesitate to tell me. Thanks for your help! I'm stuck on this since several days.
EDIT :
I finally found the error. It was with the springBind tag. I didn't well understand that you need to bind the field to show the associated error. Here is the fixed code for one field for twitter bootstrap framework.
#springBind("customer.name")
<div class="control-group #if(${status.error})error#end">
<!-- Prepended text-->
<label class="control-label">#springMessage("website.subscription.name")</label>
<div class="controls">
<div class="input-prepend">
<span class="add-on"><i class="icon-user"></i></span>
<input class="input-xlarge"
placeholder="John Doe" id="name" name="name" type="text">
</div>
<p class="help-block">
#springShowErrors("<br/>" "")
</p>
</div>
</div>
springShowErrors(...) will show all the errors associated with the field name of the POJO customer.

Resources