• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Tim Cooke
  • Junilu Lacar
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
  • Knute Snortum
Saloon Keepers:
  • Ron McLeod
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Frits Walraven
Bartenders:
  • Carey Brown
  • salvin francis
  • Claude Moore

Trying to capture data from p:autoComplete into backing bean - or possibly pass object?  RSS feed

 
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi all,

Very much new to JSF and trying to figure out the "JSF way of doing things".  I have what I believe to be a fairly simple issue.

First off, my set up:


* WildFly 8.1.0.Final "Kenny"
* Mojarra 2.2.6-jbossorg-4
* PrimeFaces 6.1
* PrimeFaces Extensions 6.1


I'm simply trying to pass data from an XHTML (JSF) page, to the backing bean/view. I have a p:autoComplete that looks like this:

class_request_system.xhtml



And then on the backing bean/view, I'd like to not only get the value of the autoComplete, which ends up being the title of course, but every single property listed above - course.code, course.title, course.type, etc. Everything I've read thus far talks about using the value to associate the value with the backing bean, however, the value is 'preoccupied' with the #{enrollmentView.courseList}.  So I've looked at using "var" and "itemValue" but I'm not sure that's the right path either.

Here's where I'm trying to get the above data:


TrainingAlterView.java


But then it gets even more confusing, since later on in that method, there's a huge switch statement that depends on methods that are usually in a typical LearningObject variable which are associated with getitng information about the course but also getting information about the person taking the course:




I don't understand how to pass the values between pages but, even more so, creating that object again which will have all of the methods that it will need to perform this approval logic that works elsewhere in the application for a removeTrainingRequest since it's tapping into an already existing LearningObject, not creating one from scratch. Maybe there's a way to pass an Object between pages - like the entire "course" object above? - that would be ideal.


I would greatly appreciate any help.  Any tutorial or stackoverflow I read inevitably isn't the exact same situation I'm in and typically isn't too applicable. Thanks in advance.
 
Ranch Hand
Posts: 91
Java Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Fred,

Did you try the "Primefaces Showcase" for info? https://www.primefaces.org/showcase/

It might have what you need.
 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Mano Ag wrote:Hi Fred,

Did you try the "Primefaces Showcase" for info? https://www.primefaces.org/showcase/

It might have what you need.



Hi Mano,

Thanks.  I have looked at that documentation - unfortunately it's not up to date - on their p:autoComplete page, they are using deprecated features such as "@ManagedBean".

Do you have any idea how to do what I'm describing? Frankly, I don't think it should be too difficult.
 
Saloon Keeper
Posts: 20635
122
Android Eclipse IDE Java Linux Redhat Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Welcome the the JavaRanch, Fred!

I'm not familiar enough with PrimeFaces AutoComplete, but I have some suspicions just based on how people who don't know JSF do terrible things with JSF.

As a rule, you don't shove data back and forth between the backing bean and the web page en masse. JSF is a true Model/View/Controller architecture and the web page is the View. So the only actual data that the View should post back to the Model (backing bean) is stuff that has been changed. The only case where whole objects are likely to be serialized is when you have a 2-column selection control where you're shuttling stuff between Column A and Column B and vice versa.

Most of the time, all you need when working with a table View element is to know what row of the table has had a button or link clicked on. And JSF can determine that without any special tags or logic on the View Template (xhtml) as long as you wrap the datatable's value list with a JSF DataModel in the backing bean.

In the case of a simple text input box with autocomplete, usually what the autocomplete tag does is post changes to what the user typed back to an autocomplete listener method in the backing bean using AJAX, and that listener would return an updated suggestion list. I'm not sure if that applies here, but once again, complete objects are not transferred in that case, just ordered collections of strings.

 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Tim.  I've no doubt I'm not doing things per "best practices".  In fact I'm not too up to speed on proper MVC architecture, which is likely part of the problem.

complete objects are not transferred in that case, just ordered collections of strings.



That sounds reasonable.  Again I'm just not sure how to pass in all of these property strings into this method when I click the command button:



I'm going to need to pass all (or at least some of these properties) to the trainingAlterView:



What is the most straightforward way to approach this?
 
Tim Holloway
Saloon Keeper
Posts: 20635
122
Android Eclipse IDE Java Linux Redhat Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
By not doing it.

The information is already on the server. It was used to generate the displayed web page, but it remains on the server. All that the server needs to know is which row's data you want to work with, and, as I said, using a JSF DataModel to wrap your courseList will make that automatic.

Also, this is not proper:


It should be:


The action value is a reference to the action method. It isn't supposed to call the action method, it's supposed to let JSF what action method to call.

If you wrap your courseList with a DataModel like so:



Then the action method can tell what row you want:


And note that we're not actually having to copy data, we go straight to the original and get a reference to it!
 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tim,

Thanks again.  This helps.  I feel like I'm getting closer. I believe I implemented what you suggested and it compiled fine, but when it comes time to submit the form, all of the values were NULL.

For the DataModel method, I did this:



And then in the addTrainingReques method:



I still don't fully understand how it "knows" what p:autoComplete item (course) they picked based on this code, but I'll take your word for it that the MVC has it all figured out.  However, this didn't work.

What I did above is basically first use this DataModel suggestetion to get the CornerstoneCourse object and then get the LearningObject I need by using a method that was already written to search by ENumber (unique course IDs). This all compiles fine and I was excited to see it work, but running in debug mode and setting breakpoints in Eclipse it seems everything is null.  Any other ideas or do you need anymore detail from me?

 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Also, I used getRowData() since getCurrentRow() didn't seem to exist, per the documentation: https://docs.oracle.com/javaee/6/api/javax/faces/model/ListDataModel.html
 
Tim Holloway
Saloon Keeper
Posts: 20635
122
Android Eclipse IDE Java Linux Redhat Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm sorry. I always forget the proper method name. It is, indeed, getRowData().

Do NOT use "new" to construct a new DataModel on the DataModel "get" method. The DataModel contains state information and must be stored in an object with at least View or Session scope (NOT Request scope - request scope is almost useless in JSF). Create the DataModel and make it a property of the backing bean and return that same DataModel always. The only time you'd change or delete it is if you changed the data that it wraps. And even then you can simply update it using its setWrappedData() method.

You do not have to change the DataModel if the wrapped object (list, in this instance) changes. Changes to the contents of the list are automatically seen by JSF, both value changes and additions/deletions/replacements of rows.

The one question I've had all along was what the autocomplete control was doing. No, a DataModel cannot help if your autocomplete is a text entry control. But normally the value of that control would be used as a lookup value in the data set - for example, a database key value. So you'd get the rest of the data by searching your table for a match on that lookup value. Again, no need to push details back from the View to the Model, because the original data is already in (or at least can be located by) the Model. You only need to provide a key for it.
 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks again Tim.  


The p:autoComplete I believe does return a string, so how would you approach this in that case? Here's the documentation: https://www.primefaces.org/showcase/ui/input/autoComplete.xhtml

If I can just extract the ENumber property I can use a method I already have to do a db lookup with it.

I'm trying not to get  frustrated but this is far more complex that I would have imagined it to be. Your help is greatly appreciated.
 
Tim Holloway
Saloon Keeper
Posts: 20635
122
Android Eclipse IDE Java Linux Redhat Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hmmmm.

If you're trying to make it so that people can select a course by typing its name, I hope they type better than I do. But in such a case, I'd probably create a Map object in the backing bean where the key was the course name and the value was the course ID and look it up that way.

More likely, though when there's a table listing the courses, I'd just add a "Register" button to the table (or make the course name a commandLink) and skip the auto-complete entirely.
 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The autoComplete actually helps since it forces you to pick values it returns from the database.  You can't edit the value after you click on a selection that autoComplete suggests.  It's actually pretty slick.  Anyway, I am not feeling too good about this project. I'm going to try tinkering a bit more.   I just seriously don't understand why it is so complex so pass a value around.


 
Mano Ag
Ranch Hand
Posts: 91
Java Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,

I think it should not be that difficult.

It may be the simplest question but, do you have a property to connect your view to ?
Once you have that the rest should be easy.

Do you have an explicit or inherited "course"  property in your backing bean?

(by backing bean I mean POJO or Managed Bean or whatever people chooses to call it...
by property I mean a private variable with  its corresponding getter/setter in a class that
uses the @Named and possibly the @ManagedBean and @Serializable annotations)
 
Tim Holloway
Saloon Keeper
Posts: 20635
122
Android Eclipse IDE Java Linux Redhat Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, I admit I have trouble envisioning just what you're trying to present. It appears to be a course catalog with detail lines about courses. But why that would require an auto-complete escapes me. Most catalogs sub-divide their course offerings into departments, programs, or other sorts of categories and usually those divisions are granular enough that you can display them all in a single window and simply click-to-pick.

On the other hand, if you're expecting people to type in free text and display matching options from all over, then the only point I could see for the table - unless that's a table of courses already selected - would be to show details of potential matches. And that would mean AJAX updates of the table's data collection display, which could potentially be pretty slow.

The idea of shoving all the details back and forth between client and server goes against the grain for several reasons. One, it's extra overhead, since, as I have said, the server already knows the details, it just needs to know which set of details to work with. And two, the more information you trust coming back from the client, the more opportunities you give to unscrupulous people to hack that data and potentially do Bad Things with it.

The PrimeFaces autoComplete does seem to learn towards shipping objects over object keys, and that's unfortunate. Compare that to the JSF SelectOneMenu and related controls, where a JSF SelectItem allows pairing a friendly label with a data key value. But even allowing for that, I'd still try and minimize the bulk data transfers. Again, if you can obtain the record's key, the rest can be looked up.
 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Mano Ag wrote:Hi,

I think it should not be that difficult.

It may be the simplest question but, do you have a property to connect your view to ?
Once you have that the rest should be easy.

Do you have an explicit or inherited "course"  property in your backing bean?

(by backing bean I mean POJO or Managed Bean or whatever people chooses to call it...
by property I mean a private variable with  its corresponding getter/setter in a class that
uses the @Named and possibly the @ManagedBean and @Serializable annotations)



I don't have that. I guess I'm just not sure how to correctly set it up.
 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tim Holloway wrote:Well, I admit I have trouble envisioning just what you're trying to present. It appears to be a course catalog with detail lines about courses. But why that would require an auto-complete escapes me. Most catalogs sub-divide their course offerings into departments, programs, or other sorts of categories and usually those divisions are granular enough that you can display them all in a single window and simply click-to-pick.



It is so managers at my company can sign up their employees for internal courses.  Once selected from the list, they can add that into a "class request" database.  The autocomplete makes it easy to quickly type in a course and find it in the catalog.

So let's say I added a "course" property in my backing bean.  I don't get how to associate/connect that in the View/frontend...
 
Tim Holloway
Saloon Keeper
Posts: 20635
122
Android Eclipse IDE Java Linux Redhat Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What's the difference between "select from list" and "find in catalog"? Is the list not taken from the catalog?
 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Mano Ag wrote:Hi,

I think it should not be that difficult.

It may be the simplest question but, do you have a property to connect your view to ?
Once you have that the rest should be easy.

Do you have an explicit or inherited "course"  property in your backing bean?

(by backing bean I mean POJO or Managed Bean or whatever people chooses to call it...
by property I mean a private variable with  its corresponding getter/setter in a class that
uses the @Named and possibly the @ManagedBean and @Serializable annotations)



So here's the thing.  I'm wondering if "itemValue" is the missing link here. My code:



The issue is, the class that needs to access that value is trainingAlterView, not enrollmentView.  And it needs to be whatever they selected, with all information intact (a CornerstoneCourse object). I was thinking of doing something like adding a "course" property in trainingAlterView and the appropriate getters/setters, and then doing



But that didn't seem to work.  I know I'm missing some fundamental JSF "thing" and it just isn't clicking for me. Any input?
 
Tim Holloway
Saloon Keeper
Posts: 20635
122
Android Eclipse IDE Java Linux Redhat Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think one of the problems here is that neither "trainingAlterView" nor "enrollmentView" are actually Views. The naming that the Primefaces examples used was pure sloppiness. And while I'm ranting - here's looking at you NetBeans: backing beans aren't Controllers, either!

A backing bean is a Model. In JSF, the xhtml is a View Template, used by the JSF renderer to construct the actual View (html) for the client. You don't write Controllers at all - they're all pre-supplied as part of JSF and its tag libraries (including PrimeFaces).

It is perfectly proper in JSF for a View Template to reference more than one Model (backing bean). And, for that matter, it is perfectly proper to inject one backing bean as a Managed Property into another backing bean. The only restrictions there are that you observe the scope of the objects in question. If you construct a bean in View Scope, for example, moving to a different View causes that bean to be destroyed. You cannot injected narrower scope objects into broader scoped objects. For example, injecting a Session Scope bean into a Request Scope bean is OK (although, as I say often, Request Scope Is Almost Useless), but the reverse - injecting a Request Scope Bean into a Session Scope bean is not.

So an action method in trainingView could talk to an enrollmentView bean directly, as long as the enrollmentView has been injected as a Managed Property into the trainingView.
 
Fred Maurice
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tim Holloway wrote:I think one of the problems here is that neither "trainingAlterView" nor "enrollmentView" are actually Views. The naming that the Primefaces examples used was pure sloppiness. And while I'm ranting - here's looking at you NetBeans: backing beans aren't Controllers, either!

A backing bean is a Model. In JSF, the xhtml is a View Template, used by the JSF renderer to construct the actual View (html) for the client. You don't write Controllers at all - they're all pre-supplied as part of JSF and its tag libraries (including PrimeFaces).

It is perfectly proper in JSF for a View Template to reference more than one Model (backing bean). And, for that matter, it is perfectly proper to inject one backing bean as a Managed Property into another backing bean. The only restrictions there are that you observe the scope of the objects in question. If you construct a bean in View Scope, for example, moving to a different View causes that bean to be destroyed. You cannot injected narrower scope objects into broader scoped objects. For example, injecting a Session Scope bean into a Request Scope bean is OK (although, as I say often, Request Scope Is Almost Useless), but the reverse - injecting a Request Scope Bean into a Session Scope bean is not.

So an action method in trainingView could talk to an enrollmentView bean directly, as long as the enrollmentView has been injected as a Managed Property into the trainingView.



I thought ManagedProperty was deprecated? See https://stackoverflow.com/a/4347707/6168454

I'm just so damn confused. Even if I correctly got the EnrollmentView to talk to the trainingAlterView, how would I alter the XHTML/view to reflect it?

 
Tim Holloway
Saloon Keeper
Posts: 20635
122
Android Eclipse IDE Java Linux Redhat Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, ManagedPropery is the precursor to @Inject, so it's still there, just a different annotation.
 
Mano Ag
Ranch Hand
Posts: 91
Java Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Hello Fred,

I'll try to explain how the view and the backing bean connect in
order to access a property.

If the basics in this post are too basic please mark that as my fault.

The View

An xhtml file is your view. In it you have JSTL (JavaServer Tag
Library) components (from JSP JavaServer Pages), JSF components
(JavaServer Faces) and possibly components from some UI framework
such as PrimeFaces. You can have HTML and CSS as well.

The Backing Bean

a)

Contains the @Named annotation as well as a scope annotation
(if the scope is session, application or conversation then the
class must also implement the Serializable interface). Such a
class is capable of handling CDI (Context and Depencency Injection).
A class with these characteristics is registered as a resource
with the JSF implementation.

b)

Defines the properties and methods that are associated to the
components displayed in one or more views.

A property in this context can be:

- A variable declared in the class as private along with its
 corresponding public getter and setter. Default values can
 be defined in the class constructor

- A property inherited into this class from a parent class

- (If I am not very much mistaken) A property @Inject-ed
 into this class

The Connection

This is where the magic happens. The view and the backing bean
connect when a component attribute accesses a property or method
by means of the EL (Expression Language).

So if you have:

<h:outputText value="#{course.code}"  />

You'd be accessing the code property in the course class
(via the getter)

In the case of:

<h:inputText value="#{course.name}"  />

You'd be accessing the name property in the course class
(via the setter)

This allows you to manipulate course.code and code.name
inside any method in your backing bean.

And that's all there is, with the caveat that attribute names
are misleading as to what they do depending on which component
they appear (yikes!).

Suggested Reading

https://docs.oracle.com/javaee/7/tutorial/

Learning Suggestion

If you have your database schema defined, you can generate the
"CRUD" for your application and check the code.







 
Tim Holloway
Saloon Keeper
Posts: 20635
122
Android Eclipse IDE Java Linux Redhat Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Fred Maurice wrote:
Thanks.  I have looked at that documentation - unfortunately it's not up to date - on their p:autoComplete page, they are using deprecated features such as "@ManagedBean".

Do you have any idea how to do what I'm describing? Frankly, I don't think it should be too difficult.



As far as I know, Fred, @ManagedBean and @ManagedProperty still work. It's deprecated, not removed. But the @Inject annotation is similar. CDI (JSR-330) was actually defined because so many different frameworks were doing the same thing, each with their own mechanisms. so a "universal" set of annotations was created.

Also, don't try using JSTL on JSF View Templates. Although Oracle does show examples, JSTL was designed for JSPs, and JSPs render into Java code. xhtml (View Definition Language) renders into a data structure, not executable code, so JSTL has no guaranteed of operating reliably and has been known to fail in cryptic ways.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!