How to save tags in database or map n controller - spring-boot

How can I map tag values with controller and save it to DB
<input type="text" name="tags" placeholder="Tags" class="tm-input form-control tm-input-info"/>
<script type="text/javascript">
$(".tm-input").tagsManager();
</script>
#PostMapping("/index")
public String addPRoduct(#RequestParam("name") String name, #RequestParam("tags") List<String> tags, #RequestParam("description") String details ) {
Product product = new Product();
product.setName(name);
product.setTags(tags);
product.setDescription(details);
proRepo.save(product);
return "done";
}
product.setTags(tags) is getting NULL
I want to store multiple tags values in DB which are created once it enter in textbox Please find the screenshot for tags values

Related

How to show appropriate message on page with Thymeleaf if list is empty

I have some controller that is connected with some lists, now that list can be empty, I'm trying to provide a user message on page if list is empty. To be more clear, user can have wallet, inside that wallet user can create a transactions, because all of that I have a page Transactions now, if user still didnt create any transaction but visit that page, I want to show him message like You didnt create any transaction.
I found this example, and tried to apply on my problem, but so far it didnt work: How to check null and empty condition using Thymeleaf in one single operation?
This is my controller:
#GetMapping("/userTransactions/{user_id}")
public String getUserTransactions(#PathVariable("user_id") long user_id, TransactionGroup transactionGroup, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
model.addAttribute("userId", userId);
List<Transaction> transactions = transactionRepository.getTransactionsByUserId(user_id);
List<TransactionGroup> transactionByDate = new ArrayList<>();
List<Transaction> transOnSingleDate = new ArrayList<>();
boolean currDates = transactions.stream().findFirst().isPresent();
if (currDates) {
LocalDate currDate = transactions.get(0).getDate();
TransactionGroup transGroup = new TransactionGroup();
for (Transaction t : transactions) {
if (!currDate.isEqual(t.getDate())) {
transGroup.setDate(currDate);
transGroup.setTransactions(transOnSingleDate);
transactionByDate.add(transGroup);
transGroup = new TransactionGroup();
transOnSingleDate = new ArrayList<>();
}
transOnSingleDate.add(t);
currDate = t.getDate();
}
transGroup.setDate(currDate);
transGroup.setTransactions(transOnSingleDate);
transactionByDate.add(transGroup);
} else {
System.out.println("Empty");
model.addAttribute("transactionGroup", "NoData");
}
model.addAttribute("transactionGroup", transactionByDate);
return "transactions";
}
And that seems to work fine, I mean, if I didn't create a transaction, message System.out.println("Empty"); will be printed, but message on page is not displayed neither.
This is thymeleaf:
<div class="date" th:each="singleGroup : ${transactionGroup}">
<h1 th:text="${singleGroup .date}"></h1>
<div class="transaction" th:each="singleTrans : ${singleGroup.transactions}">
<h2>Amount: <span th:text="${singleTrans.amount}"></span></h2><br>
<h2>Note: <span th:text="${singleTrans.note}"></span></h2><br>
<h2>Wallet name: <span th:text="${singleTrans .walletName}"></span></h2><br>
<h2>Expense Category: <span th:text="${singleTrans .expenseCategories}"></span></h2><br>
<h2>IncomeCategory: <span th:text="${singleTrans .incomeCategories}"></span></h2>
<a class="card__link" th:href="#{/api/transaction/delete/{id}(id=${singleTrans.id})}"
th:data-confirm-delete="|Are you sure you want to delete ${singleTrans.walletName} wallet?|"
onclick="if (!confirm(this.getAttribute('data-confirm-delete'))) return false">Delete</a>
<hr>
</div>
<th:block th:if="${transactionGroup=='NoData'}"> No Data Found </th:block>
</div>
And here is the part: <th:block th:if="${transactionGroup=='NoData'}"> No Data Found </th:block> But its not displayed if list is empty
What I'm missing?
You can check if your list is empty like this
<div th:if="${#lists.isEmpty(transactionGroup)}"> No Data Found </div>
<div th:if="${#lists.size(transactionGroup) ==0}"> No Data Found </div>
In addition to that, your th:block is placed inside the list outer loop and it should be outside. That's why you're not seeing anything when the list is empty.

How to create dynamic url in Spring Thymeleaf

#GetMapping("/deposit")
public String deposit(#RequestParam("amount") double amount,#RequestParam ("id") int id) {
if (amount > 0) {
accountService.deposit(id, amount);
}
return "redirect:/account";
}
I have two parameters that I need to send from my html file, my problem is that 'amount' parameter should be coming from html file. How can I dynamically do that?
<input type="number" id="amount">
<a th:href="#{/account/deposit(id=${account.id}, amount=????)}">Deposit</a>
I want to put the input value into amount in th:href would appreciate any help.
As it is mentioned by #andrewJames it would be mush easier to submit this value using form. For example:
In your HTML
<form th:action="#{/account/deposit(id=${account.id})}" method="post">
<input type="number" id="amount" name="amount">
<button type="submit">Deposit</button>
</form>
In your Controller
#PostMapping( "/deposit" )
public String onDepositSubmit( #RequestParam Long id, #RequestParam Integer amount ) {
if (amount > 0) {
accountService.deposit(id, amount);
}
return "redirect:/account";
}
This would be the easiest solution. However, it is possible to dinamically alter a link as at the client-side the link is already rendered to a normal link (e.g. /account/deposit?id=12345), so you can manipulate it using JS as you wish, for example something like this (using JQuery):
<input type="number" id="amount">
<a th:href="#{/account/deposit(id=${account.id},amount=0)}" id="amount_link">Deposit</a>
<script>
let amountInput = $( '#amount' )
let amountLink = $( '#amount_link' )
amountInput.keyup( function() {
let url = new URL( amountLink.attr( 'href' ) );
url.searchParams.set( 'amount', amountInput.val() )
amountLink.attr( 'href', url.toString() )
} )
</script>
Which would create a keyup event listener on input and update link every time the character is typed or deleted. However, this is needlessly complicated and as such is considered a bad practice.

Send values get from append forms to spring controller

I was creating a model where the structure as follows:
public class A {
private Long id;
private Type type;
private Set<String> names;
private Set<Long> ids;
private Set<String> subnames;
private Set<Long> subids;
...........
}
I would like to create the model, with multiple fields as many as I like.
so the I have created the form as follows to add new rows dynamically.
Creation Form: One of the fields-->
<form>
<div id="addNewname" class="form-group">
<label>name</label>
<div class="col-lg-4">
<input type="text" name="name_1" id="name" readonly>
</div>
<button id="btnAddname" type="button"
type="hidden"
value="btnAddName" name="btnAddName">Add
New</button>
</div></form>
With the Script to add new as follows:
int count = 1;
$(document).on("click", "#btnAddNew", function(){
count++;
$('#addNewNew').after(
'<div>' +
'<label> New Name</label>'+
'<div >' +
'<select name="name_'+ count +'">'+
'<option value="0">None</option>' +
'<c:forEach items="${names}" var="name">' +
'<option value="${name.id}">${name.name}</option> '+
'</c:forEach>'+
'</select>'+
'</div>'+
'</div>');
});
I was able to send the value to the controller of the value name="name_1" where the form been defined, but I could not do the same for the values created from the append form--script.
Any idea or suggestion to work out this, I have tried many methods but ...
You may use LazyList to add as many names you want.
In your command class, instead of using Set to define your names, try this,
import org.apache.commons.collections.FactoryUtils;
import org.apache.commons.collections.list.LazyList;
...
private List names = LazyList.decorate( new ArrayList(),
FactoryUtils.instantiateFactory(String.class));
...
In the Jsp page, all that are needed is using the arrayIndex to access or bind values. i.e.
<form:input path="names[0]" cssErrorClass="errorInput" maxlength="30"/>
In the javascript, do the same, use the arrayIndex when your create more text input on the fly.

Update model from list of viewmodels

View is something like this (I dynamically add and remove documents, Guids written here are DocumentIdentifier member of ViewModel):
<div>
<input type="hidden" name="DocumentViewModels.Index" value="8796c4e8-2262-46c0-bacc-8ffb6678b62a" />
<input type="text" name="DocumentViewModels[8796c4e8-2262-46c0-bacc-8ffb6678b62a].Document.Name" />
<input type="text" name="DocumentViewModels[8796c4e8-2262-46c0-bacc-8ffb6678b62a].Document.Type" />
<div>
<div>
<input type="hidden" name="DocumentViewModels.Index" value="3f2810c6-e338-4a6a-aa64-54b162303aab" />
<input type="text" name="DocumentViewModels[3f2810c6-e338-4a6a-aa64-54b162303aab].Document.Name" />
<input type="text" name="DocumentViewModels[3f2810c6-e338-4a6a-aa64-54b162303aab].Document.Type" />
<div>
I have viewmodel like this:
public class DocumentViewModel
{
public Document Document {get;set;}
public List<Attachments> {get;set;}
public Guid DocumentIdentifier {get;set;}
}
Controller
public ActionResult PostDocuments(List<DocumentViewModel> documentViewModels)
{
// I successfully save newly added documents in database
// Then I delete documents from database that are not in documentViewModels any more (because I dynamically add and delete them)
// Then I find documents that are on form and in database too and I want to update them
List<Document> matchedDocumentsFromDatabase = SynchronizeDocuments(documentViewModels.Select(x => x.Document));
// Here i'm stuck. I want to write something like this:
UpdateModel(matchedDocumentsFromDatabase, "DocumentViewModels");
context.SaveChanges();
// return something;
}
Can you help me?
you can use prefix as following.
public ActionResult PostDocuments(List<DocumentViewModel> documentViewModels)
{
// I successfully save newly added documents in database
// Then I delete documents from database that are not in documentViewModels any more (because I dynamically add and delete them)
// Then I find documents that are on form and in database too and I want to update them
var matchedDocumentsFromDatabase = SynchronizeDocuments(documentViewModels.Select(x => x.Document));
// Here i'm stuck. I want to write something like this:
string prefix = "";
foreach(var item in matchedDocumentsFromDatabase)
{
prefix = string.Format("DocumentViewModels[{0}]",item.DocumentIdentifier .ToString());
UpdateModel(item, prefix);
}
context.SaveChanges();
// return something;
}
hope this could help.

How to add unobtrusive validation for html template fields whats not in the model

i got a template created for custom zip code field.
My template code is below:
#{
string model = Model ?? string.Empty;
string zipFirst = "";
string zipSecond = "";
if(!String.IsNullOrEmpty(model) && !String.IsNullOrWhiteSpace(model))
{
var values = model.Split('-');
if(values.Count() == 2)
{
zipFirst = values[0] ?? string.Empty;
zipSecond = values[1] ?? string.Empty;
}
}
var pName = ViewData.ModelMetadata.PropertyName;
var zipAreaId = "#" + pName + "zipcodearea";
}
<div id="#(pName)zipcodearea">
<input type="text" maxlength="5" id="zipcodefirst" name="#(pName)codefirst" value="#(zipFirst)" style="width:136px"/> -
<input type="text" maxlength="4" id="zipcodesecond" name="#(pName)codesecond" value="#(zipSecond)" style="width:120px"/>
#Html.HiddenFor(m => m, new { #class = "generatedZipField"})
</div>
<script type="text/javascript">
jQuery(function ($) {
$('#(zipAreaId) #zipcodefirst').autotab({ target: '#(pName)codesecond', format: 'numeric' });
$('#(zipAreaId) #zipcodesecond').autotab({ previous: '#(pName)codefirst', format: 'numeric' });
$('#(zipAreaId)').zipcode();
});
</script>
And i use it like this:
[UIHint("ZipCode")]
[Display(Name = "Zip Code")]
public string Zip { get; set; }
Like you see in my template i got two fields whats not included in the model.
It is #zipcodefirst and #zipcodesecond.
What i need to achieve is to have two separate fields for full us zip code.
When user fill both fields im using jquery widget for merging them into one string and inserting it into hidden field in template. after form submited value in hidden field getting sent into server.
Whats the problem?
I need to add mvc unobtrusive validation for them two fields whats not in the model #zipcodefirst and #zipcodesecond.
validation rules
zipcodefirst field must be filled in first
then zipcodefirst field is filled you can fill second field
second field must have 4 digits in it
first field must have five digits
cant fill second field while first one is empty or incorectly filled
Im strugling with validation part for quite a while now.... :(
How i could achieve that thru mvc3 unobtrusive validation tools?
any help will be highly apreciated guys.
Add unobrusive data data validation on the textbox by adding data-val="true" and use a regular expression for your zip code.
<input type="text" data-val="true" data-val-regex="Invalid zip code format" data-val-regex-pattern="YOUR REGEXP HERE" />
UPDATE
If you also want it to be required you can add the data-val-required attribute.
<input type="text" data-val="true" data-val-requred="Zip code is required" data-val-regex="Invalid zip code format" data-val-regex-pattern="YOUR REGEXP HERE" />
More information about validation in MVC 3:
http://bradwilson.typepad.com/blog/2010/10/mvc3-unobtrusive-validation.html

Resources