I have a three step wizard. On the first step I use a repeater to create a series of buttons that an individual can select from. When the user selects one of the buttons the value of the button is saved to session state. They are taken to the next step and shown a similar list of buttons that are based on what they previously selected. Thus, if you choose "Hamburger" you might receive the options of "onion", "lettuce", "tomato" while if you choose "Hot Dog" you might receive "sauerkraut" and "ketchup".
Lets say an individual chooses Hamburger. This is saved into session state like so:
Public Sub Button_ItemCommand(ByVal Sender As Object, ByVal e As RepeaterCommandEventArgs)
' ******** Lets pass on the results of our query in LinqDataSource1_Selecting.
Session("food_select") = RTrim(e.CommandName)
Wizard1.ActiveStepIndex = 1
End Sub
Now, this works fine and dandy. But lets say I select hamburger and then realize I'm really hankering for a hot dog. I go back to the first wizard step and click on the hot dog button - but when the wizard progresses to the next step I still see the options for hamburgers! The session variable has not been updated. Why?
Thanks!
The session variable was probably updated, but the next page was still cached from the previous time it was accessed.
Make sure your wizard pages are not cached.
Problem was in checking the session variables too early. I needed to move them later in the page load process - e.g. prerender, then the session variables would be updated.
Related
I'm having an issue binding the value of a page item to a declared variable in an anonymous PL/SQL block process.
The problem is that the page item (:P4550_REQUESTOR) is not populated with a value until a conditional is met. It appears that the PL/SQL block process is binding the variable to an empty value as soon as the page is loaded, despite the fact that the process does not fire until a specific button has been clicked.
Here is my code:
DECLARE
v_email_to app_user.email%type;
v_requestor VARCHAR2(15);
BEGIN
v_requestor := :P4550_REQUESTOR;
BEGIN
SELECT email INTO v_email_to
FROM app_user
WHERE userid = v_requestor;
END;
SEND_APEX_MAIL (
v_email_to,
'Your vacancy request has been rejected.'
|| chr(10)
|| 'Emailed to: ' || v_email_to
|| chr(10)
|| 'Requestor: ' || v_requestor,
'Vacancy Request Rejected'
);
END;
Does anyone have any thoughts on this?
The block works just fine if I hard code a value to v_requestor. If I try to get the value of P4550_REQUESTOR after the page has loaded, it is empty. After clicking the edit button, P4550_REQUESTOR is populated.
** **MORE DETAIL** **
P4550_REQUESTOR is a page item that resides within the Vacancy Request region which is only displayed when a conditional is met. Specifically, the conditional is an edit button associated with a table row that is created on page load. Clicking the edit button causes the details region to display, and the associated page items to be populated.
The page item values in the Vacancy Request region are populated via an Automated Row Fetch which fires After Header.
P4550_REQUESTOR has a Source Type of DB Column.
The process that fires the code above is set to fire On Submit - After Computations and Validations
If I log the value of P4550_REQUESTOR when the page loads, it shows null. If I log the value after clicking the edit button, I get the expected string value.
Process Flow Control in Oracle APEX
(This is actually useful to think about in other programming disciplines and environments.)
Problem Defined
The problem is that the page item (:P4550_REQUESTOR) is not populated with a value until a conditional is met. It appears that the PL/SQL block process is binding the variable to an empty value as soon as the page is loaded, despite the fact that the process does not fire until a specific button has been clicked.
The problem statement reworded in Apex terminology and presented in the form of an actual question:
There is a REPORT REGION on the page which contains the result of a direct reference to a data table/view. This report is managed by an Apex process called "Automated Fetch" and is initiated automatically by the loading of the page headers.
There is a FORM ITEM on a page which which is populated conditionally by a BUTTON ITEM selection made by the user. The BUTTON ITEM is part of the report results.
There are multiple button items. Each is associated with a value for each report record.
If the user does not select the BUTTON ITEM from the REPORT REGION, the FORM ITEM remains unassigned and contains a "null" value.
There is a defined PL/SQL block of code which is set to execute when a SUBMIT BUTTON item is pressed (also on the same page). Why does my code block (defined page process) run with a null value when it is triggered without first pressing a BUTTON ITEM from the REPORT REGION first?
Event Driven Program Design for Procedural Programmers
The answer is not obvious if you think under the paradigm of a procedural language. Without diving into a lecture on the topic, here's a visual layout of the problem space of the OP that I cooked up to illustrate how the problem can be made more obvious:
This is my Apex page design in implementation. It's generic enough to use as a template for other Apex designs. There are no flow arrows on this diagram because it's a stateful system. One thing causes another thing to happen and so on... but not always and not all at the same time.
Use Cases for Apex UI Page Designs
Try walking through a few use cases to understand how the elements broken down in the diagram operate together. Each user may take any number of click combinations and interactions, but there is a commonality:
They all enter the same initialized conditions on page load.
They all leave the page by: navigating elsewhere or through the SUBMIT button event.
Use Case #1
User chooses {MyPage:SQLReport:ThisButton} from one of the records in {MyPage:SQLReport}
According to {MyPage:SQLReport:ThisButton} #3, the value associated between the report record and the button item is passed to: {MyPage:HTML-Region:ThisItem}
The form item state has been updated and changed from the initial null value.
User selects {MyPage:HTML-Region:ThisSubmit} button to inform the system to continue on.
The submit button executes the defined PL/SQL procedure block: {MyPage:RunCodeBlock}
Use Case #2
User enters page and reviews results displayed in the {MyPage:SQLReport} region.
User decides no additional input is necessary and then selects the {MyPage:HTML-Region:ThisSubmit} button to inform the system to continue on.
(a note: the state of form item {MyPage:HTML-Region:ThisItem} has not been changed from the initial null value at this point... after the submit button has been selected)
The submit button executes the defined PL/SQL procedure block: {MyPage:RunCodeBlock}
Use Case #3
User chooses {MyPage:SQLReport:ThisButton} from one of the records in {MyPage:SQLReport}
According to {MyPage:SQLReport:ThisButton} #3, the value associated between the report record and the button item is passed to: {MyPage:HTML-Region:ThisItem}
The form item state has been updated and changed from the initial null value.
User chooses {MyPage:SQLReport:ThisButton} from a different selection from one of the records in {MyPage:SQLReport}.
According to {MyPage:SQLReport:ThisButton} #3, the value associated between the report record and the button item is passed to: {MyPage:HTML-Region:ThisItem}
The form item state has been updated and changed from the initial value stored in step (2).
User selects {MyPage:HTML-Region:ThisSubmit} button to inform the system to continue on.
The submit button executes the defined PL/SQL procedure block: {MyPage:RunCodeBlock}
The difference between each case should illustrate why the dependent value (ThisItem, or more specifically, page item P4550_REQUESTOR) is null in one use case vs. the other.
Building a Physical Implementation (An Apex Page)
The table I used is called STAR_EMPS. It is similar to the EMP table but has only three columns: ename, deptno and salary. Although it is not super important, this is the data set I used to populate STAR_EMPS:
I used a simple two-column table named STAR_EMPS_LOG for capturing the output of a successfully executed procedure call. You could accomplish the same with just one column, but I wanted a sequential id for tracking the order each event was recorded- for running multiple test cases. The procedure is one of several defined processes kept on this page:
contained in: {MyPage:RunCodeBlock} is below:
DECLARE
-- output from this procedure will be recorded in the star_emps_log
-- table. {MyPage:RunCodeBlock}
mycelebrity star_emps.ename%TYPE:= :P17_CELEBRITY_NAME;
mylogmessage star_emps_log.log_message%TYPE;
BEGIN
-- Conditional; changes message based on the value set for the
-- page item.
if mycelebrity is null then
mylogmessage:= 'No button was pressed on the previous page.';
else
mylogmessage:= 'The user selected: ' || mycelebrity ||
' from the report list.';
end if;
-- populate value from the page item.
INSERT INTO star_emps_log (log_message)
VALUES (mylogmessage);
commit;
END;
This is how the page layout was set up:
As in your example, I made a {MyPage:SQLReport} region with its supporting elements. The SQL Report represents a query directed at the source data table.
{MyPage:Form} has been renamed to {MyPage:HTML-Region}.
{MyPage:SQLReport} is defined by a SQL query, there is also a mock column to use as a place holder for placement of the "edit" buttons.
{MyPage:SQLReport:ThisButton} The button specifications are detailed through this:
The TWO Page processes: PROCESS and BRANCH need to be linked with the same settings referencing a BUTTON triggering Item.
User Interface Test Cases
Run through the three suggested scenarios to get started. Verify that the system is interpreting the requests correctly. This is what the page layout looks like:
The two processes on the system have a definition that wasn't mentioned in previous discussions may solve our original problem at hand:
Some Parting Thoughts
It is a good thing this turns out to be a trivial case once broken down. The diagramming method described here should scale to other Apex applications of varying complexity. There is considerable utility in stepping away from the code, locking down on terminology and trying to describe systems and processes without actual code. Please be sure to share any stories if this approach helps with your own Oracle Apex design challenges.
Onward!
The original, verbose answer seems to way overcomplicate the issue. The session state concepts manual covers this behaviour more succinctly.
Should P4550_REQUESTOR be a normal item created from a wizard, using :P4550_REQUESTOR will return a value in processes running post submit because the submit processes moves values in browser to session state.
If P4550_REQUESTOR is rendered conditionally, then it will always be null and I'm not sure what would happen if you tried to set it - probably depends how.
On a similar note, if you used &P4550_REQUESTOR. to parameterise the process, you would face the behaviour originally described (and made the code less secure)
I have a multiview with 4 views. To switch between the views I use 4 buttons and switch the multiview's activeview index to the relevant view inside the click event of each button.
In each view there are various controls to capture data. There is then a submit button at the bottom of the final view to write all the data to a database.
What I want to achieve is to capture a time stamp of when the user clicks the button to move to each view (which will ultimately be written to the database). I can assign a timestamp to a variable by using the below code in the click event of each of the 4 buttons
Dim phase1TimeStamp as string = DateTime.Now.TimeOfDay.ToString()
The problem is, when I come to write the records to the database in the click event of the submit button, it cannot see the values assigned to these time stamp variables.
Is there a way I can pass these variable values to the submit button click event or is there a different way I can achieve this altogether? Thanks
The easiest way to do this is probably by saving the variable to session, then retrieving it. You didn't say if this was ASP .NET Web Forms or MVC, so I will give you an option for each. MVC has a few different ways you can achieve this (ViewData, ViewBag, TempData, or directly to Session). I'm not quite as familiar with Web Forms but you can at least save to Session.
Web Forms
to save to session:
HttpContext.Current.Session("phase1TimeStamp") = phase1TimeStamp.ToString()
to retrieve it (you may have to cast it, depending on the type and your VB settings):
Dim myVar as String = HttpContext.Current.Session("phase1TimeStamp")
MVC
to save to session:
Session("phase1TimeStamp") = phase1TimeStamp.ToString()
to retrieve it:
Dim myVar as String = Session("phase1TimeStamp")
A note about MVC: If you want this to work across multiple sessions (I.E., for different users or even for the same user but with multiple tabs open), you will need to append the identifier ("phase1TimeStamp") in this case with some sort of unique identifier.
You can store the values in Session cache, like this:
Session("MultiView1_Clicked_DateTime") = DateTime.Now.TimeOfDay.ToString()
Session("MultiView2_Clicked_DateTime") = DateTime.Now.TimeOfDay.ToString()
Session("MultiView3_Clicked_DateTime") = DateTime.Now.TimeOfDay.ToString()
Session("MultiView4_Clicked_DateTime") = DateTime.Now.TimeOfDay.ToString()
The Session value will exist in memory across page requests.
Note: You can name the Session key whatever you wish, but to get the value back out you need to match that key name exactly. Also, everything in Session is stored as an Object so you will need to cast the value to a String when you want to retrieve the value.
I need to navigate between some records that I have in a database.
For example, I have a prev-record button on my page which navigates back by one record.
But as soon as I click the button, the page_load is fired first thus setting my function variables to their initial values.
Thus I can use the button only once. The second time I use, it will navigate to the same record.
I need a way to store the value of the variable after the function is executed and reuse this value again.
I am a beginner.
Thanks for the help in advance!
This can be achieve in different ways.
You can keep the old value in viewstate or in query stirng and next time you can check it.
But if you are using gridview you can go through the below example
http://www.codeproject.com/Articles/67520/GridView-Paging-and-Sorting
view state example
http://aspnet-with-c-sharp.blogspot.in/2010/12/viewstate-with-example-in-aspnet-c.html
In your page load, only set the function variables if Page.isPostback is false. This will prevent the values from being reset on a postback. eg.
If (!Page.isPostBack)
{
//Set initial function variables
// also store the initial values, possibly in session
}
When you navigate to the next record, store the previous record values in session. Then when you you go to the previous record, use the session value.
i'm trying tocreate a biding system with this structure :
users can reserve an auction and then when the auction is starting users can click on a button and this button will rais up the base price. the problem is :
i want to show the last order for all users and this will happen every one seccond and this will be in an update panel that it includes me datalist (showing runnig auctions) and every one seccond this updatepanel should be update and datasource should get data that is very slow.
any suggestion ?
Read about Comet.
Basically you'll get an event of a bid, then you need to publish it. See Publish–subscribe.
Also google for pub sub asp.net.
Edit #1: Google for http push as well.
I am working on a job portal site where user can enter multiple profiles.
I am showing all profiles in a gridview. My requirement is now that
there should be a status link with his all profiles (it is in bit).
Example:
This is my gridview:
jobseekerid | Profileid | status
1 2 Active
1 3 DeActive
1 4 DeActive
....
....
From all of this only one profile can be active.
So when the user clicks on any inactive profile, it will become active and then all
remaining profile will become inactive.
The condition is that at a time only one profile can be active. (When he make his one profile active, the remaining ones will become inactive automatically.)
Now the Problem is, I am not able to make all the remaining profiles inactive when the user makes a profile active in the gridview.
How can I do this?
This is a common problem, and is usually solved by retaining the original dataset that you populated the gridview with. So, in your case, you should stored the dataset (or a list of profiles - whatever dataset you used to populate gridview) in a viewstate (given it is not too big, otherwise the page will load slow). Then, when you populate your gridview, you need to assign a profile ID to each click event, so you know which one got clicked. You then need to loop over the dataset that you saved in your viewstate, and update all of them (except the one that just got clicked) to inactive. The loop is not as cludgy as it sounds... with sql server 2005 and 2008 you have a new datatype called 'table', so you can pass all the other profileIDs in a one swoop to the DB to update them all to inactive.
Upon an update, loop through the table rows of the Gridview and change the values accordingly, if that's sufficient enough to update the record in the backend. If there is a value associated with it, you could hold that value in a hidden field and change the value in the hidden field as well.
If these changes are going to happen on the fly (i.e. you are updating the database upon a change), you could set a hidden field as a postback trigger and eval() it when you've clicked on whatever button is saving your updated record with the updated status. This would cause the RowCommand to fire, where you could loop through each record and update accordingly.