ADF using EL in Java code - jsf

I've got a main page that displays number of records, when I click on create, it should navigate to create form (another JSF), where on Submitting the new record, it should navigate back to main page and display all the records including the new one.
I've been able to achieve the navigation using navigation rules in adfc-config file. And I've created Action method (beans) that returns expected string used in navigation.
What challenge I'm facing now is on button click, I can invoke only one method (action), which has to return the expected string for navigation. Or I can use EL that does the refresh. So I'm either able to Refresh the page after creating a new record, or able to Navigate. Can't do both. (Usage of actionListener won't work, because actionListener works before action, my requirement needs sequential execution.
Is there a way I can use EL in my Java code? So that I can put it right after the record creation and before return string?
Some method that executes method specified by EL, where I just have to pass the EL as a string?
Update: Both Query (display) and Insert are API calls.

From what you're saying, you're using the Unbounded task flow adfc-config to build your navigation business logic. This is not right! The Unbounded task flow's primary purpose is to define the base structure of your site. For example, on your Homepage, if you have a link for "Create Department" and another one for "Add Employee", there would be only 2 simple navigation rules to link to those independent pages.
To achieve your goal, what you need is a Bounded task flow and a few page fragments. The picture below is an actual Bounded taskflow in one of the applications I worked on. Let's take it as an example.
The main feature of a Bounded task flow is that all fragments in the same task flow will share a common data control (i.e. all fragments will see the same set of data). As you can see from the picture above, my starting page is a Search page for Corporate cards, where I'll display all records based on what users search for.
On this Search page, I also have a Create button to allow users to create a new record, which would lead to the Details page (which is also the page to edit current records). Once users commit the transaction on the Details page, they will be redirected back to the Search page by following the viewCorporateCard navigation rule. Since both the Search page and the Details page share the same data control (the same iterator to be precise), users will automatically see the new record on top of the Search page when they're back here. You don't have to do anything manually to achieve this.
Hope this helps! :)

To pass EL value as string
this.setvalueToExpression("#{bindings.Orderno.inputValue}",
"sample");//pass string value
public void setvalueToExpression(String el, Object val) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ExpressionFactory expressionFactory =
facesContext.getApplication().getExpressionFactory();
ValueExpression exp =
expressionFactory.createValueExpression(elContext, el,
Object.class);
exp.setValue(elContext, val);
}

Related

ADF Refresh page jsf with page fragments jsff after set session variable

I have a template which includes a button that let you select a profile, you push the button and appear the available profiles, choose one and push accept. After that I set a variable session successfully.
I have a "First" jsf page with two jsff page fragments from a View Link. The view link is composed by a headerView and detailView. The headerView had a bind variable. What I need is that parameter (bindVariableParameter) can be set by the session variable of the template.
This is what I get:
I am in a home page (separate Application Module), I push the template button before I load de "First" jsf page and after that I go to the "First" jsf page the information is loaded successfully. What I do in the Application Module is something like that:
protected void prepareSession(Session session) {
Map sessionScope = ADFContext.getCurrent().getSessionScope();
String company = (String)sessionScope.get("compId");
System.out.println("Default Comapny in BC is: " + company);
super.prepareSession(session);
this.getSession().getUserData().put("Company", company);
System.out.println("After setting value in userData map of BC");
}
And in the bind variable expression of the headerView I use:
adf.userSession.userData.Company
It works great!!!! But!!!!
When I press the button again and I choose another profile, the info is not updated. Neither in the headerView neither in the detailView.
Also, when I go to the "First" jsf page (without previously push the template button), I got no info, which is right, because I don't have any session variable. After that I push the template button and select the profile, but the page is not refreshed.
I tried several ways to to this but I'm lost.
Could you help me?
Regards.
You have two options for this:
Option one: tune your AM as follows:
jbo.doconnectionpooling=true
jbo.txn.disconnect_level = 1
This will ensure prepareSession() method is being called before each operation. This happens to be a best practice in ADF productions systems, increasing scalability (see here )
Option two: Better than using prepareSession(), you can pass the Http Session data to ADF BC through a custom DataControlFactory.
You can find an example here: http://andrejusb.blogspot.co.uk/2012/05/solution-for-sharing-global-user-data.html

How to Refresh ADF jsf page components by pressing a button?

I have a fusion web application that contains an af:query panel (I created it query panel with table), and af:table and af:panelFormLayout that are related with each other. When I search an entry in the query panel results are shown both in table and in panelFormLayout. When I press reset button in the query panel, only the query panel is reset. I want to all the page to reset. How can I do that by using the easiness of ADF?
Basically you want to override the reset functionality of the af:query. In that case, you should:
1. Set the QueryListener property of the af:query to a managed bean method. You can refer to this example which describes all the steps required: Programmatically RESET query panel
Inside it, you'll see this call: AdfFacesContext.getCurrentInstance().addPartialTarget(t1);
It is responsible for the refresh of the table. Now, if you have all the content inside an af:panelGroupLayout for example (or any other payout type component), you can refresh it instead (so you need to bind it with a field on the bean and use it instead of t1 in this call. Otherwise, if you still wish the full page refresh, follow step 2.
2. Add the needed code to make the page refresh:
FacesContext context = FacesContext.getCurrentInstance();
String currentView = context.getViewRoot().getViewId();
ViewHandler vh = context.getApplication().getViewHandler();
UIViewRoot x = vh.createView(context, currentView);
x.setViewId(currentView);
context.setViewRoot(x);
Just put it inside the method described on the above link.

How to dynamically create an a4j:commandLink in a component renderer?

I'm trying to add some functionality to the rich:dataTable by extending its renderer. More specifically, i'd like to render a link in the header column that triggers an ajax call (to trigger an action in a backing bean).
So my fist thought was to modify the dataTable's renderer to instantiate and add an a4j:commandLink instance. That does work to some extend, the link does get rendered just fine, however the associated action is not being called, and an added parameter assignemnt is not performed. furthermore i cant really make out what portions of the view are being executed and rendered, it seems the values i set are being ignored (for example if i specify #all as a value for those two properties i still get a partial response containing just a tiny fraction of my page).
This is the code i use to create the link:
UICommandLink l = (UICommandLink) context.getApplication().createComponent(UICommandLink.COMPONENT_TYPE);
l.setTransient(false);
l.setRender("#all");
l.setExecute("#all");
l.setActionExpression(ULHelper.createMethodExpression("#{orderBy.toggle('"+ sortName + "')}", null, String.class);
l.setParent(uiColumn);
l.getChildren().add(headerFacet);
l.encodeAll(context);
uiColumn is the UIColumn instance, headerFacet is the text that should be rendered within the link.
The link does get displayed correctly, a click on the link triggers an ajax request just fine (no errors in the javascript console) - but i have no idea what happens next on the server side, the action is not getting called, the table is not being re-rendered either.
If i add an ActionListener
l.addActionListener(...);
or add a parameter instance to the link
UIParameter par = (UIParameter) context.getApplication().createComponent(UIParameter.COMPONENT_TYPE);
par.setValue(sortName);
par.setAssignToExpression(ULHelper.createValueExpression("#{bean.text}", String.class));
l.getChildren().add(par);
it makes no difference, neither of the two are executed.
I suspect it has something to do with state saving, that the a4j:commandLink does not get saved and therefore the 2nd request does not find that link (and therefore the listener, parameter etc...) to work with, but i have no idea how to persist (and restore) the state of the link.
Just sample from working sources, which may be helpful:
import org.ajax4jsf.component.html.HtmlAjaxCommandLink;
public UIComponent ajaxLink(...) {
HtmlAjaxCommandLink ajaxLink = new HtmlAjaxCommandLink();
ajaxLink.setId(...);
ajaxLink.setValue(...);
ajaxLink.setAjaxSingle(true);
ajaxLink.setOncomplete(...some js func..);
ajaxLink.setReRender(...);
FacesContext context = FacesContext.getCurrentInstance();
MethodExpression actionListenerExpression = context.getApplication().getExpressionFactory().createMethodExpression(context.getELContext(), "#{someSeamComponent.someAction}", null, new Class[]{ActionEvent.class});
MethodExpressionActionListener actionListener = new MethodExpressionActionListener(actionListenerExpression);
ajaxLink.addActionListener(actionListener);
return ajaxLink;
}
uiComponent.getChildren().add(ajaxLink(...));

Maintaining state between pages in seam

I have a xhtml page with Search criteria and search results. Clicking on search button will dynamically update the results on the same page. I have a controller for search/results xhtml in Page Scope.
There is an edit button in every record in the search results. Clicking on the edit button will open a new page(new controller in Page scope). Once I edit and save I want to come back to the search criteria page with search resutls.
I can store the search criteria in session and requery and display the results. I looked at conversation and I am not sure if I can use it in this scenario?
Any ideas other than dumping the data in session for this scenario?
Pass the search criteria to the edit view as well (but don't display them or something) and then let the edit view pass it back to the search view once editing is finished.
If you want to persist data between two pages, you have many ways:
1) String parameters
2) Session data
3) Long running Conversation
4) Serialize your data elsewhere (DB or other).
Since you are talking about "saving" I may think you are saving your data in a database. If you have persisted your data in the second page in some way you can just query for them.
Otherwise you can use session and conversation, the second has a "smaller" and defined scope. You can decide when to create one and to create destroy. Simply put a in the first page pages.xml and create a bean with conversation scope.
The session scope will keep your data in your session scoped component until you close your browser.
Hope this helps.
I would go with the session scoped bean. If you use a search bean you can go anywhere in your application and maintain your search state, also it lends itself to saving searches in the database (so users can save searches between sessions).
#Scope(ScopeType.SESSION)
#Name("someRandomSearch")
public class SomeRandomSearch {
private SearchObj1 userSelection1;
private List<SearchObj1> searchCriteriaList1;
private SearchObj2 userSelection2;
private List<SearchObj2> searchCriteriaList2;
private String randomUserInput;
// getters/setters, some helper classes, cascade dropdown stuff, etc.....
// clear search criteria
public void reset(){
this.userSelection1 = null;
this.userSelection2 = null;
this.randomUserInput = null;
}
}
Just make sure to implement equals method in your model classes - maybe that's obvious, but when I first started using Seam I missed this little tidbit and it took forever to figure out why we couldn't hold onto dropdown selections in our search pages.
If when you say "open a new page", you mean navigate to another page in the same browser window/tab, then a Conversation is the ideal method for storing the search state.
Depending on your detailed use case, you might prefer to setup nested conversations (when you click on the edit).
You might also want to setup a pageflow to manage that particular navigation logic.
See the official documentation.

how to distinguish a jsf action or direct url link invoked the page

I have a situation, I have a session bean with list, this list I show in html data table. When the user hits the url from browser or normal href, I have to show all records. There is provision to search for the data also, where I have to show the filtered list. Now after a user has made the search, the list contains filtered records and after doing this he leaves the page to some other, and now if the user hits the url or uses the menu to come back to this page, since I have this list in session bean, I still have the filtered list.
Since there is no default action in JSF 1.1 or 2.0 preRenderView concept, its difficult to clear the list and get non filtered data(all results) again. Even tricks in getList() method fail to accomplish the task.
I have planned to use phase listener, as when a user reaches a page via href or url hit in browser, invoke application phase does not happen. I can toggle boolean variable in my session bean and in getList() I can perform some trick to check it was url,href hit or by command button.
Hope I have made myself clear. In short I have to identify in my bean whether the request came directly from href,browser or an action. If search action filter records for data table if not keep list cache and keep showing it as long as search is not made.
Just guide me whether I am doing things in right way or thinking too much or can it be done in much more efficient way.
Thanks in advance.
Well platform is jsf 1.1 in weblogic portal 10.3 .....
JSF 1.x actions use by default POST method. Direct links/bookmarks/etc are by nature GET method. Since there's no ResponseStateManager#isPostback() or FacesContext#isPostback() in JSF 1.1, you have to determine the request method yourself:
HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
boolean postback = "POST".equalsIgnoreCase(request.getMethod());
Or check for a certain parameter in the request parameter map, but I can't tell from top of head which one you'd like to check. You've to determine it yourself.
boolean postback = facesContext.getExternalContext().getRequestParameterMap().containsKey(SOME_KEY);
If postback is true, then a JSF action is been invoked.

Resources