I have a dynamic action doing the below ,
Submit page ,
Successful Alert message,
Log out and redirect to another website (www.google.com),
And I have two required item in page.
When pressed the button and the item is null ,the successful Alert message appears and after that the system shows the error (the item is required). How can I show the successful alert message only when the process and validation are done without errors ,and when ok is pressed in the alert message redirect to website and log out from the sessions
There are different ways you could approach this. You're currently using a mix of Dynamic Actions and page-level validations and processes that aren't going to play well together. I suggest you move all the logic to Dynamic Actions. Here are step by step instructions to do what I think you're trying to do. You can learn from this and then integrate what you want back to your solution.
Create a new blank page. Mine was page 17. You'll need to update references to "P17" with your page number if it's different. Disable the page level attribute Warn on Unsaved Changes to prevent prompts before the redirect to Google.
Add a new HTML region to the page.
Add a new item to the region. Set Name to P17_FIRST_NAME and leave the default Type of Text Field.
Add a new item to the region. Set Name to P17_LAST_NAME and leave the default Type of Text Field.
Add a new item to the region. Set Name to P17_RESULT, Type to Hidden, and Value Protected to No. This item will be used to transfer messages from the server to the client via Ajax.
Add a button to the region. Set Name to RUN_PROCESS and Action to Defined by Dynamic Action.
Create a new Dynamic Action that fires when the button is clicked. The easiest way to do this is to right-click the button and select Create Dynamic Action. Set the Name to RUN_PROCESS clicked.
Select the Show action that was created by default for the Dynamic Action. Set Action to Execute PL/SQL Code and copy-paste the following code into the PL/SQL Code attribute.
declare
l_result_obj json_object_t := json_object_t();
l_errors_arr json_array_t := json_array_t();
l_error_obj json_object_t;
begin
if :P17_FIRST_NAME is null
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', 'P17_FIRST_NAME');
l_error_obj.put('message', 'First Name is required.');
l_errors_arr.append(l_error_obj);
end if;
if :P17_LAST_NAME is null
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', 'P17_LAST_NAME');
l_error_obj.put('message', 'Last Name is required.');
l_errors_arr.append(l_error_obj);
end if;
if l_errors_arr.get_size() > 0
then
l_result_obj.put('status', 'error');
l_result_obj.put('errors', l_errors_arr);
:P17_RESULT := l_result_obj.to_string();
return;
end if;
null; -- do "success" processing here
l_result_obj.put('status', 'success');
l_result_obj.put('message', 'Hi ' || :P17_LAST_NAME || ' ' || :P17_LAST_NAME ||
'! You will now be redirected to Google.');
:P17_RESULT := l_result_obj.to_string();
end;
As you can see, the validations are now being done inside the process. The PL/SQL code is making use of the JSON types introduced with Oracle 12.2. If you're on an older version of the database, you can adapt the code to use APEX_JSON instead.
While still in the Execute PL/SQL Code action, set Items to Submit to P17_FIRST_NAME,P17_LAST_NAME and Items to Return to P17_RESULT. This is how you can transfer values from the page into session state before the process executes and then back to the page after the process finishes executing.
Create a new Dynamic Action that fires on the Change event of P17_RESULT. The easiest way to do this is to right-click the item and select Create Dynamic Action. Set the Name to P17_RESULT changed.
Select the Show action that was created by default for the Dynamic Action. Set Action to Execute JavaScript Code and copy-paste the following code into the Code attribute.
var result = JSON.parse($v('P17_RESULT'));
apex.message.clearErrors();
if (result.status === 'error') {
for (var idx = 0; idx < result.errors.length; idx++) {
result.errors[idx].type = 'error';
result.errors[idx].location = ['page', 'inline'];
result.errors[idx].unsafe = false;
}
apex.message.showErrors(result.errors);
} else if (result.status === 'success') {
apex.message.alert(result.message, function(){
apex.navigation.redirect('https://google.com');
});
}
The JavaScript code takes the result from the process and either displays error messages or an alert. I'm using apex.message.alert instead of apex.message.showPageSuccess because the former supports a callback when the message is dismissed. When the message is dismissed, apex.navigation.redirect takes the user to Google.
Here's what it should look like in the end:
I hope there's enough information here for you to understand what's going on. Let me know if you have any questions. You'll find the documentation for apex.navigation and apex.message here: https://apex.oracle.com/jsapi
P.S. Here's an example of what the PL/SQL code would look like using APEX_JSON.
declare
l_error_count pls_integer := 0;
l_result_obj clob;
begin
apex_json.initialize_clob_output;
apex_json.open_object();
apex_json.open_array('errors');
if :P17_FIRST_NAME is null
then
l_error_count := l_error_count + 1;
apex_json.open_object();
apex_json.write('pageItem', 'P17_FIRST_NAME');
apex_json.write('message', 'First Name is required.');
apex_json.close_object();
end if;
if :P17_LAST_NAME is null
then
l_error_count := l_error_count + 1;
apex_json.open_object();
apex_json.write('pageItem', 'P17_LAST_NAME');
apex_json.write('message', 'Last Name is required.');
apex_json.close_object();
end if;
apex_json.close_array();
if l_error_count > 0
then
apex_json.write('status', 'error');
apex_json.close_object();
:P17_RESULT := apex_json.get_clob_output();
apex_json.free_output;
return;
end if;
null; -- do "success" processing here
apex_json.write('status', 'success');
apex_json.write('message', 'Hi ' || :P17_LAST_NAME || ' ' || :P17_LAST_NAME ||
'! You will now be redirected to Google.');
apex_json.close_object();
:P17_RESULT := apex_json.get_clob_output();
apex_json.free_output;
end;
Related
I am new to developing application using oracle apex. Please excuse me if this question seems very trivial in nature.
In a nutshell, I am trying to invoke a REST service programmatically to populate an interactive grid on oracle apex page. Here's what I already tried.
Created a page that has a button to invoke a process.
The process invokes a REST service to get all order lines belonging to a particular order. The sample response from the REST service is as below
{
"items": [{
"HeaderId": 300100550016803,
"FulfillLineId": 300100550016806,
"SourceTransactionLineId": "1",
"SourceTransactionLineNumber": "1",
"OrderedQuantity": "10",
"OrderedUOM": "Each",
"RequestedFulfillmentOrg": "Vision Corporation"
},{
"HeaderId": 300100550016803,
"FulfillLineId": 300100550016807,
"SourceTransactionLineId": "2",
"SourceTransactionLineNumber": "2",
"OrderedQuantity": "15",
"OrderedUOM": "Each",
"RequestedFulfillmentOrg": "Seattle Manufacturing"
}]
}
If the rest service invocation was successful (http status code: 200), then I create the apex_collection as below in the same process. Also, I have set one of the page fields (P3_REFRESH_ORDER_LINES_GRID) to ‘Y'. On page load, the value for this attribute must be null.
if apex_web_service.g_status_code = 200 then --OK
dbms_output.put_line( 'Response : ' || l_data ); --if response was OK, print it
apex_collection.create_or_truncate_collection( 'OrderLines' );
apex_collection.add_member(
p_collection_name => 'OrderLines',
p_clob001 => l_data );
:P3_REFRESH_ORDER_LINES_GRID := 'Y';
end if;
I have then used the below SQL query to populate data into the interactive grid
Set the region type to “Interactive Grid”
Source: Local Database
Type: SQL query
SELECT ol.fulfill_line_id as FulfillLineId, ol.quantity as Quantity
FROM APEX_collections c,
JSON_TABLE(
c.clob001, -- the following lines depend on your JSON structure
'$.items[*]'
columns(
fulfill_line_id number path '$.FulfillLineId',
quantity number path '$.OrderedQuantity')
) ol
WHERE c.collection_name = 'OrderLines';
Then, I have setup a dynamic action on the page item (Its a hidden text field)
- P3_REFRESH_ORDER_LINES_GRID
- Dynamic Action name : RefreshGrid
- When: Event Name: Change
- selection type: Item
- Item - P3_REFRESH_ORDER_LINES_GRID
- Client side condition - Type: Item is not null
- Item - P3_REFRESH_ORDER_LINES_GRID
- True condition: Action: Refresh, selection type: Region, Region: Order Lines (Name of the region containing the IG)
After I click on the button to invoke the rest service to fetch the order lines, the interactive grid does not display any data. Can you suggest where am I going wrong here?
Potential Issue(s)
Step 1 You didn't really specify how your button works. If it is submitting the page, you may have problems with P3_REFRESH_ORDER_LINES_GRID field remaining null.
You could have Server-Side conditions preventing the invocation or on Page-Load you may be resetting P3_REFRESH_ORDER_LINES_GRID to null, and Step 5 will NOT trigger.
Step 3(Most Likely Issue) If you are not submitting the page, and you just have a Dynamic Action, executing Server-Side code: you may have forgotten to include P3_REFRESH_ORDER_LINES_GRID in the Items to Return.
Your P3_REFRESH_ORDER_LINES_GRID flag will remain null and Step 5 will NOT trigger.
To Debug
You can try debugging your page here by checking Session under Developer Tools. I would make sure each step work and executes however I intend it to execute.
Also leverage APEX_DEBUG in my PL/SQL
Open your Browser's Developer Tools and look under Console. You should see Dynamic Action Fired lines there if Step 5 is being triggered at all!
As you have not shared how your debugging went, and other observations after clicking the button, such as:
Was the collection created?
Is there data in the collection?
What's the value of P3_REFRESH_ORDER_LINES_GRID
You should be able to see what the answers are for the above using Session.
Requirement -
Below fields to be displayed on a APEX page for any Jira issue created.
Issue Number/Issue Id
Summary
Description
Status
Assignee
Example, user01 and user02 both having access to Oracle APEX and Jira. user01 created 3 issues and user02 created 5 issues in Jira. Now when user01 who logs into Oracle APEX, should see 3 issues and when user02 who logs into Oracle APEX, should see 5 issues on a APEX page.
https://jira.local.com/jira/rest/api2
I'm new to APEX Rest service call and request to all of you to provide some sample APEX code to call Jira REST API using username/password for the above requirement.
Thanks all.
I have done something similar before. In my case, the goal was to get all the issues of project PRJ001 (Jira Project Key) from Jira and store them in a local database table (J_ISSUES), periodically, so I've created a Job that executed the following procedure from time to time:
create or replace PROCEDURE "JIRA_SYNC_ISSUES" as
var_response CLOB;
var_counter number := 0;
var_total number := 1;
var_prj_key varchar2(10);
begin
var_prj_key := 'PRJ001';
var_total := 1;
var_counter := 0;
while var_total > var_counter
loop
apex_session.create_session (p_app_id => 107, p_page_id => 1, p_username => 'USERNAME01');
var_response:= apex_web_service.make_rest_request(
p_url => 'https://yourcompany.atlassian.net/rest/api/2/search?jql=project="'|| var_prj_key ||'"&maxResults=100&startAt=' || var_counter || '',
p_http_method => 'GET',
p_credential_static_id => 'oud_rest'
);
SELECT JSON_VALUE(var_response, '$.total' RETURNING NUMBER) into var_total
FROM DUAL;
for i in (SELECT *
FROM
JSON_TABLE(var_response, '$.issues[*]'
COLUMNS (
key VARCHAR2(100) PATH '$.key',
prj_key VARCHAR2(100) PATH '$.fields.project.key',
status VARCHAR2(100) PATH '$.fields.status.name',
updated VARCHAR2(100) PATH '$.fields.updated',
assignee VARCHAR2(100) PATH '$.fields.assignee.name',
time_spent NUMBER PATH '$.fields.timespent'
)))
loop
begin
insert into j_issues (jis_key, jis_jpr_key, jis_status, jis_updated, jis_assignee, jis_time_spent)
values (i.key,
i.prj_key,
i.status,
to_timestamp(substr(i.updated,1,10)||' '||substr(i.updated,12,8),'YYYY-MM-DD HH24:MI:SS'),
i.assignee,
i.time_spent);
exception
when dup_val_on_index then
update j_issues
set jis_jpr_key = i.prj_key,
jis_status = i.status,
jis_updated = to_timestamp(substr(i.updated,1,10)||' '||substr(i.updated,12,8),'YYYY-MM-DD HH24:MI:SS'),
jis_assignee = i.assignee,
jis_time_spent = i.time_spent
where jis_key = i.key;
end;
var_counter := var_counter + 1;
end loop;
end loop;
end jira_sync_issues;
In the first part it is authenticating and making the call to the API. In the second, it takes the var_response and inserts it into the required table.
For the first part, I've read this: https://www.jmjcloud.com/blog/simplifying-apex_web_service-oauth2-client-credentials
For the second: https://docs.oracle.com/database/121/SQLRF/functions092.htm
Notice the var_counter and var_total variables. They are used to iterate through the Jira responses, because there is a limit of items being retrieved in each response. So, if you are expecting more than that limit, you should make more calls to retrieve them.
If the volume of issues is big, there are advantages in doing a scheduled sync like this instead of letting the user wait for the entire result. After the data is in your database, you can just query it as usual.
Let me know if it helps ;)
I'm running Apex 19.2
I have a page with some items created dynamically as follows :
HTML clob;
Html := APEX_ITEM.textarea(p_idx=>32, p_value=>'MyValue',p_item_id=>'MyId',p_attributes=>'class="textarea"');
htp.p(HTML);
The page items are generated correctly :
<textarea name="f32" rows="4" cols="40" wrap="VIRTUAL" class="textarea" id="MyId"></textarea>
I'm also adding the item wrapper to match the static Items layout created from the designer.
<div class="t-Form-inputContainer col">
<div class="t-Form-itemWrapper">
<textarea name="f32" rows="4" cols="40" wrap="VIRTUAL" class="textarea" id="MyId"></textarea>
</div>
<span id="MyId_error_placeholder" class="a-Form-error"></span>
</div>
In the validation, I'm checking some rules from apex_application.g_fn arrays and I would like to show an error on the item created via :
apex_error.add_error(p_message => 'error', p_display_location => apex_error.c_inline_with_field_and_notif, p_page_item_name=> 'MyId');
After validation, the error is not shown next to the item created. Notification also appears but it's empty. However If I try to show the same error on a static item created in the designer. The error is shown properly.
Can anyone help please ?
Thanks.
As you've found, APEX_ITEM doesn't work with APEX_ERROR in the way that you'd like it to. Marc's comments here indicate that APEX_ITEM will likely not be developed further, so it probably never will. https://stackoverflow.com/a/61737128/3010084
Your best option might be to move your validation logic to a stored procedure. Do all the validation in one call via parameters. In addition to the regular parameters, add a parameter that indicates if the response should be JSON or not. If so, just return a JSON document with the errors, otherwise use apex_error. This will allow you to call the validation logic via Ajax to show the errors where you like, but also on submit/page processing (because client-side validation can't be trusted).
Here are some steps you can follow to see how this works... First, compile the following procedure in your schema:
create or replace procedure validate_thing(
p_description in varchar2,
p_return_json in boolean,
p_json_result out json_object_t
)
is
l_errors_arr json_array_t := json_array_t();
l_error_obj json_object_t := json_object_t();
l_item_id varchar2(30);
l_error_message varchar2(255);
begin
if length(p_description) > 10
then
l_item_id := 'description';
l_error_message := 'Description should be less than 10 characters.';
if p_return_json
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', l_item_id);
l_error_obj.put('message', l_error_message);
l_errors_arr.append(l_error_obj);
else
-- Server-side code will not worry about displaying the error with the item as
-- this is just a backup for the client-side validation
apex_error.add_error(
p_message => l_error_message,
p_display_location => apex_error.c_inline_in_notification
);
end if;
end if;
if p_return_json
then
p_json_result := json_object_t();
if l_errors_arr.get_size() > 0
then
p_json_result.put('status', 'error');
p_json_result.put('errors', l_errors_arr);
else
p_json_result.put('status', 'success');
end if;
end if;
end;
As you can see, the procedure has logic to do client-side validations (JSON) or server-side validation (APEX_ERROR). You would need to add additional parameters and logic as needed for the form.
Create a new blank page in your app and go to the Page Designer for the new page. Right-click Content Body (under Regions) and select Create Region. Set the region's Type to PL/SQL Dynamic Content and add the following code to the PL/SQL Code attribute:
declare
html clob;
begin
-- The div and fieldset wrappers are needed so that APEX will generate an error
-- message template automatically to display the error inline.
html := '<div><fieldset>';
html := html || APEX_ITEM.textarea(p_idx=>32, p_value=>'MyValue',p_item_id=>'description',p_attributes=>'class="textarea apex-item-textarea"');
html := html || '</fieldset></div>';
htp.p(html);
end;
That code uses apex_item to add an item to the page dynamically. Note, the value passed to p_item_id, as that's important. The apex-item-textarea class is needed for error styling and the div and fieldset wrappers are needed to display error messages inline.
Select the Processing tab in Page Designer. Right-click Ajax Callback and select Create Process. Set Name to DO_VALIDATIONS and enter the following code in the PL/SQL Code field.
declare
l_result json_object_t;
begin
validate_thing(
p_description => apex_application.g_x01,
p_return_json => true,
p_json_result => l_result
);
htp.p(l_result.to_string());
end;
That is the code that will call validate_thing with p_return_json set to true. Note that the value of "description" is being passed in via apex_application.g_x01. You have g_x01 - g_x20 to work within this way. There are various options you could leverage to sent values in via Ajax, this is just one example. See see the doc on apex.server.process (used next) for more info.
Return to the rendering tab, right-click the new region, and select Create Button. Set the Button Name to SUBMIT. Right-click the SUBMIT button and select Create Dynamic Action. Set the Name to SUBMIT clicked. Select the default Show action, set its Action to Execute JavaScript Code, then add the following code to the Code field:
apex.server.process(
'DO_VALIDATIONS',
{
x01: $x('description').value
},
{
success: function(result) {
apex.message.clearErrors();
if (result.status === 'error') {
for (var idx = 0; idx < result.errors.length; idx++) {
result.errors[idx].type = 'error';
result.errors[idx].location = ['page', 'inline'];
result.errors[idx].unsafe = false;
}
apex.message.showErrors(result.errors);
} else if (result.status === 'success') {
apex.page.submit('SUBMIT');
}
},
error: function( jqXHR, textStatus, errorThrown ) {
console.log(jqXHR, textStatus, errorThrown)
}
}
);
This is the JavaScript code that will invoke the new DO_VALIDATIONS Ajax process. If errors are returned from the server, apex.message.showErrors will display them. Otherwise, the page is submitted for processing.
Select the Processing tab, right-click Processing, and select Create Process. Set Name to Do Validations and enter the following code in the PL/SQL Code attribute:
declare
-- Only needed to call validate_thing, not used.
l_result json_object_t;
begin
validate_thing(
p_description => apex_application.g_f32(1), -- This is where the item's value will be when submitting normally
p_return_json => false, -- This tells validate_thing to use apex_error
p_json_result => l_result
);
end;
That code will invoke validate_thing with p_return_json set to false. This will rerun the validations on the server-side to ensure they are enforced there. As it's just a backup for the client-side call, I don't worry about displaying errors inline with the items (the JS will do that).
Right-click Processing again and select Create Process. Set Name to Do Work and just enter null; for the PL/SQL Code Attribute. Set Success Message to It ran.. Under Server-side Condition, set Type to PL/SQL Expression and enter not apex_error.have_errors_occurred in the PL/SQL Expression field.
This process represents the actual business logic you want to run after validations have passed. You will only see the success message after clicking submit if both the Ajax and server-side validations have passed.
If you wish the test the server-side validations, add this line of JavaScript code in the Dynamic Action, just before the line that submits the page:
$x('description').value = '12345678910';
That will update the value of the text area to exceed the limit enforced by the server.
This is a follow on to "APEX row selector" posted 5 days ago.
The problem was collecting multiple values from an interactive grid. From the excellent links to post supplied I was able to achieve this. However, the next part of the project is to open an edit dialog page and update multiple values.
I added this code to the attribute of the interactive grid:
function (config)
{
var $ = apex.jQuery,
toolbarData = $.apex.interactiveGrid.copyDefaultToolbar(),
toolbarGroup = toolbarData.toolbarFind("actions3");
toolbarGroup.controls.push(
{
type: "BUTTON",
action: "updateCar",
label: "Edit Selected Cars",
hot: true,
});
config.toolbarData = toolbarData;
config.initActions = function (actions)
{
// Defining the action for activate button
actions.add(
{
name: "updateCar",
label: "Edit Selected Cars",
action: updateCar
});
}
function updateCar(event, focusElement)
{
var i, records, model, record,
view = apex.region("ig_car").widget().interactiveGrid("getCurrentView");
var vid = "";
model = view.model;
records = view.getSelectedRecords();
if (records.length > 0)
{
for (i = 0; i < records.length; i++)
{
record = records[i];
alert("Under Development " + record[1]);
vid = vid + record[1] + "||";
apex.item("P18_CAR").setValue(vid);
// need to open next page here and pass parameters
}
}
}
return config;
}
I need to know how to open a form and have the parameter values available to pass to an oracle update script.
Thank you for any help you can provide. I did find some posts but I really need a good example. I have tried everything to no avail.
There are various ways you could do this. Here's one way, perhaps someone else will offer a more efficient option.
The JavaScript options for navigation in APEX are documented here:
https://docs.oracle.com/en/database/oracle/application-express/19.1/aexjs/apex.navigation.html
Since you're trying to open a separate page, you probably want to use apex.navigation.dialog, which is what APEX automatically uses when opening modal pages from reports, buttons, etc.
However, as noted in the doc, the URL for the navigation must be generated server-side for security purposes. You need a dynamic URL (one not known when the page renders), so you'll need a workaround to generate it. Once you have the URL, navigating to it is easy. So how do you get the URL? Ajax.
Create an Ajax process to generate the URL
Under the processing tab of the report/grid page, right-click Ajax Callback and select Create Process.
Set Name to GET_FORM_URL.
Set PL/SQL code to the following
code:
declare
l_url varchar2(512);
begin
l_url := apex_page.get_url(
p_application => :APP_ID,
p_page => 3,
p_items => 'P3_ITEM_NAME',
p_values => apex_application.g_x01
);
apex_json.open_object();
apex_json.write('url', l_url);
apex_json.close_object();
end;
Note that I'm using apex_item.get_url to get the URL, this is an alternative to apex_util.prepare_url. I'm also using apex_json to emit JSON for the response to the client.
Also, the reference to apex_application.g_x01 is important, as this will contain the selected values from the calling page. You'll see how this was set in the next step.
Open the URL with JavaScript
Enter the following code in the Function and Global Variable Declaration attribute of the calling page:
function openFormPage(ids) {
apex.server.process(
'GET_FORM_URL',
{
x01: ids.join(':')
},
{
success: function (data) {
var funcBody = data.url.replace(/^"javascript:/, '').replace(/\"$/,'');
new Function(funcBody).call(window);
},
error: function (jqXHR, textStatus, errorThrown) {
console.error(errorThrown);
// handle error
}
}
);
}
In this case, I'm using apex.server.process to call the server-side PL/SQL process. Note that I'm passing the value of ids.join(':') to x01. That value will become accessible in the PL/SQL code as apex_application.g_x01. You can use additional items, or you can pass a colon-delimited string of values to just one item (as I'm doing).
The URL that's returned to the client will not be a standard URL, it will be a JavaScript snippet that includes the URL. You'll need to remove the leading and trailing parts and use what's left to generate a dynamic function in JavaScript.
This is generally frowned upon, but I believe it's safe enough in this context since I know I can trust that the response from the process call is not malicious JavaScript code.
Add a security check!!!
Because you're creating a dynamic way to generate URLs to open page 3 (or whatever page you're targeting), you need to ensure that the modal page is protected. On that page, create a Before Header process that validates the value of P3_ITEM_NAME. If the user isn't supposed to be able to access those values, then throw an exception.
I'm developing an Oracle Application express (APEX 4.2) application.
One of the page controls (text box, title) have a "PL/SQL Expression" read-only condition:
:APP_PROJECT_READ_ONLY = 'YES'
:APP_PROJECT_READ_ONLY is an application item and it's set from a dynamic action on_load which fires on page load:
DECLARE
CURR_USER VARCHAR2(50);
BEGIN
IF :REQUEST = 'NEW' THEN
:APP_PROJECT_ID := 0;
:APP_PROJECT_READ_ONLY := 'NO';
ELSE
:APP_PROJECT_ID := :P2_ID;
SELECT OWNER INTO CURR_USER
FROM PROJECTS
WHERE ID = :APP_PROJECT_ID;
IF CURR_USER = :APP_USER THEN
:APP_PROJECT_READ_ONLY := 'NO';
ELSE
:APP_PROJECT_READ_ONLY := 'YES';
END IF;
END IF;
EXCEPTION WHEN NO_DATA_FOUND THEN
NULL;
END;
Checking session state shows that :APP_PROJECT_READ_ONLY's value is correct, but it doesn't seem to drive whether title is read only:
If I leave on_load's "page items to return" blank, then title is always editable.
However if I set it to title, then title will be always read-only and also it's source control doesn't work, it's leaved empty (in previous case it was working correctly).
How can I fix it?
Your problem is chronology.
The page renders, conditions evaluated, then you calculate your application item on the browser's page load.
Move your code into a computation, perhaps before regions, hence done as part of page render.
REQUEST values are organically only available in page processing, so unless you're explicitly setting that, it may be something to look out for.
You should also consider using declarative actions, where possible.
www.grassroots-oracle.com/2013/05/performance-of-apex-conditions.html