Skip to main content

APEX page item computations and processes under control

I

I was experimenting lately with page items and how to setup APEX page (preprocessing section) in more cleaner, reusable and generic way. I also wanted to move the logic from APEX to PL/SQL packages to fulfil my MVC vision (to keep as much as possible code in PL/SQL, not in APEX). So I made this up.

For every page in application I have created a package, "P0" for page zero, "P100" for page 100... For 100 pages I would create 100 packages, but that is still better then have the logic scattered on individual pages. And most of the times I have to create packages anyway because I need a place where to store form/grid handlers and page related logic. Then I have created INIT_DEFAULTS procedures in each of these packages. And in this procedure I setup page items and run the pre-rendering processes. Since we are talking about packages, I can reuse other procedures and function and limit the amount of copy pasted code.

I use my wrapper around these session state calls (so I can check if these items exists for example), but the typical INIT_BLOCK on non zero pages would look like this:

    PROCEDURE init_defaults /* in P# package(s) */
    AS
    BEGIN
    	-- logger
        NULL;

        -- call page related processes
        NULL;

        -- set page items
        APEX_UTIL.SET_SESSION_STATE('P100_ITEM1_NAME', 'ITEM1_VALUE', FALSE);
        APEX_UTIL.SET_SESSION_STATE('P100_ITEM2_NAME', 'ITEM2_VALUE', FALSE);
    EXCEPTION
    WHEN OTHERS THEN
    	-- logger
        RAISE;
    END;


I was tired of creating INIT_DEFAULT process on every APEX page and referencing correct procedure there. Of course there is a better way. So create INIT_DEFAULTS procedure in P0 package (since I store other shared things there). The code checks if there is a procedure in matching package and if yes, then it will execute this:

    PROCEDURE init_defaults /* in P0 package /
    AS
        v_package_name      user_procedures.object_name%TYPE;
        v_procedure_name    user_procedures.procedure_name%TYPE;
    BEGIN
        -- initialize page 0 items (if needed)
        NULL;

        -- find init block for specific/current page
        BEGIN
            SELECT
                p.object_name,
                p.procedure_name
            INTO
                v_package_name,
                v_procedure_name
            FROM user_procedures p
            WHERE p.object_name         = 'P' || TO_CHAR(APEX_APPLICATION.G_FLOW_STEP_ID)
                AND p.procedure_name    = 'INIT_DEFAULTS';
            --
            IF v_procedure_name IS NOT NULL THEN
                EXECUTE IMMEDIATE
                    'BEGIN ' || v_package_name || '.' || v_procedure_name || '(); END;';
            END IF;
        EXCEPTION
        WHEN NO_DATA_FOUND THEN
            NULL;
        END;
    EXCEPTION
    WHEN OTHERS THEN
        -- logger
        RAISE;
    END;


So now I don't need to create any preprocessing on these 100 pages, I just need to put this into new application process INIT_DEFAULTS and run it on load before headers:

p0.init_defaults();

Done. What do you think?

One additional note, I also have views starting with "P#" so when I look at the objects in schema, I immediately know that these views are used on that page. And this works great for me.


Comments