How to notify the user in case of unsubmitted change in QDataWidgetMapper - c++

I'm using QDataWidgetMapper to display values in a model. I set its submit policy to be ManualSubmit so that users won't accidentally put in wrong values. But I also want to warn the user about unsubmitted change if he/she selects another row without saving. I have consulted the documentation and the Internet, but it seems that no signals are emitted prior to change in selection, nor is there any API querying the dirty status of the QDataWidgetMapper, which makes my task seemingly impossible. Is there any way to achieve this?

You can have a variable in the submit slot whose value you can monitor when the user selects another row.
Let value of that variable be x.
When user selects another row, fire a signal whose slot will check whether some text has changed or appeared in the text box of previous row && if that variable is still x.
If the variable is still x that would mean user didn't click the submit button.
When user clicks the submit button, let the variable be y.

Related

How to add a new record into an interactive grid using IG methods then set column's value using $s() api?

I am using Oracle Apex 18.2.
I have an interactive grid and a custom button to add a new row to the IG using,
apex.region("myRegionStaticId").widget().interactiveGrid('getActions').invoke('row-add-row'); then set a column's value using, $s("myColumnStaticId","2");. When I try it, it adds the first row without setting any columns' values and starts setting the value from the second row on. Even using selection-add-row or insert-record, there is always something with the first row. Here is a sample,
[https://apex.oracle.com][1]
ws = ESLAM_WS
user = forhelp
pwd = forhelppwd
app = TEST
page = Add Row on top of an IG.
After a lot of talking and testing, I've found that $s with setTimeout isn't very reliable. I've set up page 7 again to demonstrate.
If you click the Rowaddrow button twice in rapid succession (the second time before the first setValue returns), the second row will not be initialized. I'll show you a workaround for this below, but you'll
If you lower the setTimeout to, say, 10 ms, and try focusing in the Expiry Date column before clicking the Rowaddrow button, you'll find it doesn't work. This means that, while the setTimeout of 100 ms works now, it could break in the future if the IGs internal logic changed. Unlikely but who knows.
For the moment, I would say that $s can only be reliably used to set a column value in an IG for the active row. When the row-add-row action adds a new record, it does make it active, but that is done asynchronously via setTimeout. This is because the IG is based on the flyweight pattern and there are a number of async (setTimeout based) heuristics that are built in to handle focus and blur events to correctly enable and disable rows and cells as needed.
I've found the following to be the most reliable solution. Unfortunately, it's more complex than what you had before - but it was the only way I could wrangle it all together. Feel free to use it or not. See page 8 for an example.
Right-click the custom Rowaddrow button and select Create Dynamic Action. Set the Name of the DA to rowAddRow button clicked. The When settings will automatically be configured for the click event on the button.
Select the action for the new DA. Set Action to Execute JavaScript and enter the following JavaScript in the Code attribute.
addRowClicked = true; // Global used to distinguish custom button click
this.triggeringElement.disabled = true; // Disable button to serialize access
apex.region("KITCHEN_SHARE_DTL").widget().interactiveGrid("getActions").invoke("row-add-row");
Create a new Dynamic Action and set the Name to New row initialized. In the When section, set Event to Row Initialization [Interactive Grid], Section Type to Region, and Region to KITCHEN_SHARE_DTL.
Under Client-Side Condition, set Type to JavaScript expression and enter the following code in JavaScript Expression (which ensures the DA only fires for the click of the Rowaddrow button):
addRowClicked === true
Select the action for the new DA. Set Action to Set Value, Set Type to Static Assignment, and Value to 2. In Affected Elements, set Section Type to Column(s) and Column(s) to INGREDIENT_ID. This will replace the static assignment that was being done with $s. Ensure that Fire on Initialization is disabled.
Right-click the True branch for the DA and select Create TRUE Action. Set the Action to Set Value, Set Type to SQL Statement, and enter the following code in SQL Statement:
select MIN(EXPIRY_DATE) from stock
where ingredient_id = TO_NUMBER(:INGREDIENT_ID);
Set Items to Submit to INGREDIENT_ID and disable Escape Special Characters. In Affected Elements, set Selection Type to Column(s) and Column(s) to EXPIRY_DATE. Ensure that Fire on Initialization is disabled.
Right-click the True branch for the DA and select Create TRUE Action. Set Action to Execute JavaScript Code and enter the following JavaScript in the Code attribute.
addRowClicked = false; // Unset the global
$x('ADD').disabled = false; // Enable the button
Change the following code:
$s("INGREDIENT_ID","2");
with the following one:
setTimeout(function(){ $s("INGREDIENT_ID","2"); }, 100);
It seems that the IG needs a little time to render the new row before you are able to change any value.

Oracle APEX - displaying conditional prompt

I have a form with a validation to check if the name entered already exists in the database and when submit button is clicked I want to proceed with an insert if the validation succeeds and if it fails, display a user prompt and if the user OK's it, then proceed with the update of existing record. I know how to do one of those at a time but not sure how to do this conditionally.
If I want to display a prompt I can use redirect to URL on a button click and set a prompt to whatever I want but how to only display a prompt when the validation fails?
Based on the followup comments, I would recommend the following:
Add a hidden item to the page, P1_NAME_EXISTS, for example. Ensure that its Value Protected setting is disabled.
Change the Action of the submit button to Defined by Dynamic Action.
Create a Dynamic Action on the click event of the button.
Make the first action an Execute PL/SQL Code action. Populate the Items to Submit property with the name of the item that has the name value you wish to validate. Then enter the PL/SQL code needed to see if the name is a duplicate. Set the value of P1_NAME_EXISTS to 'Y' or 'N' (or similar Boolean like values) within the PL/SQL code. Then put the name of the item (P1_NAME_EXISTS) in the Items to Return property of the action.
Add a second action. Set the Action to Execute JavaScript Code. Enter code like the following in the Code field:
var nameExists = $v('P1_NAME_EXISTS') === 'Y';
if (!nameExists) {
apex.page.submit('SAVE');
} else {
apex.page.confirm('This name already exists. Would you like to update the existing entry?', 'SAVE');
}
The JavaScript code will check the value of the hidden item after the PL/SQL process updates it. If the name doesn't already exist, then the page will just be submitted. If the name already exists, then the user will be prompted. Only if they click okay will the page be submitted.
You could change the value of the submit values if you needed to tell the difference.
You create a declarative Validation. If your validation condition fails, you'll see the error you define, instead of normal processing.
In this case you could have validation based on existence of a row.
If all validations are fine, then page processing will commence.
All computations, validations, and processes can be conditional - either a nominated button, or a condition often based on valid of :REQUEST.
Or, you could have a constraint on the table that fails when the value already exists, and handle that with your APEX error function. Why do a pre-check when you can rely on DB constraints?

Oracle Apex Set values before moving to another page, Items are all null

I am trying to do the following:
Anonymous user with a unique key enters a code and clicks 'Start Survey'
The button needs to call a plsql process to populate some hidden page items.
Once the values are set branch to the survey page which will use the hidden items for filtering results.
The Problem
No matter what I have tried so far the items set by the process are null when I get to the next page. I assume this is because it did not submit. The way I have it at the moment is:
Button navigates to the next page
New process set to when the button is pressed sets the values of the page items.
By the time it gets to the next page they are blank again.
I could set the button to submit and do the branch in the processing but I think the submit would happen before the values are set. I find it confusing what order these things happen in.
Can I please get help with making this work, and is there a good article on understanding this area better?
here is the code from the process that puts the values in:
Begin
select id into :P1_pat_id
from lic_paticipent
where unique_id = :P1_unique_code;
select sur_id into :P1_sur_id
from lic_paticipent
where unique_id = :P1_unique_code;
select id into :P1_first_res_id
from lic_result r
where r.pat_id = :P1_pat_id
and r.sur_id = :P1_sur_id
and r.qop_id is null
and rownum = 1;
End;
Thanks in advance for your help.
OK I solved it and it is my playing around with another issue that cased it.
I had set the hidden fields to "Always replacing" instead of "Only when null" so the plsql process updated the session but not the item so when I did a submit the null item replaced what the plsql process had set. I had expected that when the session was updated it would update the item also.
I worked it out by making the hidden field visible and could see it was blank but had a value when I checked the session state.
Hidden page items in your current page cant be used in other pages unless your current page is a global page. You have to pass the value to another page item in the other page.
Try this:
Go to the other page and Create hidden items to catch the value to be passed from the first page.
Go back to the first page and retain your process and create a branch process. then set it to redirect to another page. then you'll see Set items below. Put your hidden items in the other page in the left side then your hidden items in your current page in the right side in this format &P1_NEW.(with the period)
It should look like this
Set Items
P11_PAT_ID--------------------------&P1_PAT_ID.
P11_SUR_ID--------------------------&P1_SUR_ID.
etc.

Paradimatic signal for when a user selects a row

I have a QTableView that represents a model made of rows and few columns, for example coordinates such as x,y,z. The rows are whole elements and I want to trigger a signal every time a user has chosen a selection. I envision some graphics object changing depending on the selected row.
My current attempt is to do something like
ui.tlbView->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
ui.tlbView->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows);
connect(ui.tlbView,&QTableView::clicked ,this,&FancyWidget::rowSelected);
This works sometimes, but fails other times. For example clicking on the vertical header does not register while the selection changes. This is bad because I want a signal that triggers every time the selection changes.
This makes me feel like catching the clicked signal is a hack and given that the widget correctly identifies that it is selected, even when my clicked signal is not called. I'm trying to figure out how to match 1:1 the selection state of the widget.
To get notified of selection changes, have a look at QItemSelectionModel.
The table view's selection model you can access via selectionModel(). In your case, QItemSelectionModel::selectionChanged() should be what you need.
connect(ui.tlbView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &FancyWidget::selectionChanged);

Lotus Notes: refresh form from field

I have an editable field. Another computed field value depends from the value of the editable field.
In the Exiting event of the editable field I add:
Dim workspace As New NotesUIWorkspace
Dim uidoc As NotesUIDocument
Set uidoc = workspace.CurrentDocument
Call uidoc.Refresh
But it still not works. If I check the form property Automatically refresh fields, it goes OK, but the form performance decreases, it is very slow.
Any suggestions? Thanks!
Lotus Notes always computes the whole form from left to right and from top to bottom.
If a computed field is above the field, that triggers the refresh, then it does not have access to the "new" values of the editable field on the first refresh.
You would need 2x Call uidoc.refresh to make the computed field reflect the changes.
Or you move the computed field BELOW the editable field, then one single refresh will be sufficient.
Alternatively you may choose to use the onBlur- Event instead of the exiting- event as the "on"- Events were meant to replace the "Classic" Field events since version 6 of Lotus Domino / Notes. Check this link to Designer Help to see hints like
The corresponding LotusScript-only events still occur, but their continued use in Release 6 applications is discouraged.
onBlur: New for LotusScript with Release 6 and
Exiting: Preferred is onBlur
in the editable field's event "OnBlur" , switch to Client/LotusScript) and only add :
notesuiuiworkspace.CurrentDocument.Refresh
Don't forget to remove the one in exiting.