I'm developing a Java EE e-commerce application that will sell car parts. I can add items to the shopping cart implemented using CopyOnWriteArrayList. I then use a managed bean (session scoped) to display its contents.
I then use a to display the data in ViewCode.xhtml. The probelsm is: It will only show the first item in the arraylist. Please can someone help?
The Managed Bean:
#ManagedBean(name="ViewCartManagedBean")
#SessionScoped
public class ViewCartManagedBean {
List<Orderitem> cartItemsList = new ArrayList<>();
#EJB
com.shop.cart.CartFacade cartFacade;
public ViewCartManagedBean(){}
#PostConstruct
public void initialize(){
setCartItemsList();
}
public List<Orderitem> getCartItemsList() {
return cartItemsList;
}
public void setCartItemsList() {
cartItemsList = cartFacade.viewItemsIntheCart();
}
}
The cart facade
#Stateless(name="ShoppingCartLocal")
public class CartFacade {
#PersistenceContext(unitName ="Shop")
EntityManager cartEntityManager;
#EJB
ShoppingCart cartBean;
public CartFacade(){}
public void assignCustomerToCart(CustomerEntity customer){
cartBean.setCustomer(customer);
}
public boolean addItemToCart(ProductEntity product, int quantityPurchased){
boolean result = false;
result=cartBean.addCartItem(product, quantityPurchased);
return result;
}
public List<Orderitem> viewItemsIntheCart(){
return cartBean.getCartItems();
}
the ShoppingCartBean
#Stateful(name="ShoppingCart")
#StatefulTimeout(value = 200)
public class ShoppingCartBean implements ShoppingCart,ShoppingCartLocal {
#PersistenceContext(unitName ="Shop", type=PersistenceContextType.EXTENDED)
private EntityManager cartEntityManager;
private CustomerManager customerManagerBean;
private CopyOnWriteArrayList<Orderitem> cartItems= new CopyOnWriteArrayList<Orderitem>();
private CustomerEntity customer=null;
public CustomerEntity getCustomer() {
return customer;
}
public void setCustomer(CustomerEntity customer) {
this.customer = customer;
System.out.println("hey Im linked to the cart " + customer.getName());
}
private com.shop.entity.Orderitem basketItem=new Orderitem();
public ShoppingCartBean(){}
#PostConstruct
public void initialise(){
//cartItems = new CopyOnWriteArrayList<Orderitem>();
}
public void removeCartItem(int itemCode){
System.out.println("hello");
}
#Override
public boolean addCartItem(ProductEntity product, int quantityPurchased){
double subTotal;
boolean result=false;
if (cartItems.size()==0){
basketItem.setItemcode(product.getItemcode());
basketItem.setItemdescription(product.getItemdescription());
basketItem.setUnitprice(product.getUnitprice());
basketItem.setQuantitypurchased(quantityPurchased);
subTotal=quantityPurchased*basketItem.getUnitprice();
basketItem.setSubtotal(subTotal);
cartItems.add(basketItem);
result=true;
}else{
Iterator<Orderitem> basketIterator = cartItems.iterator();
while (basketIterator.hasNext()){
Orderitem cartItem = basketIterator.next();
System.out.println("cart item item code: " + cartItem.getItemcode());
System.out.println("product item code: " + product.getItemcode());
if(cartItems.size()!=0 && !(cartItem.getItemcode().equals((product.getItemcode())))){
basketItem.setItemcode(product.getItemcode());
basketItem.setItemdescription(product.getItemdescription());
basketItem.setUnitprice(product.getUnitprice());
basketItem.setQuantitypurchased(quantityPurchased);
subTotal=quantityPurchased*basketItem.getUnitprice();
basketItem.setSubtotal(subTotal);
cartItems.add(basketItem);
result=true;
}
}
}
System.out.println("cart size " + cartItems.size());
return result;
}
Finally the view (ViewCart.xhtml)
<h:form name="ViewCartManagedBean">
<h:dataTable var="cartList" value="#{ViewCartManagedBean.cartItemsList}"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row" >
<h:column>
<f:facet name="header"><h:outputText value="Item Code" style="font-family: Verdana, Helvetica, sans-serif;font-size: 16px;"/></f:facet>
<h:outputText value="#{cartList.itemcode}" style="font-family: Verdana, Helvetica, sans-serif;font-size: 14px;"/>
</h:column>
Datatable looks like a valid way to display your list data, pretty much a copy of the tutorial
However the way you add your data is wrong. (which is why I suggested using a debugger in comments.)
at the time of printing you should notice only 1 element in your list (I expect) or many times the same item.
Your instance variable:
private com.shop.entity.Orderitem basketItem=new Orderitem();
is reused over and over. this should be a method variable not an instance variable. You add the same instance to the list over and over, while updating it's properties. This will update the properties of a single instance and not create new ones. This means that if you do:
List list = new SomeList();
SomeObject object = new SomeObject();
list.add(object);
list.add(object);
object.setName("name");
the list will contain 2 references to the same object, both with name "name"
So again: this is what you are doing when you use the instance variable
basketItem rather than make it a variable that only lives in the method addCartItem
when adding items to your cart you should use something like:
public boolean addCartItem(ProductEntity product, int quantityPurchased){
for (Orderitem current : cartItems) {
if (current.getItemCode().equals(product.getItemCode())) {
// adding duplicate entry.
return false; // or handle adding differently
}
}
// now that we're sure that the item doesn't already exist in the basket
Orderitem basketItem=new Orderitem();
basketItem.setItemcode(product.getItemcode());
basketItem.setItemdescription(product.getItemdescription());
basketItem.setUnitprice(product.getUnitprice());
basketItem.setQuantitypurchased(quantityPurchased);
basketItem.setSubtotal(quantityPurchased*basketItem.getUnitprice());
cartItems.add(basketItem);
return true;
}
Next time, run your debugger and check (after adding several items to your list) what the actual contents of the list items are. That way you can probably spot that something is going wrong.
Related
I am having problems accessing GUI elements outside the model class in my ZK project. I have a ListItemRenderer that renders the data and the position of the corresponding model when I click on an element in a list box, but my instance is permanently null when I access the article class again, as well as all GUI elements that I connect when I create the class for the first time (via getFellow ()). Is that even the right approach? Alternatively, could I add a listener to a variable that reloads the text box if it is changed? Thanks for every hint, I've already had several frustrating hours behind me and hope the code snippet is enough.
ZUL:
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./winArticles"?>
<window id="winArticles" title="Looking for Evidence" width="1100px" height="880px"
border="normal" use="xxx.Articles" closable="true" sizable="false">
...
<listbox id="artikel_output" width="100%" height="" multiple="true"
checkmark="true" vflex="true" nonselectableTags="*">
<listhead>
<listheader label="Artikel"/>
</listhead>
</listbox>
...
<div vflex="1">
<textbox style="font-size:50px"
id="tb_article_abstract"
multiline="true"/>
</div>
...
</window>
Model :
public class Articles extends Window implements AfterCompose,
IGenericDomainValueSelectorActions, IUpdateModal, IGenericListActions {
private static Articles instance;
public Articles() { }
public static Articles getInstance() {
if (instance == null) {
instance = new Articles();
}
logger.debug("Instance getInstance " + instance.getId());
return instance;
}
#Override
public void afterCompose() {
instance = new Articles();
tb_article_abstract = (Textbox) getFellow("tb_article_abstract");
...}
Initializing the listbox renderer:
public void fillListBoxWithArticles(final Listbox lb, List<Article> articles) {
if (articles.size() == 0) {
lb.appendChild((Component) articles.get(0));
}
lb.setItemRenderer(new ArticleItemRenderer());
lb.setCheckmark(true);
lb.setMultiple(true);
ListModelList<Article> lml_articles = new ListModelList<Article>(articles);
lml_articles.setMultiple(true);
lb.setModel(lml_articles);
lb.focus();
}
If a list box element has been selected, display an attribute of it in a text box, but the textbox is always null...
public void setArticleToInfobox(Article selectedArticle, int selectedIndex) {
this.selectedArticle = selectedArticle;
// tb_article_abstract = null
tb_article_abstract.setValue(selectedArticle.getAbstract_full());
tb_article_abstract.invalidate();
}}
The ItemRenderer is getting the data (and the index) of the selected Item:
public class ArticleItemRenderer implements ListitemRenderer<Article> {
#Override
public void render(Listitem item, Article data, int index) throws Exception {
item.appendChild(new Listcell(data.getArticletitle() + ", " );
item.addEventListener(Events.ON_CLICK, new EventListener() {
#Override
public void onEvent(Event event) throws Exception {
EvidenceBasedArticles.getInstance().setArticleToInfobox(data, item.getIndex());
}});}
You are making some crucial faults here.
public static Articles getInstance() {
if (instance == null) {
instance = new Articles();
}
logger.debug("Instance getInstance " + instance.getId());
return instance;
}
This will never work good, you are developing a web application.
This means that 2 users at the same time can have only 1 instance, however your Article is allocated to a specific Desktop, so 1 user will have problems.
What's wrong with :
lb.setItemRenderer(new ArticleItemRenderer(tb_article_abstract));
Your renderer has a new instance for this specific class, so it's bound to the correct desktop.
As long you don't remove that item from the DOM, this would be no problem to do.
I have a class called persone (peoples), it's just an arraylist of object persona (person).
I want to use this the object persone for populate a JComboBox.
I've read many post, and I've understood that I've to use DefaultComboBoxModel(E[] items), but, of course, I've missed something. I made some mistake. Can I have an example ? And how to set or get the selected item?
This is my class:
public class Persone {
private ArrayList<Persona> el = new ArrayList<Persona>();
public Persone() {
}
public ArrayList<Persona> getEl() {
return el;
}
public void setEl(ArrayList<Persona> el) {
this.el = el;
}
public boolean delPersonaFromPersone(Persona persona) {
return this.el.remove(persona);
}
public boolean addPersonaToPersone(Persona persona) {
return this.el.add(persona);
}
public boolean substPersonaInPersone(Persona persona, Persona withPersona ) {
if ( !this.el.remove(persona))
return false;
return this.el.add(persona);
}
#Override
public String toString() {
return "Persone [el=" + el + "]";
}
}
You can't add an Object containing an ArrayList to a combo box.
Instead you need to add individual Persona object to the combo box.
Then you would need to provide a custom renderer to display the Persona object.
Check out Combo Box With Custom Renderer for more information and examples on how to do this.
I've found my mistake (some bad assignment).
For use in JComboBox, I've made a new array from ArrayList.
Here my code:
JComboBox<Persona> cbResponsabile = new JComboBox<Persona>();
Persona[] array = persone.getEl().toArray(new Persona[persone.getEl().size()]);
cbResponsabile.setModel(new DefaultComboBoxModel(array));
contentPanel.add(cbResponsabile);
// .....
// assignment
// persona is an element of array
cbResponsabile.setSelectedItem(persona);
I'm having this issue where I have dynamically generated values in hidden inputs like so:
<div id="items-div" class="selection-div">
<input name="selectedItem[0].articleName" id="selectedItem" type="hidden" value="cereal"></input>
<input name="selectedItem[0].quantity" id="selectedItem" type="hidden" value="2"></input>
<input name="selectedItem[1].articleName" id="selectedItem" type="hidden" value="yogurt"></input>
<input name="selectedItem[1].quantity" id="selectedItem" type="hidden" value="10"></input>
</div>
I append these to the items-div using jquery depending on what the user chooses on-screen, each of those is an Item.
public class Item {
private String articleName = "";
private int quantity = 0;
public String getArticleName() {
return articleName;
}
public void setArticleName(String articleName) {
this.articleName = articleName;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
And this is the form class which has an ArrayList of these items
public class CreateArticleForm extends ActionForm {
private ArrayList<Item> selectedList = new ArrayList<Item>();
public Item getSelectedItem(int index) {
if (selectedList == null) {
selectedList = new ArrayList<Item>();
}
while (index >= selectedList.size()) {
selectedList.add(new Item());
}
return (Item) selectedList.get(index);
}
public ArrayList<Item> getSelectedList() {
return selectedList;
}
public void setSelectedList(ArrayList<Item> selectedList) {
this.selectedList = selectedList;
}
}
And finally the action class
public class CreateArticleAction extends
Action {
public ActionForward executeAction(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response, User user)
throws Throwable {
CreateArticleForm articleForm = (CreateArticleForm) form;
//... do stuff
}
}
I would expect that on post all the server would round up all the selectedItem[X] and call the getSelectedItem to build up the arraylist and populate it then set the properties to each object but when I submit the page on debug, I see the selectedList arraylist comes up empty. I am using this logic based from a previous assignment where instead the information with indexed properties was instead generated when the page was first loaded and then printed with a logic:iterate tag and then each input had a indexed="true" property, but since in this case it is from what the user clicks on the page, I instead use jquery to fill out the "items-div" with what the user is choosing, but it should be the same no? Am I missing something? It ran previously just fine... Thank you for your time.
EDIT: The above works if I hard-code test hidden inputs in the jsp page, it submits those but not the ones dynamically created and appended with jquery.
$('.items-div').append($('<input/>').attr({
type : 'hidden', name: 'selectedItem['+index+'].articleName', id : 'selectedItem', value: objItem.articleName}));
I should've known since before, but apparently it's a security measure to only allow elements that had been originally rendered to be posted back, so the ones I hard-coded worked just fine, but any others appended -after- rendering won't be submitted so I will probably have to put the objects in an array of objects, JSONfiy them and send them as a string to the action class, using an existing hidden input.
I am using a simply city SuggestBox where I am getting list of cities from the database and putting them in GWT suggestBox oracle.
After that user can select his city from the suggestBox suggestions and user saves his record. For example, he will select "London" from the suggestbox list.
Now when user saves his record, I will not save "London" in the database for that user, instead I want to save "3" (london ID) in database.
For this what I am doing is like this:
public MultiWordSuggestOracle createCitiesOracle(ArrayList<City> cities){
for(int i=0; i<cities.size(); i++){
oracle.add(cities.get(i).getCity()+","+cities.get(i).getCityId());
}
return oracle;
}
Now, I have the city and cityID both displaying in suggestBox and then can save from there 'city' and 'cityId'.
Everything works fine, but it doesn't looks good:
like it dispays as "London,3" and so on in the suggestBox suggestions..
I don't want to show this 3, how and where can I save this Id(3) for future use?
You can also create your own typed Suggestion-Box. You need to implement "Suggestion" and extend "SuggestOracle".
Super simple version may look:
// CityOracle
public class CityOracle extends SuggestOracle {
Collection<CitySuggestion> collection;
public CityOracle(Collection<CitySuggestion> collection) {
this.collection = collection;
}
#Override
public void requestSuggestions(Request request, Callback callback) {
final Response response = new Response();
response.setSuggestions(collection);
callback.onSuggestionsReady(request, response);
}
}
//CitySuggestion
public class CitySuggestion implements Suggestion, Serializable, IsSerializable {
City value;
public CitySuggestion(City value) {
this.value = value;
}
#Override
public String getDisplayString() {
return value.getName();
}
#Override
public String getReplacementString() {
return value.getName();
}
public City getCity() {
return value;
}
}
// Usage in your code:
// list of cities - you may take it from the server
List<City> cities = new ArrayList<City>();
cities.add(new City(1l, "London"));
cities.add(new City(2l, "Berlin"));
cities.add(new City(3l, "Cracow"));
// revert cities into city-suggestions
Collection<CitySuggestion> citySuggestions = new ArrayList<CitySuggestion>();
for (City city : cities) {
citySuggestions.add(new CitySuggestion(city));
}
//initialize city-oracle
CityOracle oracle = new CityOracle(citySuggestions);
// create suggestbox providing city-oracle
SuggestBox citySuggest = new SuggestBox(oracle);
// now when selecting an element from the list, the CitySuggest object will be returned. This object contains not only a string value but also represents selected city
citySuggest.addSelectionHandler(new SelectionHandler<SuggestOracle.Suggestion>() {
#Override
public void onSelection(SelectionEvent<Suggestion> event) {
Suggestion selectedItem = event.getSelectedItem();
//cast returned suggestion
CitySuggestion selectedCitySuggestion = (CitySuggestion) selectedItem;
City city = selectedCitySuggestion.getCity();
Long id = city.getId();
}
});
Keep the reference from city name to id in a Map<String, Integer> and then look the ID up there before you save it.
I have a User object with two boolean fields:
//User Bean
public class Users {
private Boolean showContactData;
private Boolean showContactDataToContacts;
// Getters + Setters
}
I would like to show that as a RadioChoice in the UI using Apache Wicket.
Snippet from the HTML part:
<input type="radio" wicket:id="community_settings"/>
Java Form with radio in Wicket
public class UserForm extends Form<Users> {
public UserForm(String id, Users user) {
super(id, new CompoundPropertyModel<Users>(user));
RadioChoice rChoice = new RadioChoice<Long>("community_settings", choices, renderer);
add(rChoice );
}
}
My issue is now that I of course have no attribute community_settings in the Users Object.
I simply want to map those two boolean values to a radio choice in the UI.
How could I do that in Wicket?
Thanks!
Sebastian
You need a model to map the data:
RadioChoice<Long> rChoice = new RadioChoice<Long>("community_settings", new IModel<Long>() {
public Long getObject() {
if (user.getShowContactData() && user.getShowContactDataToContacts()) {
return 1L;
}
// ...
}
public void setObject(Long choice) {
if (choice == 1) {
user.setShowContactData(true);
user.setShowContactDataToContacts(true);
} else if (choice == 2) {
// ...
}
}
public void detach() {
}
}, choices);
BTW, personally I would use an Enum, so there's no special mapping at all. It seems like you are doing things a bit too "low level" and so the wicket model stuff will feel really cumbersome. Try to use objects instead of primitive types if it's appropriate.