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.
Related
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);
}
I am writing an app in which the end user can mark documents as his favourites. I already have the necessary forms and views to save and read back the favorites, but I have one little problem: all is done in the back end (the favorites are displayed from a view, not a scoped variable) and there seems to be a sync issue between the click on the "add to favorites" link and the partial refresh that reloads the favorites: the newly added document only shows after a second refresh. No problem then, I then decided to move the favorites in a managed bean I already have for the session where I keep the language and other user's prefs.
The problem I now face is this: how can I trap the login event so I can build the favorites list in the bean? I looked at how the "xInvolve" control's favorite piece was built and I found that there is some code added to the custom control's beforePageLoad event. But I'm wandering if there's a better way of doing this. If I go that way, this means that each time a page loads, it will go in my session bean to look if it needs to build the favorites list. I feel it's a bit of an overload: I'd rather build the list once, when the user logs in.
Is that possible or I should keep the beforePageLoad code just as it is now? Any ideas/thoughts are appreciated.
Note this does NOT actually trap the login.. I'm not sure how to do that exactly but I'm not sure it's nexessary..
Just thinking out loud here.. but I would try this..
Assume you have a "UserObject" to hold the favorites for the user.. then the object gets loaded it reads them in etc...
What about an "App Bean".. a managed bean in app scope... basically a factory for your application... inside the AppBean you have a Map... so that's an easy way to get a hold of the userobject anytime and it lives throughout the app scope...
Now on each page.. you try to grab the UserObject... if it doesn't exist.. you load it once into the App Bean so it's there for later... if it exists.. it's already loaded... you then update the UserObject when the user adds/removes a favorite... make sure to go through the object in the app bean to keep it updated...
An advantage of this is if the user opens another browser or tab.. it all pulls from the AppBean...
Give that some thought and let me know if you need any help...
Also note: This is a java solution... it might be workable in SSJS though..
A standard login page is HTTP only, not XPages. HTTP identifies that a login is required, validates credentials, checks the URL that you're redirecting to exists and only then does the XPages runtime take over.
If you want to trap login, you need to have an XPage making an AJAX request to do the login.
You might want to have a look at XPages Help Application on OpenNTF. I built a favouriting function into that. Favourites are stored in the person's profile, but for the duration of the session held in memory in a Map. The person's profile is created with the hashed value of the username. There is a potential issue with renames, but that's not a significant issue.
You could use a SessionListener. In the sessionCreated method you can calculate the List and initialize your session scoped bean:
public class MySessionListener implements SessionListener {
public void sessionCreated(ApplicationEx arg0, HttpSessionEvent event) {
FavBean bean = new FavBean();
// create the favorites List
// and push it to your bean
// add the bean to session scope
event.getSession().setAttribute("favBean", bean);
}
public void sessionDestroyed(ApplicationEx arg0, HttpSessionEvent event) {}
}
I have a tabbed panel containing different sections of a form. In one section, users are given the ability to add a child document to the currently open document. In a second section, they are given a listbox, where the options are dynamically generated (via #DbLookup) by looking at a view of all the child documents, filtered by the current document's ID. This functionality all works correctly, however, there is a problem with the dynamic listbox options.
When a user adds a new child document, then switches to the next tab, the listbox is not updated with this new document. If they save/re-edit the main document or refresh the page, it makes no different, the user must load another XPage before going back to the original in order for the listbox to update. I have tried to resolve this by doing full updates of the page, using session.evaluate and "NoCache" in the #DBLookup call, or calling database.getView("My view").refresh(), but without luck.
There is also a similar problem where I have a repeat control which uses a view of child documents (again filtered by main document ID) as a datasource. When a user adds a child document using a button, it partially refreshes the repeat - but doesn't show the new child document until the page is refreshed again (or you leave the page and return).
Is there something crucial I am missing with regards to the JSF lifecycle/the way that view data is cached?
As first measure I would add another formula item to the listbox which simply returns the current time (#Now() should work). That way you can check if the listbox options are refreshed on the update in the first place.
If the options are refreshed fine it's indeed clear that the #DbLookup does some caching, although I'm not aware of any default caching logic.
At least for a test I would change the code to use a NotesView object instead of the #DbLookup, something like this:
var nview = database.getView("someview");
var nc = nview.getAllEntriesByKey(currentDocument.getDocument().getUniversalID(), true);
var a = [];
var ve = nc.getFirstEntry();
while (ve) {
a.push(ve.getColumnValues().elementAt(0)); // value of first column
ve = nc.getNextEntry(ve);
}
return a;
(I wrote the code from memory, there may be syntax errors).
Since the code only works with view entries it should be equally fast than the #DbLookup. And you could even do a nview.refresh() if needed.
I have an Xpages application that pulls data from another .nsf file. I have a view panel linked to a view in that db. The view has documents with several different forms in it. I want to be able to open each document in it's own form(xpage).
How do I write a computed At Runtime, open selected document using: statement that will select the correct Xpage to present the document.
If you use the Data View component instead of a View Panel, you can compute the pageName attribute, referencing the var attribute to return a different value for each row based on the document that row represents. The flexibility of the Data View component also makes it easier to make your app look more like a modern web application and less like an Excel spreadsheet. As an additional bonus, the mobile theme invokes a renderer that makes each Data View instance look like a native mobile list, so using Data Views instead of View Panels simplifies mobile development.
You have 2 options:
use "use xpage associated with form" and edit the form's property
use a SSJS formula to compute the Form. You provide a variable name in the view control var to access a view row as XSPViewEntry. If the Form is in a view column even one you don't display you use .getColumnValue otherwise getDocument.getItemValueString
Does that work for you?
Maybe this mothed can help you: Unable to get document page name for
Hope this helps
Mark
I had a similar problem today. I use only one form but 3 different xpages for associated with this form. I have 3 different document types in the view. I used rowData the get the type of the document.
try{
var v=rowData.getColumnValue("form");
if(v.indexOf("x")> -1){var page ="x.xsp"}
else if(v.indexOf("y") > -1){var page = "y.xsp"}
else{var page = "z.xsp"}
}catch(e){
var page = "x.xsp"
}
So to your view you can create a column with the value of the form and you can use it.
I have used the extension library Dynamic View control which has an event you can code to get a handle to the NotesViewEntry which was selected. See the demo database page Domino_DynamicView.xsp and the Custom Event Handler tab for an example.
Note, in 8.5.3 (I have not upgraded yet) if you add or edit the eventHandler for onColumnClick it will be added to the XPages source as an xe:eventHandler. It needs to be an xp:eventHandler to work. The way to do it is to copy the code in the source from the exiting event and delete it. Recreate the event and update the code. Then go back into the source and change the tags within the eventHandler to xp:.
On a page I have some fields that I want to be "readonly" (in my meaning they can't be accessed but they will store values, read earlier question in this matter if issues...).
I use a client JS setting these attributes on page load:
$(".readonly").attr('readonly', true);
If I have a partial update on any of these fields the attribute is lost and the field is accessible.
What is the best practice to overcome this and make it work?
Every partial refresh has a oncomplete method bound to it. What you could do is add code to the oncomplete method so the item is being set readonly again. Another, better, approach would be not to change the attribute clientside but to have hidden fields which are used to store the data.
When you have an event bound to for instance an Link control you can change the oncomplete code by clicking in your source pane on the event tag. When you browse the events section in the properties pane you will see the onComplete, onError, onStart properties. You can add your own clientside script in these properties.
Before trying to overcome the "problem" You shoud try to understand what exactly partial refresh do and where the state of application is kept.
Unfortunately partial refresh is replacing current html content (or rather part of it) with a newly created one and only form fields that has backing controls will keep state.
I suggest You should try setting readonly property on controls which You would like to make readonly (if there is some logic here You can always use ssjs).
Optionally You can try to preserve the state on the client side by using csjs global variables but this is rather hard to manage.
And one more thing - try to use the technology to solve the problem(xpages) and try not to hack Your way through with use of stuff that You accidentally know (jquery).
I would agree with jjtbsomhorst on using onComplete event. But another alternative could be setting the readonly property via code like this:
var textField:com.ibm.xsp.component.xp.XspInputText = getComponent("inputText1");
var readOnlyAttr:com.ibm.xsp.complex.Attr = new com.ibm.xsp.complex.Attr("readonly", "readonly");
var list:java.util.ArrayList = new java.util.ArrayList();
list.add(readOnlyAttr);
textField.setAttrs(list);
You could call this on the afterPageLoad event of the XPage. But I really don't know whether this would be the best way to about!