ZK - Accessing GUI elements from ItemRenderer - java

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.

Related

Issue with posting arraylist with indexed properties from jsp to action class

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.

Shopping Cart page displays only one item

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.

Apache wicket breadcrumb on one page

I would like to create breadcrump on my page, but I am unable to do it by following wicket examples.. I need to extend BreadCrumbPanel when I also need to extend WebPage..
I want breadcrumb to be visible only on this specific page, after clicking some of links on the page(they call setresponsepage with some parameters) I would like to append my breadcrumb
public final class GroupMainPage extends WebPage {
// Map<String, Group> hostGroup = PropertiesLoader.getInstance().getHostGroupMap();
List<Group> hostGroup = PropertiesLoader.getInstance().getHostGroupList();
public GroupMainPage() {
super();
HostGroupManager.getInstance();
createMainTable(hostGroup);
add(new Label("message", "OK \n ok"));
}
then I have some methods which help me create table on my page, especially this one with links where I would like to append my breadcrumb:
ListView<Component> list = new ListView<Component>("groupListElement", ((Group) component).getDependentGroups()) {
#Override
protected void populateItem(ListItem<Component> item) {
final Component c = item.getModelObject();
Link link = new Link("groupLink") {
#Override
public void onClick() {
Group g = (Group) c;
if (g.getDependentGroups() != null && g.getDependentGroups().size() > 0) {
setResponsePage(new GroupMainPage(g.getDependentGroups()));
} else {
setResponsePage(new GroupServiceListPage(g.createServicesList()));
}
}
};
link.add(new Label("linkLabel", c.getName()));
item.add(link);
How to make it possible?

map two boolean fields of an IModel to a RadioChoice in Wicket

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.

How to add addGlobalEventListener in a class in blackberry?

I have made a multiple entry-point project, where App2 is set to autorun and App1 runs on user request.
I am trying to invoke a global event from App1, received by App2.
public class App2 implements GlobalEventListener {
static public int counter = 0;
public static final long countId = 0x1251402f595f81a5L;
public static final long eventId = 0xba4b84944bb7429eL;
private App2() {
Application.getApplication().addGlobalEventListener(this);
}
public static App2 waitForSingleton() {
counter = 2; // Added the counter in Runtime store in a similar way as
// added in eventOccured method
// Deleted some unuseful code
}
public void eventOccurred(long guid, int data0, int data1, Object object0,
Object object1) {
if (guid == eventId) {
callMethodOnOccuranceOfEvent();
}
}
public void callMethodOnOccuranceOfEvent() {
counter++;
RuntimeStore store = RuntimeStore.getRuntimeStore();
Object obj = store.get(countId);
if (obj == null) {
store.put(countId, new Integer(counter));
} else {
store.put(countId, new Integer(counter));
}
}
}
Then in other class I tried like
public class App1 extends MainScreen {
public App1() {
}
protected void makeMenu(Menu menu, int instance) {
super.makeMenu(menu, instance);
menu.add(new MenuItem("Call", 20, 10) {
public void run() {
callMethodonclick();
}
});
}
public void callMethodonclick() {
ApplicationManager.getApplicationManager().postGlobalEvent(App2.eventId);
RuntimeStore store = RuntimeStore.getRuntimeStore();
Integer c = (Integer) store.get(App2.countId);
add(new RichTextField("Event Recived#counter#" + c));
}
}
If I invoke the event for three times
Event Recived#counter#2
Event Recived#counter#2
Event Recived#counter#2
while the Expected result is
Event Recived#counter#3
Event Recived#counter#4
Event Recived#counter#5
which I guess suggests that object for App2 in not null but eventOccurred never invoked.
the output clearly suggests that callMethodonclick is not able to post Global event,even though globalEventListener was added in constructor.
Must be like this.
if (obj == null) {
store.put(countId, new Integer(counter));
} else {
store.replace(countId, new Integer(counter));
}
store.put() throw an IllegalArgumentException, because there is something in a store(see API Reference), but this Exception is handled by some system thread, that invokes eventOccured() method and show nothing about this Exception. It is one of the various Blackberry bug.
You are not updating the text in the RichTextField. It only gets added to the screen when there is no runtimestorage object associated with App2.RTSID_MY_APP.
Your code needs to keep a handle on the RichTextField by putting it into a field of the App1 object. Then update the text in the run() method.
I edited your code, adding braces to the if statement, which makes this more clear.

Categories

Resources