I'm making a page using wicket.
The main page consists of a table displaying invoice information.
In the last column of the table has a link for each one of the invoices displaying the full information for that invoice, by opening a modal.
I'm using de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal
My goal is when I open the modal, the header of the modal shows the invoice number of that invoice that was opened.
I'm able to get it only after refreshing the page, and if I open the modal of another invoice the header is not updated, it shows the number of the previous invoice. I have to refresh again the page.
I don't know how to open a modal that shows in the header the number of the respective invoice without refreshing the page.
below the markup of the main page.
<wicket:extend>
<div class="page-header">
<h2>
<wicket:message key="invoices-welcome">[Welcome message]</wicket:message>
</h2>
</div>
<div>
<span wicket:id="navigator">[dataview navigator]</span>
</div>
<div>
<table cellspacing="0" class="table table-condensed">
<tr>
<th>Status</th>
<th>Invoice number</th>
<th>Supplier</th>
<th>Customer</th>
<th>Amount</th>
<th>Actions</th>
</tr>
<tr wicket:id="rows">
<td><span wicket:id="status">[status]</span></td>
<td><span wicket:id="invoiceN">[invoiceN]</span></td>
<td><span wicket:id="supplier">[supplier]</span></td>
<td><span wicket:id="customer">[customer]</span></td>
<td><span wicket:id="amount">[amount]</span></td>
<td><a wicket:id="showModal">View</a></td>
</tr>
</table>
</div>
<div wicket:id="modal"></div>
</wicket:extend>
Java code of the main page
package nl.riskco.liberobc.web.pages.invoices;
import java.util.List;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigator;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.ListDataProvider;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import nl.riskco.liberobc.client.business.model.InvoiceDomain;
import nl.riskco.liberobc.client.business.services.IInvoiceService;
import nl.riskco.liberobc.client.business.services.InvoiceServiceMocked;
import nl.riskco.liberobc.web.pages.BasePage;
//#AuthorizeInstantiation("VIEWER")
public class InvoicesPage extends BasePage {
private static final long serialVersionUID = 1L;
private InvoiceModalAgile modal2;
public InvoicesPage(PageParameters parameters) {
super(parameters);
IInvoiceService service = new InvoiceServiceMocked();
List<InvoiceDomain> invoicesToTest2;
invoicesToTest2 =service.getInvoices(1, 30);
modal2 = new InvoiceModalAgile("modal", Model.of(new InvoiceDomain()));
modal2.addCloseButton();
modal2.setOutputMarkupId(true);
add(modal2);
DataView<InvoiceDomain> dataview = new DataView<InvoiceDomain>("rows",
new ListDataProvider<InvoiceDomain>(invoicesToTest2)) {
private static final long serialVersionUID = 1L;
#Override
protected void populateItem(Item<InvoiceDomain> item) {
// TODO Auto-generated method stub
InvoiceDomain invoice = item.getModelObject();
item.add(new Label("status", invoice.getStatus()));
item.add(new Label("invoiceN", String.valueOf(invoice.getInvoiceGUID())));
item.add(new Label("supplier", invoice.getSupplier()));
item.add(new Label("customer", invoice.getCustomer()));
item.add(new Label("amount", String.valueOf(invoice.getAmount())));
item.add(new AjaxLink("showModal") {
private static final long serialVersionUID = 1L;
#Override
public void onClick(AjaxRequestTarget target) {
modal2.setInvoiceModel(Model.of(invoice), target);
modal2.show(target);
}
});
}
};
dataview.setItemsPerPage(10L);
add(dataview);
add(new PagingNavigator("navigator", dataview));
}
#Override
protected void onDetach() {
// TODO Auto-generated method stub
super.onDetach();
}
}
Markup of the modal
<wicket:extend>
<div class="panel panel-default">
<div class="panel-heading">Invoice details</div>
<div class="panel-body">
<table class="table table-bordered">
<tr>
<th><wicket:message key="invoice-id">[invoice-id]</wicket:message></th>
<td><div wicket:id="invoiceN"></div></td>
</tr>
<tr>
<th><wicket:message key="invoice-status">[invoice-status]</wicket:message></th>
<td><div wicket:id="status"></div></td>
</tr>
<tr>
<th><wicket:message key="invoice-customer">[invoice-customer]</wicket:message></th>
<td><div wicket:id="customer"></div></td>
</tr>
<tr>
<th><wicket:message key="invoice-supplier">[invoice-supplier]</wicket:message></th>
<td><div wicket:id="supplier"></div></td>
</tr>
<tr>
<th><wicket:message key="invoice-ibanSupplier">[invoice-ibanSupplier]</wicket:message></th>
<td><div wicket:id="iban"></div></td>
</tr>
<tr>
<th><wicket:message key="invoice-amount">[invoice-amount]</wicket:message></th>
<td><div wicket:id="amount"></div></td>
</tr>
<tr>
<th>Approved</th>
<td><form wicket:id="form"><input type="checkbox" wicket:id="checkbox1"></form></td>
</tr>
<tr>
<th>Early payment</th>
<td><form wicket:id="form2"><input type="checkbox" wicket:id="checkbox2"></form></td>
</tr>
<tr>
<th>Paid (by customer)</th>
<td><form wicket:id="form3"><input type="checkbox" wicket:id="checkbox3"></form></td>
</tr>
</table>
</div>
</div>
</wicket:extend>
Java code of the modal
package nl.riskco.liberobc.web.pages.invoices;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.StringResourceModel;
import de.agilecoders.wicket.core.markup.html.bootstrap.behavior.BootstrapResourcesBehavior;
import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
import nl.riskco.liberobc.client.business.model.InvoiceDomain;
public class InvoiceModalAgile extends Modal<InvoiceDomain>{
private static final long serialVersionUID = 1L;
private Label labelGuid;
private Label status;
private Label customer;
private Label iban;
private Label amountLabel;
private Label supplierLabel;
private CheckBox approved;
private CheckBox earlyPayment;
private CheckBox customerPaid;
private Form form;
private Form form2;
private Form form3;
private WebMarkupContainer header;
private WebMarkupContainer footer;
public InvoiceModalAgile(String id , IModel<InvoiceDomain> model) {
super(id, model);
add(form = new Form<>("form"));
add(form2 = new Form<>("form2"));
add(form3 = new Form<>("form3"));
status = (new Label("status",model.getObject().getStatus()));
status.setOutputMarkupId(true);
add(status);
supplierLabel = (new Label("supplier",model.getObject().getSupplier()));
supplierLabel.setOutputMarkupId(true);
add(supplierLabel);
labelGuid = new Label("invoiceN",model.getObject().getInvoiceGUID());
labelGuid.setOutputMarkupId(true);
add(labelGuid);
customer = (new Label("customer",model.getObject().getCustomer()));
customer.setOutputMarkupId(true);
add(customer);
iban = new Label("iban",model.getObject().getIBANsupplier());
iban.setOutputMarkupId(true);
add(iban);
amountLabel = new Label("amount",model.getObject().getAmount());
amountLabel.setOutputMarkupId(true);
add(amountLabel);
approved = new CheckBox("checkbox1");
approved.setOutputMarkupId(true);
approved.setEnabled(false);
add(approved);
form.setOutputMarkupId(true);
add(form);
form.add(approved);
earlyPayment = new CheckBox("checkbox2");
earlyPayment.setOutputMarkupId(true);
earlyPayment.setEnabled(false);
add(earlyPayment);
form2.setOutputMarkupId(true);
add(form2);
form2.add(earlyPayment);
customerPaid = new CheckBox("checkbox3");
customerPaid.setOutputMarkupId(true);
customerPaid.setEnabled(false);
add(customerPaid);
form3.setOutputMarkupId(true);
add(form3);
form3.add(customerPaid);
BootstrapResourcesBehavior.addTo(this);
}
public void setInvoiceModel(IModel<InvoiceDomain> invoice, AjaxRequestTarget target){
this.labelGuid.setDefaultModel(Model.of(invoice.getObject().getInvoiceGUID()));
target.add(labelGuid);
this.amountLabel.setDefaultModel(Model.of(invoice.getObject().getAmount()));
target.add(amountLabel);
this.status.setDefaultModel(Model.of(invoice.getObject().getStatus()));
target.add(status);
this.customer.setDefaultModel(Model.of(invoice.getObject().getCustomer()));
target.add(customer);
this.supplierLabel.setDefaultModel(Model.of(invoice.getObject().getSupplier()));
target.add(supplierLabel);
this.iban.setDefaultModel(Model.of(invoice.getObject().getIBANsupplier()));
target.add(iban);
this.approved.setDefaultModel(Model.of(invoice.getObject().getApprovedFlag()));
target.add(approved);
this.earlyPayment.setDefaultModel(Model.of(invoice.getObject().getOptForEarlyPaymentFlag()));
target.add(earlyPayment);
this.customerPaid.setDefaultModel(Model.of(invoice.getObject().getHasCustomerPaidFlag()));
target.add(customerPaid);
this.header(Model.of(String.valueOf(invoice.getObject().getInvoiceGUID())));
}
#Override
protected void onDetach() {
// TODO Auto-generated method stub
super.onDetach();
}
}
The problem is that you use the model object of the empty model that you pass at Modal construction. You need to use dynamic models for the properties.
Static/simple model:
label = new Label("staticValue", personModel.getObject().getName());
Here the label will use the name of the current person for each rendering.
Dynamic model:
label = new Label("staticValue", new AbstractReadOnlyModel<String>() {
#Override public String getObject() {
return personModel.getObject().getName());
}
}
You see that the dynamic version reads personModel's name lazily and it is called at each rendering of the Label. This way it will read the name of the person even if you put a new Person into the Label's Model.
In your case you need something like:
status = new Label("status", new PropertyModel(this, "model.object.status"));
For more information read: https://cwiki.apache.org/confluence/display/WICKET/Working+with+Wicket+models
Related
I'm trying to do CRUD operations with Spring. I'm using HTML and Thymeleaf on the frontend. I return the results of certain actions I have made and error messages, if any, using a custom class that I write. I don't have any problems so far. However, if an error occurs during these operations and I return this error through the class I wrote, I do not know how to display it on HTML using Thymeleaf.
I'm returning an object of this class type;
#Getter
#Setter
public class WarehouseAPIResponseHolder<T> {
private T responseData;
private HttpStatus httpStatus;
private WarehouseAPIResponseError error;
public WarehouseAPIResponseHolder(HttpStatus httpStatus) {
this.httpStatus = httpStatus;
}
public WarehouseAPIResponseHolder(T responseData, HttpStatus httpStatus) {
this.responseData = responseData;
this.httpStatus = httpStatus;
}
public WarehouseAPIResponseHolder(HttpStatus httpStatus,
WarehouseAPIResponseError error) {
this.httpStatus = httpStatus;
this.error = error;
}
}
My error class;
#Getter
#Builder
public class WarehouseAPIResponseError {
private String code;
private String message;
}
Example of an error;
if (CollectionUtils.isEmpty(warehouseEntities)) {
return new WarehouseAPIResponseHolder<>(HttpStatus.NOT_FOUND, WarehouseAPIResponseError
.builder()
.code("DATA_NOT_FOUND")
.message("No records found in the database.")
.build());
}
The method in my controller class;
#GetMapping
public String getAllWarehouses(Model model) {
model.addAttribute("listOfWarehouses",warehouseCRUDService.list().getResponseData());
return "warehouses";
}
My HTML code;
<div class="container my-2">
<h1 align="center">Warehouse List</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>Code</th>
<th>Name</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr th:each="warehouse : ${listOfWarehouses}">
<td th:text="${warehouse.id}"></td>
<td th:text="${warehouse.code}"></td>
<td th:text="${warehouse.name}"></td>
<td th:text="${warehouse.status}"></td>
</tr>
</tbody>
</table>
</div>
I am successfully listing, but if there is an error message I don't know how to display it. I did not use Spring validation methods. Is there any way I can do this in a simple way?
You can set the error on backend using model.addAttribute("errorMessage", error)
and then show it in an element if error exists. For example:
<span th:if="${errorMessage != null}" th:text=${errorMessage}/>
I want to bind my HTML table with all fields to Java code in Spring Boot.
Therefore, I have annotated my method with Postmapping, too.
I was already able to show all the fields in Thymeleaf and I was also able to set the checkBox value ( true / false ) accordingly.
This is my Thymeleaf HTML code:
<form action="#" th:action="#{/mitarbeiterverwaltung}" th:object="${users}" method="post">
<fieldset>
<table border="1" align="center">
<thead>
<tr>
<!-- <th:text = "#{mitarbeiterverwaltung.active}>Active ( Tick ) / Passive</th>-->
<th>Active ( Tick ) / Passive</th>
<th>ID</th>
<th>Username</th>
<th>Anzeigename</th>
<th>Dienstnummer</th>
</tr>
</thead>
<tbody>
<tr th:each="user, itemStat : *{users}">
<td><input th:field="*{users[__${itemStat.index}__].isActive}"
th:checked="${user.isActive}"
class="checkBox"
type="checkBox"
name="checkBox"
/></td>
<td><input th:field="*{users[__${itemStat.index}__].id}"
readonly/></td>
<td><input th:field="*{users[__${itemStat.index}__].username}"
readonly/></td>
<td><input class="anzeigename"
type="text"
name="anzeigename"
th:field="*{users[__${itemStat.index}__].anzeigename}"
th:id="${itemStat.index}"
readonly/></td>
<td><input class="dienstnummer"
type="text"
name="dienstnummer"
th:field="*{users[__${itemStat.index}__].dienstnummer}"
th:id="${itemStat.index}"
readonly/></td>
</tr>
</tbody>
</table>
<br />
<div style="text-align:center;">
<input type="submit" id="submitButton" th:value="Speichern"/>
</div>
</fieldset>
And this is my Java code, where the field isActive of UserCreationDto is always null.
#PostMapping
public String updateActivePassiveUser(#ModelAttribute UserCreationDto userTableSettings,
#RequestParam("checkBox") String checkBoxName, BindingResult result, Model model, Errors errors) {
logger.info("Method {} called in {}", new Object() {}.getClass().getEnclosingMethod().getName(), this.getClass().getName());
if (errors.hasErrors()) {
logger.error("Error in {}", new Object() {}.getClass().getEnclosingMethod().getName());
return "error";
}
List<Benutzer> users = userManagementServiceImpl.getAllUsers();
userManagementServiceImpl.updateActivePassiveUser(1, 0);
return "redirect:/mitarbeiterverwaltung?success";
}
Here is a picture of the field in Java code where the method is annotated with #PostMapping
And so does my #RequestMapping look like:
This is my #RequestMapping method:
#RequestMapping
public String showUserManagement(Model model) {
logger.info("Method {} called in {}", new Object() {}.getClass().getEnclosingMethod().getName(), this.getClass().getName());
List<Benutzer> users = userManagementServiceImpl.getAllUsers();
userForm = userManagementServiceImpl.saveUserForm(users);
model.addAttribute("users", userForm);
return "mitarbeiterverwaltung";
}
My UserCreationDto where all the fields get added to a list:
public class UserCreationDto {
private List<User> users = new ArrayList<>();
public void addUser(User user) {
this.users.add(user);
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
And my simple POJO class with all the fields
#Data
public class User {
//#SafeHtml prevents XSS ( Cross-Site Scripting )
#SafeHtml
private String username;
private String password;
private String anzeigename;
private String dienstnummer;
private long id;
private Boolean isActive;
}
The other fields like anzeigename, dienstnummer, id, and username are filled within my Java code, however, isactive is always null.
Maybe, someone can tell me what I am doing wrong here.
Thank you very much in advance.
I think you have to many options set. You don't need th:checked:
<input th:field="*{users[__${itemStat.index}__].isActive}"
class="checkBox"
type="checkBox"
name="checkBox" />
I found another way now, but it is not really nice.
#PostMapping
public String updateActivePassiveUser(#Valid #ModelAttribute("userForm") UserCreationDto userTableSettings,
#RequestParam List<String> searchValues, BindingResult result, Model model, Errors errors) {
The field searchValues contains all the checkBoxes that are ticked.
This is my view:
<td><input type="checkbox"
name="searchValues"
th:value="${user.id}"
th:checked="${user.isActive}"
/>
Now, the only problem that I am having is how to update my column that is of type Boolean in Postgresql?
For accomplishing this task I call this:
userRepo.updateActivePassiveUser(new Boolean("False"), id);
#Modifying
#Query(value = "UPDATE benutzer SET active = :active WHERE id = :id", nativeQuery = true)
#Transactional
void updateActivePassiveUser(#Param("active") Boolean active, #Param("id") long id);
However, the value in my database never changes.
Maybe, someone could give me a last hint, please!
I know this is a question which has been asked before. I did look at those questions but I was still not able to resolve my problem and thus writing in on stackoverflow. I am trying to bind the form parameters from my form addArticles.jsp to the controller. On the controller when I do a system.out.println I only get the categoryId and do not get the categoryName. I am not sure what I am doing is incorrect and pretty amused.
addArticles.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Add Article</title>
</head>
<body>
<center>
<h2>Create New Article</h2>
<form:form action="/one2one/articles/save.do" method="POST" modelAttribute="command">
<table>
<tr>
<td><form:label path="id">Article ID</form:label></td>
<td><form:input path="id" value="${article.id}"></form:input></td>
</tr>
<tr>
<td><form:label path="title">Article Title</form:label></td>
<td><form:input path="title" value="${article.title}"></form:input></td>
</tr>
<tr>
<td><form:label path="description">Article Description:</form:label></td>
<td><form:input path="description" value="${article.description}" cssStyle="width: 150px;"></form:input></td>
</tr>
<tr>
<td><form:label path="category.categoryId">Category Type</form:label></td>
<td><form:select path="category.categoryId" cssStyle="width: 150px;">
<option value="-1">Select a type</option>
<c:forEach items="${categories}" var="category">
<option <c:if test="${category.categoryName eq article.category.categoryName}">selected="selected"</c:if>
value="${category.categoryId}">${category.categoryName}</option>
</c:forEach>
</form:select>
</td>
</tr>
<tr>
<td><form:label path="keywords">Article Keywords:</form:label></td>
<td><form:input path="keywords" value="${article.keywords}"></form:input></td>
</tr>
<tr>
<td><form:label path="content">Article Content:</form:label></td>
<td><form:input path="content" value="${article.content}"></form:input></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="SAVE"/></td>
</tr>
</table>
</form:form>
</center>
</body>
</html>
ArticlesController.java
package com.java.bricks.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.java.bricks.model.Article;
import com.java.bricks.model.Category;
import com.java.bricks.service.ArticleService;
import com.java.bricks.service.CategoryService;
#Controller("articlesController")
#RequestMapping(value="/articles")
public class ArticlesController {
#Autowired
private ArticleService articleService;
#Autowired
private CategoryService categoryService;
#RequestMapping(value="/list", method=RequestMethod.GET)
public ModelAndView listArticles(#ModelAttribute("command") Article article, BindingResult bindingResult){
Map<String,Object> model = new HashMap<String,Object>();
model.put("articles", articleService.listArticles());
return new ModelAndView("articlesList",model);
}
#RequestMapping(value="/add",method=RequestMethod.GET)
public ModelAndView addArticle(#ModelAttribute("command") Article article, BindingResult bindingResult) {
Map<String,Object> model = new HashMap<String,Object>();
model.put("articles", articleService.listArticles());
model.put("categories", categoryService.listCategories());
return new ModelAndView("addArticle",model);
}
#RequestMapping(value="/save",method=RequestMethod.POST)
public ModelAndView saveArticle(#ModelAttribute("command") Article article, BindingResult bindingResult) {
Map<String,Object> model = new HashMap<String,Object>();
System.out.println("----------------------");
System.out.println(article.getCategory());
System.out.println(article.getCategory().getCategoryName());
System.out.println(article.getCategory().getCategoryId());
articleService.addArticle(article);
model.put("articles",articleService.listArticles());
return new ModelAndView("addArticle",model);
}
}
when I click save the first 4 lines of the SOP statements are
System.out.println(article.getCategory());
output: Category [categoryId=29, categoryName=null]
System.out.println(article.getCategory().getCategoryName());
null
System.out.println(article.getCategory().getCategoryId())
29
I am not sure why the categoryName is not populated in the controller.
Article.java
package com.java.bricks.model;
public class Article {
private Long id;
private String title;
private String description;
private String keywords;
private String content;
private Category category;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getKeywords() {
return keywords;
}
public void setKeywords(String keywords) {
this.keywords = keywords;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
You aren't going to get the category name in the form's content because the category's name is being used a the label for the option. Only the value gets bound. This is your binding path="category.categoryId". You aren't binding anything to path="category.categoryName" so it's going to be null.
So in your controller you have to get the category by its ID. If you want to do some automatic custom conversion, that is a separate question.
Here's a nice article on entity conversion.
I'm pretty new to Spring and Spring Web Flow to be precise.
I'm running into the issue of not being able to bind the view with the form on submit :-
Here is what I have for code :-
P.s : I don't know what model={} does in the flow XML, but that's what was available in the code already, and changing it to alertForm doesn't change the behavior/
a) JSP
<form:form name="alertSubmitForm" method="post" id="alertsForm" modelAttribute="alertForm">
<table class="general">
<tr>
<th>Alert Text
</th>
<td><form:textarea path="alertText" cols="50" id="alertText" style="padding-top: 11px"></form:textarea>
</td>
<td><span id="characterCount"></span>/250
</td>
<td><br/><br/><br/><br/><br/><input id="advancedAlertOptions" type="button" value="More" class="primarybtn" style="float:right;"/></td>
</tr>
<tr class="advancedAlertOptions" style="display:none">
<th>Active Date
</th>
<td><form:input path="activeDate" id="activeDate" type="date"/>
</td>
</tr>
<tr class="advancedAlertOptions" style="display:none">
<th>Expiration Date
</th>
<td><form:input id="expDate" path="expDate" type="date"/>
</td>
</tr>
<tr class="advancedAlertOptions" style="display:none">
<th>Author
</th>
<td><form:input id="author" path="author" type="text" disabled="true" value="${author}" />
</td>
</tr>
<tr class="advancedAlertOptions" style="display:none">
<th>Added on
</th>
<td><form:input id="addedDate" type="date" path="addedDate" disabled="true"/>
</td>
</tr>
</table>
<input id="cancelAddAlert" type="button" value="Cancel" class="secondarybtn" style="float:right; margin-left:20px;"/>
<input id="persistAlert" type="submit" value="Add" class="secondarybtn" style="float:right;" name="_eventId_addAlert"/>
</form:form>
b) Flow XML
<view-state id="general" view="editMember/general" model="{}" parent="#abstract-member-view">
<on-entry>
<evaluate expression="new com.company.member.alerts.AlertForm()" result="viewScope.alertForm"/>
</on-entry>
<on-render>
<evaluate expression="alertManagementService.getAlertsList(partyIdMember)" result="viewScope.alerts" />
</on-render>
<transition on="addAlert" to="general" bind="true" >
<evaluate expression="alertManagementService.addAlertToMember(alertForm,partyIdMember)" />
</transition>
</view-state>
c) Service Call
package com.company.member.alerts;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.hibernate.SQLQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.company.domain.db.GenericDao;
#Service("alertManagementService")
#Transactional(readOnly = true)
public class AlertManagementServiceImpl implements AlertManagementService {
#Autowired
GenericDao dao;
#Override
public List<AlertForm> getAlertsList(Long memberId) {
String a = "SELECT * FROM PARTY_ALERT WHERE PARTY_ID = "+memberId+ " ORDER BY PA_ACTIVE_DATE";
SQLQuery query = dao.createSQLQuery(a);
List<Object[]> queryResults = query.list();
List<AlertForm> results = new ArrayList<AlertForm>();
for(Object[] arr : queryResults) {
AlertForm alertForm = new AlertForm();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd H:m:s");
try {
alertForm.setAlertId(Long.valueOf(arr[0].toString()));
alertForm.setMemberId(Long.valueOf(arr[1].toString()));
alertForm.setAlertText(arr[2].toString());
Date acD = df.parse(arr[3].toString());
alertForm.setActiveDate(acD);
if(arr[4]!=null) {
Date expD = df.parse(arr[4].toString());
alertForm.setExpDate(expD);
}
alertForm.setAuthor(arr[5].toString());
Date adD = df.parse(arr[6].toString());
alertForm.setAddedDate(adD);
alertForm.setAddedDate(adD);
alertForm.setActiveDate(acD);
}
catch (ParseException e) {
e.printStackTrace();
}
results.add(alertForm);
}
return results;
}
#Override
public void addAlertToMember(AlertForm alert, Long memberID) {
Date expDate;
PartyAlerts partyAlertsDB = new PartyAlerts();
if(alert.getAlertText()!=null) {
partyAlertsDB.setAlertText(alert.getAlertText());
partyAlertsDB.setActiveDate(alert.getActiveDate());
partyAlertsDB.setMemberId(memberID);
if((expDate = alert.getExpDate())!=null) {
partyAlertsDB.setInactiveDate(expDate);
}
}
else { //hardcoding into DB
partyAlertsDB.setActiveDate(new Date());
partyAlertsDB.setInactiveDate(new Date());
partyAlertsDB.setAlertText("This is a hardcoded alert");
partyAlertsDB.setMemberId(memberID);
}
dao.save(partyAlertsDB);
}
}
d) Form Backing Bean
package com.company.member.alerts;
import java.io.Serializable;
import java.util.Date;
public class AlertForm implements Serializable{
private static final long serialVersionUID = 1L;
private Long alertId;
private Long memberId;
private String alertText;
private Date activeDate;
private Date expDate;
private Date addedDate;
private String author;
public AlertForm() {
}
public Long getAlertId() {
return alertId;
}
public void setAlertId(Long alertId) {
this.alertId = alertId;
}
public Long getMemberId() {
return memberId;
}
public void setMemberId(Long memberId) {
this.memberId = memberId;
}
public String getAlertText() {
return alertText;
}
public void setAlertText(String alertText) {
this.alertText = alertText;
}
public Date getActiveDate() {
return activeDate;
}
public void setActiveDate(Date activeDate) {
this.activeDate = activeDate;
}
public Date getExpDate() {
return expDate;
}
public void setExpDate(Date expDate) {
this.expDate = expDate;
}
public Date getAddedDate() {
return addedDate;
}
public void setAddedDate(Date addedDate) {
this.addedDate = addedDate;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
The issue is that - when I submit the form - alertForm element are NULL . The getter to get all the alerts on render works as expected.
Any help will be highly appreciated.
If you are new to SWF why are using advanced features like flow inheritance? what are the contents of the parent flow which contains the reference:
... model="{}" parent="#abstract-member-view">
This is most likely the source of your problem. You need to explicitly define the model attribute to an already initialized POJO in order to bind the form fields correctly to it.
So for testing purposes to simplify initialize a new AlertForm in the flow some where before and OUTSIDE your view-state
....
<set name="alertFormModel" value="new com.company.member.alerts.AlertForm()"/>
....
<!-- then when you enter the view-state define it like this: -->
<view-state id="general" view="editMember/general" model="alertFormModel">
....
</view-state>
if this test works then create/implement a Factory pattern for AlertForm to get rid of the ugly 'new' syntax in your flow xml
I'm trying to send object in a SpringController to the client. But it doesn't work.
I've read the same questions a bunch of times, but couldn't figure it out.
Here is my code :
#Controller
#RequestMapping(value = "/departs/{from}")
public class NextTrainController {
/** Handle nextTrains request with a destination specified */
#RequestMapping(value = "/{to}", method = RequestMethod.GET)
public String getNextTrainsToDestination(#PathVariable String from, #PathVariable String to,
#RequestParam(value = "date", required = false) Date date, Model model) {
// Date null means we leave now
if (date == null)
date = new Date();
/* debug */
List<TransilienTrain> trains = new ArrayList<TransilienTrain>(5);
TransilienTrain train = new TransilienTrain();
train.setMission("VIK30");
trains.add(train);
train = new TransilienTrain();
train.setMission("KOOPA34");
trains.add(train);
train = new TransilienTrain();
train.setMission("BOUGA90");
trains.add(train);
model.addAttribute("origin", from);
model.addAttribute("destination", to);
model.addAttribute("trains", trains);
return "departs";
}
My departs.jsp :
<c:if test="${not empty trains}">
<table class="table table-striped table-hover">
<thead>
<tr>
<th class="col-sm-1">Départ</th>
<th class="col-sm-1">Train</th>
<th class="col-sm-2">Destination</th>
</tr>
</thead>
<tbody>
<c:forEach var="o" items="${trains}">
<tr>
<td>12h38*</td>
<td>${o.mission}</td>
<td>Paris Nord</td>
</tr>
</c:forEach>
</tbody>
</table>
<p>* Horraires théoriques</p>
</c:if>
My TransilienTrain class has a getter/setter for the mission attribute.
#Entity
#Table
public class TransilienTrain {
private String mission;
public String getMission() {
return mission;
}
public void setMission(String mission) {
this.mission = mission;
}
}
When I check the source code of the page, I do have the items in my list, but the o.mission isn't replaced with anything.
Found the solution. Thanks to #singh101.
Forgot to import the taglib definition:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>