Someone maybe knows why I can't display list of categories in my app. File categories.xhtml shows only word Categories. Class Category sets id and name in constructor.
categories.xhtml
<ui:component>
<h:form>
<h4>Categories</h4>
<ul>
<ui:repeat var="category" value="#{categoriesBean.modelCategories}">
<li><h:outputText value="#{category.name}">
</h:outputText>
</li>
</ui:repeat>
</ul>
</h:form>
</ui:component>
CategoriesBean.java
#ManagedBean
#RequestScoped
public class CategoriesBean {
private ListDataModel<Category> modelCategories = new ListDataModel<Category>();
public ListDataModel<Category> getModelCategories() {
return modelCategories;
}
public void setModelCategories(ListDataModel<Category> modelCategories) {
this.modelCategories = modelCategories;
}
public CategoriesBean() {
modelCategories.setWrappedData(DAO.getDAO().getCategories());
}
}
DAO.java
public class DAO {
private static DAO instance = new DAO();
private List<Category> categories = new ArrayList<Category>();
{
Category smartphones = new Category(1, "Smartphones");
Category consoles = new Category(2, "Consoles");
categories.add(smartphones);
categories.add(consoles);
}
public static DAO getDAO() {
return instance;
}
public List<Category> getCategories() {
return this.categories;
}
Here is site source:
<form id="j_idt2" name="j_idt2" method="post" action="/Shop/categories.xhtml" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_idt2" value="j_idt2" />
<ul>
</ul><input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="H4sIAAAAAAAAAJVSQWvUQBR+Tbp2G1Zpt9KL6KkIgmSp2IuLuIvt0sXULqSCxYPOZqebWSfJOPOym/RQ8B8InoSKVw/e/AXVgyAo6FFv3j16dyaN3R704EBe8vK+9+Z773tvfkJFKAmLIzImboqMu5tEhVtEVOa+Hb1ffvTFBqsDDk/IoEMCTGQX5jGUVIUJH2TiVgvMqU2q2i7ox0Y4M3rIBriaSlh64BV1OYmH7nZ/RANsPvt8/9WCusItgEzohIrQJ30CB2Ab70CCa3Iyd48EVLlBEokkpjG697q3/3yv9GQiqMT8Ds0VlKeuC0o4N71wI06j00GB4BBEyfopUqWbXpo23ZaS5B5TmD39evHFB/LShpkuzCq2TwuW9mTWWJ10+e/sfCRIN/VMqPTJmMrdj29vPj/8tGWB5cF8wIlSd0lEEerFSBqGYcPXZOJh0wNH6ZxBUQNh+RjBkoZPJSOc7ZM+p81MiLEZEyhja7qbS/p6V6VxScZYTlG57V7P626slzjNee0fQBYJ7q7TPZJy7Bz/XGkLwfOd5DGNf72+unvYGrVqZnaTC7DYCDS/YSKZrpGFGHGAme13338cZZmWbe3/ZOtJNtblTgtk+M4hnJ+KtBMSbEvqa7Im6GigVShhlc0VE3FKx9i6kflssYHXbhSv6yfLVTWrpsPVso/cOBUDWj3BWEJkvwHxOyj9FQMAAA==" autocomplete="off" />
</form>
You don't need to call a list of DataModel when using ui:repeat :
<ui:repeat var="category" value="#{categoriesBean.categories}">
<li><h:outputText value="#{category.name}">
</h:outputText>
</li>
</ui:repeat>
Then when you'll call a service it will be most of the time be database interactions where you inject a service in your bean. For that you should use the #PostConstruct attribute (which is not needed in your case).
#ManagedBean
#RequestScoped
public class CategoriesBean {
// this is not needed but that's how you'd get from db.
//#Inject
//private MyService service;
private List<Category> categories;
// getters and setters
#PostConstruct // in your case this is not needed but it is if you use injection
public void init() {
categories = yourService.getCategories(); // this is not needed.
//instead you can add it like this.
categories = new ArrayList<Category>();
categories.add(1, "blabla");
}
}
Related
I'm trying to write a simple controller that will POST data from an HTML form to some REST endpoint.
Here's what my controller looks like:
package com.integration.common.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
#Controller
public class WebController {
#GetMapping("/form")
public String form(Model model){
model.addAttribute("fieldProps",new FieldProperties());
return "Form";
}
#PostMapping("/form")
public String submit(#ModelAttribute FieldProperties fieldProps){
return "Result";
}
}
My model:
package com.integration.common.controller;
public class FieldProperties {
private String owner;
private String storyName;
public String getOwner() {
return owner;
}
public String getStoryName() {
return storyName;
}
public void setOwner(String owner) {
this.owner = owner;
}
public void setStoryName(String storyName) {
this.storyName = storyName;
}
}
And finally, my form:
<form action="#" th:action="#{/form}" th:object="${fieldProps}" method="post" >
<div class="form-group">
<label for="owner">Owner</label>
<input type="text" id="owner" th:field="*{owner}" class="form-control"/>
</div>
<div class="form-group">
<label for="storyName">Name of Story</label>
<input type="text" id="storyName" th:field="*{storyName}" class="form-control"/>
</div>
<input type="submit" value="Submit" />
</form>
I understand how the flow works, but for some reason I'm still getting this exception. Do I need to somehow incorporate the #Autowired flag into my code? I'm closely following this tutorial: https://spring.io/guides/gs/handling-form-submission/
There are two ways of passing model attributes from one view to another view.
a. Your FieldProperties class variable name should be same as "fieldProperties" instead of "fieldProps" and change html to refer to "fieldProperties".
#Controller
public class WebController {
#GetMapping("/form")
public String form(Model model) {
model.addAttribute("fieldProperties", new FieldProperties());
return "Form";
}
#PostMapping("/form")
public String submit(#ModelAttribute FieldProperties fieldProperties) {
return "resultForm";
}
}
b. If you don't want to change to code at all the places by changing variable then change your post method to below, add one more parameter Model model in the method and add fieldProps again as attributes in the model
#PostMapping("/form")
public String submit(#ModelAttribute FieldProperties fieldProps, Model model) {
model.addAttribute("fieldProps", fieldProps);
return "resultForm";
}
I have a JSF2 application that should show a page where a number os items must be added in a list. The user wants to add those items, set some properties of them and finally persist them all together, in a single save operation.
The domain object that should be handled by this page looks like this:
public class Item {
private long id;
private String name;
private Item previous;
public Item() { }
public Item(Item previousItem) {
this.previous = previousItem;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Item getPrevious() {
return previous;
}
}
The ItemBean class looks like this:
#ManagedBean
public class ItemBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<Item> items = new ArrayList<Item>();
public List<Item> getItems() {
if(items.size()==0) {
items.add(new Item()); // adding the first item
}
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
public void addItem(Item previousItem) {
Item newItem = new Item(previousItem);
items.add(newItem);
}
public void save() {
...
}
}
The view is a xhtml file that looks like this:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<ui:composition template="/templates/layout.xhtml">
<ui:define name="content">
<h2>Items</h2>
<fieldset>
<legend>Items being added</legend>
<ui:repeat value="#{itemBean.items}" var="item">
<div>
<h:outputLabel value="Item" for="name" />
<h:inputHidden value="#{item.id}" />
<h:inputText id="name" value="#{item.name}" />
<h:commandLink action="#{itemBean.addItem(item)}">Add</h:commandLink>
</div>
</ui:repeat>
</fieldset>
<div class="options">
<h:commandButton action="#{itemBean.save}" value="Save"/>
<div class="clear border-bottom"></div>
</div>
</ui:define>
</ui:composition>
</body>
</html>
Notice that in order to add a new item, the current one must be sent to satisfy business rules.
The problem is that I can add a second item with no problema, but when I click in the Add link next to the second item, the page is rerendered with one single item, just like it was in the beggining.
Unfortunatelly, I can't see what's missing to make it work, even after reading a lot of posts, pages and some book chapters.
Update 1
I was asked about the kind of scope used with this bean. It´s de default scope (#RequestScoped). I was trying to avoid using #SessionScoped for the sake of scalability, but in this particular case, I´m not sure I have a choice. Anyone with more experience could give me tip?
What is the scope of your ManagedBean ?
Since you didn't post any persistence code, I suppose the items List only exists througout your Bean's life. This means that if your Bean is #ViewScoped or #RequestScoped, your items cease to exist after you submit your form.
You need use an ajax component, something like:
<fieldset id="list">
<legend>Items being added</legend>
<ui:repeat value="#{itemBean.items}" var="item">
<div>
<h:outputLabel value="Item" for="name" />
<h:inputHidden value="#{item.id}" />
<h:inputText id="name" value="#{item.name}" />
<h:commandLink action="#{cargoBean.addItem(item)}">
<f:ajax render="list" />
Add
</h:commandLink>
</div>
</ui:repeat>
</fieldset>
I see no form in your xhtml page like :
<h:form>
<ui:repeat>
<h:inputBlabla/>
</ui:repeat>
</h:form>
A form is needed while using h:input fields.
I have the class Lesson, which holds the reference to Course object, like so:
public class Lesson {
...
private Course course;
...
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
...
}
And I want to set the Course property on the Lesson object through the select form:
<form:form method="post" action="addLesson" modelAttribute="lesson">
<form:select path="course">
<form:options items="${courses}"/>
</form:select>
<input type="submit" name="addLesson" value="Add lesson">
</form:form>
In my controller I have the following:
#Controller
public class LessonController {
#Autowired
private LessonRepository lessonRepository;
#Autowired
private CourseRepository courseRepository;
// form setup
#RequestMapping(value = "/", method = RequestMethod.GET)
public String showSchedule(ModelMap model) {
...
model.addAttribute("lesson", new Lesson());
model.addAttribute("courses", courseRepository.findAll());
...
}
#RequestMapping(value = "/addLesson", method = RequestMethod.POST)
public String addLesson(#ModelAttribute("lesson") Lesson lesson, BindingResult result) {
lessonRepository.save(lesson);
return "redirect:/";
}
...
}
The problem is that it passes the String representation of the Course object (defined by toString()) to the course setter of the Lesson object.
How do I properly set the Course property of the Lesson object using my select form?
Usually for UI rendering Formatter<T> is used with ConversionService. But prior to Spring 3, PropertyEditors were used.
I've shared sample github project for your case https://github.com/jama707/SpringSelectBoxSample
#Component("courseFormatter")
public class CourseFormatter implements Formatter<Course> {
private CourseRepository courseRepository=new CourseRepository();
#Override
public String print(Course course, Locale arg1) {
return course.getName();
}
#Override
public Course parse(String actorId, Locale arg1) {
return courseRepository.getCourse(actorId);
}
}
According to spring documentation you need to set itemValue and itemLabelon the form:options tag, otherwise ,as you already mentioned, the value will be the toString() of the Object, itemValue and itemLable should refer to properties from your Course bean.
Assuming that your Course class has a property name, then your form should look like this:
<form:form method="post" action="addLesson" modelAttribute="lesson">
<form:select path="course">
<form:options items="${courses}" itemValue="name" itemLabel="name"/>
</form:select>
<input type="submit" name="addLesson" value="Add lesson">
</form:form>
You can bind the course object directly instead of some course object property by using Spring Converters.
Implement the Converter interface which in your case may convert selected courseName to Course:
public class CourseConverter implements Converter<String, Course> {
public Course convert(String source) {
List<Course> courseList = //Populate courseList the way you did in Lesson
Course course = //Get course object based on selected courseName from courseList;
return course;
}
}
Now register the converter:
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean" >
<property name="converters">
<set>
<bean class="your.package.CourseConverter"/>
</set>
</property>
</bean>
and change your form:options as:
<form:options items="${courses}" itemValue="courseName" itemLabel="courseName"/>
My goal is to get the selected value of type Sistema, so I can update a datatable and another SelectOneMenu.
Whenever a value is selected the ajax tag behaves correctly, and calls configura(), however my sistemaSelecionado (wich is an Object in Bean)always return as null to my Backing Bean.
The converter is working fine in another page with the same class Sistema. But it doesn't fire on this specific page.
This is the xhtml page
<div>
<p:outputLabel title="Sistema"></p:outputLabel>
</div>
<div>
<p:selectOneMenu id="selectOneMenu"
value="#{permissaoListBean.sistemaSelecionado}"
converter="entityConverter">
<p:ajax event="change" listener="#{permissaoListBean.configura}"
update="selectOneMenuGrupo,secoes"></p:ajax>
<f:selectItem itemLabel="Selecione" itemValue="" />
<f:selectItems value="#{permissaoListBean.listaSistema}"
var="sistema" itemLabel="#{sistema.nome}" itemValue="#{sistema}">
</f:selectItems>
</p:selectOneMenu>
</div>
Here is my Backing Bean
#Component("permissaoListBean")
#Scope("session")
public class PermissaoListBean {
private List<Sistema> listaSistema = new ArrayList<Sistema>();
//Service das entidades
#Autowired
private SistemaService sistema;
#Autowired
private GrupoService grupo;
#Autowired
private SecaoService secao;
//Objetos da view
private Sistema sistemaSelecionado;
private Grupo grupoSelecionado;
private List<Secao> secaoSelecionada = new ArrayList<Secao>();
private LazyDataModel<Secao> modelo ;
public void populaSistema(){
listaSistema = sistema.findAll();
}
public void configura(){
populaGrupo();
populaSecao();
}
public void populaGrupo(){
setListaGrupo(grupo.findBySistema(sistemaSelecionado));
}
//dataTable lazyLoad code
//end of lazyload
public List<Sistema> getListaSistema() {
setListaSistema(sistema.findAll());
return listaSistema;
}
public void setListaSistema(List<Sistema> listaSistema) {
this.listaSistema = listaSistema;
}
//getters and setters
I have a page where I have a static list containing the list of products which are again grouped into product groups.I have a toggle button in the JSP page which shuffles between the enabled and disabled products .Code for my toggle button is as follows
<h:commandButton value="retrieve" image="#{displayProductsBean.productsToggleImage}" actionListener="#{displayProductsBean.fetchProductsBasedOnStatus}">
<c:choose>
<c:when test="${displayProductsBean.productFetchCriteria=='0'}">
<f:attribute name="buttonSelected" value="1" />
</c:when>
<c:otherwise>
<f:attribute name="buttonSelected" value="0" />
</c:otherwise>
</c:choose>
</h:commandButton>
Now in the managed bean I am able to get the value of the button selected and have logic to retrieve either enabled or disabled products
But I don't know how would I get back to the same page and also I don't want the list to be reloaded again from the DB.Code in my bean class is as follows
public void fetchProductsBasedOnStatus(ActionEvent event)
{
System.out.println("The fetchProductsBasedOnStatus in bean is called");
String selected = (String) event.getComponent().getAttributes().get("buttonSelected");
System.out.println("The value of toggle button is"+selected);
setProductFetchCriteria(Integer.parseInt(selected));
System.out.println("The value of toggle button is"+this.toString());
}
Somebody please help me resolve this .....
But I don't know how would I get back to the same page
Just return null or void in action method.
and also I don't want the list to be reloaded again from the DB
Just don't do that? If you keep the bean in the view scope and load the lists in the (post)constructor, then the same lists will be kept as long as the enduser is interacting with the same view. You should only not use JSTL tags as it breaks the view scope.
Your code can be simplified as follows:
<h:commandButton value="retrieve" image="#{bean.showDisabledProducts ? 'enabled' : 'disabled'}.png" action="#{bean.toggle}">
<f:ajax render="#form" />
</h:commandButton>
<h:dataTable value="#{bean.products}" ...>
...
</h:dataTable>
with
#ManagedBean
#ViewScoped
public class Bean {
private boolean showDisabledProducts;
private List<Product> enabledProducts;
private List<Product> disabledProducts;
#EJB
private ProductService service;
#PostConstruct
public void init() {
enabledProducts = service.listEnabledProducts();
disabledProducts = service.listDisabledProducts();
}
public void toggle() {
showDisabledProducts = !showDisabledProducts;
}
public List<Product> getProducts() {
return showDisabledProducts ? disabledProducts : enabledProducts;
}
public boolean isShowDisabledProducts() {
return showDisabledProducts;
}
}