aspose file tools*
The moose likes JSF and the fly likes updating product quantity with ajax Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Java » JSF
Bookmark "updating product quantity with ajax" Watch "updating product quantity with ajax" New topic
Author

updating product quantity with ajax

Thomas Maxwell
Greenhorn

Joined: Jan 01, 2013
Posts: 7
I'm trying to build a simple webshop application using JSF. On the cart.xhtml page I display all the items the user has put in his cart. The user can remove a product from the cart, no problem. The other feature I want this page to have is that the user can edit the amount for a specific product. When the page loads the user sees a row per product and each row has an inputText which holds the number of times the user wants that product. Seeing as this is an inputText the user can change this value and then press the "Update" button next to the inputText to change the amount.

I am unable to make this work. I don't understand how I can get the "new" value (so the new amount the user wants) to be passed to the backing bean. The only thing I am able to accomplish is that the amount that is in the inputText originally is passed to the backing bean.

This is the code that represents the column to update the amount:


The item object is just the var from the datatable. I bind the amount to view using the binding attribute but it only gives the original value, not the new one. How do I accomplish this?
Louis Bros
Ranch Hand

Joined: Jun 03, 2011
Posts: 54

Hey, do you need to tell the ajax tag what jsf component to execute?

If you don't specify an execute attribute on your ajax tag it'll default to @this, so your inputText might be missed.

You could try:



OCA7
Thomas Maxwell
Greenhorn

Joined: Jan 01, 2013
Posts: 7
I think by default it posts the whole form, which means the execute is @this. If I try it with @form then I get the error that item.amount is not a writable property, which is correct, but that's part of the problem I think. What I really want to do is bind the inputText to two properties (one for showing its old value and one for containing whatever new value is entered). I have no idea if this is possible but that's what I'm trying to accomplish (in whatever way is possible)
Louis Bros
Ranch Hand

Joined: Jun 03, 2011
Posts: 54

I think in this case '@this' is the commandButton since it's a child of the commandButton element, so if you want the inputText processed you'd need to use @form or the inputText's id.

Why is 'item.amount' kept read only? I've done something like this in the past where 'item.amount' is set and 'item' is passed to the bean method:

Thomas Maxwell
Greenhorn

Joined: Jan 01, 2013
Posts: 7
Yes, good question, I should have specified. The reason it's a read-only property is because this is a school assignment and the model (all the POJOs and DAOs etc.) were handed to us by the lecturer and we can't touch those. So I can't change that.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16140
    
  21

If your instructor is teaching you some of the crimes you are committing, then the only thing saving him/her from having me march up to him/her and breathing fire in said instructor's face is geography.

Rule #1 in JSF is that the more JSF-specific java code you create, the more likely you're doing things wrong, but Rule #2 is that if your View Template looks like a program, it's DEFINITELY wrong.

A JSF dataTable is paired with a JSF DataModel object (the one clear exception to rule #1 is that you should use JSF Model classes, where needed). If you do not code one explicitly, an anonymous one one will be automatically constructed for you.

The DataModel is used to maintain context while keeping JSF specifics out of the underlying data collection. Among other things, it contains a cursor that can be referenced by calling the model object's getRowData() or getRowIndex() methods. That's why anonymous auto-constructed models are not a good option for what you are doing. If you have created the DataModel yourself, then the action method editAmountForItem can get the row data for the selected row directly from the model. AND you won't have to code parameters on the View definition.


Customer surveys are for companies who didn't pay proper attention to begin with.
Thomas Maxwell
Greenhorn

Joined: Jan 01, 2013
Posts: 7
I think I understand your explanation, but even with a DataModel I won't be able to do what I want to do right? Seeing as the DataModel will be bound to the list of Products and thus by default the quantity that the product had initially (not the amount I have entered in the inputText).

I have added as attachment a screenshot of the page I'm talking about, just to make sure there are no misconceptions about the problem.

The 1s you see are the quantity before I came to the cart page, as you can see these are inputTexts and when I click the blue refresh button the CartItem object (i've been saying it's a Product object, but it's actually a CartItem) should get the value that the user entered in the inputText.


[Thumbnail for cartproblem.png]

Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16140
    
  21

I think you are making the common mistake that the datamodel must be bound directly to an ORM Domain Model object or collection. That is not so.

The DataModel is the JSF UI model. In simple cases, you can use it to wrap a collection of read-only objects, but the rows in the model can actually be any type of object you desire. It's not uncommon to make a row model object decorate or aggregate Domain model objects, and one of the classic cases of that is the Shopping Cart.

When you click the commandLink control, it fires off the standard JSF lifecycle, which involves validating the data being submitted, updating the model data - specifically the value(s) in the selected DataModel row - and then invokes the action method which can do what it wants, secure in the knowledge that the data is valid and up-to-date. The same basic rules apply regardless of whether this is done as an AJAX request or as a traditional whole-page request, with the only difference being how much data is transferred.

An excellent reference for this kind of stuff is Rick Hightower's multi-part series "JSF for NonBelievers" at IBM DeveloperWorks. It's quite old - written for JSF Version 1, but it's still valid even today.
Thomas Maxwell
Greenhorn

Joined: Jan 01, 2013
Posts: 7
You're right that I did not know that de DataModel did not have to be bound to the actual ORM data model. I'm trying to implement it as per your suggestion but I'm still having some difficulty. Here's what I have so far.

In my CartBean I have delcared:


When the datatable calls #{cartBean.items}, this is what I have done:


I loop over the CartItem objects, which have the readonly property for amount and I place them in cartItemsList, which is a list of CartItemDataModel objects, show below:


It adds all of the CartItems to this new list. Then I make a ListDataModel based off this list (now those rows should be able to update amount seeing as the objects are of type CartItemDataModel.

In the editAmountForItem I now have:


As you said, I don't have any parameters there anymore seeing as I can just pick up the selected datarow. Am I still misunderstanding your previous post or is this by and large what you had in mind? Unfortunately it's still not working though :-).
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16140
    
  21

It's simpler than that.

Create your collection of CartItems as an ordinary List, such as an ArrayList. Then wrap it:


You can alternatively create the ListDataModel with a no-argument constructor and bind your list to it using the setWrappedData(myCartItemsList) method.

There is no need to write your own "get" method for the row items. When using wrapped data, the DataModel's built-in accessor works just fine.
Thomas Maxwell
Greenhorn

Joined: Jan 01, 2013
Posts: 7
That's what I tried first, but the collection of CartItems contains CartItem objects which don't allow me to change the amount, so I still get the error that cartItem.amount is a non-writable property. I'm sorry for asking so many questions about this teeny tiny problem, I'm just new to JSF.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16140
    
  21

Sorry. Those little extra items are misleading me. JSF is designed to make things simple. People seem to hate simple, and they get in trouble because they make things complex.

You should not be attempting to create cartitems in the getItems() method. That adds side-effects to the "get" method, and a proper Javabean get method should avoid side-effects (the technical term is "idempotent"). This is especially important in JSF, since the "get" method can get invoked 4 or 5 times on a single request and every time you re-create the ListDataModel you lose the context that had been built in the previous instance. Construct the ListDataModel once, cache it, and return that same object for every "get" request. That will also cut down on needless (and in your case, harmful) overhead.

JSF is updating your model, but you're destroying the updated model before you can read it back as things stand right now.
Thomas Maxwell
Greenhorn

Joined: Jan 01, 2013
Posts: 7
Yup, I had a feeling that that could be a problem point as well. I've just isolated it to a different bean to test it and it works like a charm now. Thanks so much for your help Tim.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: updating product quantity with ajax