Dynamische Linkerzeugung

Viele von euch kennen bestimmt das Problem, das ihr einen Button auf einer Seite habt, der über einen Page-Redirect eine andere Seite in eurer Applikation aufruft. Sollten sich die Parameter des Links nach dem Rendern ändern, müsst ihr nun den Link neu erzeugen. Im Netz gibt es viele Blogs und Forumsbeiträge über dieses Problem. Ich habe mir gedacht, das muss doch irgendwie viel einfacher gehen.

Das eigentliche Problem liegt darin, das APEX die URL beim Rendern der jeweiligen Seite baut. Sollte sich nun mittels AJAX irgendeine Komponente auf der Seite ändern, deren Inhalt Teil des jeweiligen Links ist, wird der Link nicht automatisch neu generiert. Mein erster Gedanke war, das können wir doch mittels JET / Knockout lösen. Hier würde ich einfach ein Binding erzeugen, welches den Link immer neu erzeugt, sobald sich etwas ändert. Nach einer kurzen Unterredung mit einem Kollegen, war aber klar, das es zu viel Overhead wäre, einen Link immer neu zu errechnen, obwohl ich diesen vielleicht nicht brauche.

Also lassen wir das mit dem Binding und ermitteln den Link, in dem Moment, wenn wir ihn brauchen mittels JQuery.  Folgender Plan: Beim Laden der Seite werden alle Links, der Buttons mit der Klasse „dyn-links“ gelesen und der hinterlegte Link geparst und zwischengespeichert. Der eigentliche Click-Handler wird durch einen neuen „dynLinkRedirect()“ ersetzt. Hier wird nun, sobald der Benutzer auf den Button klickt, der eigentliche Link erzeugt und die jeweilige Navigation ausgeführt. Da bei einem Button, der nicht Teil eines Reports ist, keine Ersetzung der Substitutionsmarkierungen „#P1_CUSTOMER_ID#“ stattfindet, kann dieser Wert beim Laden gelesen werden und später, beim Klick auch wieder neu ermittelt werden.

Zuerst legen wir auf der Page 0  (GlobalPage) eine neue Dynamic Actioin. Diese soll JavaScript Code ausführen.

Im Code wird ein Array „dynLinkTarget“ angelegt. Hier werden alle Links der zu bearbeitenden Buttons auf der jeweiligen Seite gespeichert. Dabei wird in der Funktion „dynLinkBuild“ diese Array gefüllt. Es werden die Links aller Buttons geparsed und in Teilen gespeichert. Die Funktion „dynLinkRedirect“ wird hierbei als neuer Handler der geparsten Button benutzt. Dabei wird der zum passenden Button, der gerade geklickt wurde, Link neu duch einen AJAX-Request ermittelt und ausgeführt.

// this array holds all linke on this page which need to be stored
var dynLinkTarget = [];

// build an run link based on stored and parsed content
dynLinkRedirect = function(){
let myID = this.id;

dynLinkTarget.forEach(function(dynLinkObject){
if (dynLinkObject.id == myID) {
//console.log(dynLinkObject);

// Call ServerProcess and get URL
 apex.server.process( "APP_DYN_LINK", {
x01: dynLinkObject.targetPage,
x02: dynLinkObject.clearPage,
x03: dynLinkObject.paramTargets,
f01: dynLinkObject.paramSources,
pageItems: "#" + dynLinkObject.paramSources.join(", #")

}, {
success: function(data) {
console.log('redirecting to : ' + data.v_result);
apex.navigation.redirect(data.v_result);
}
} );

}
});

};

// this function retrieves and parses all relevant info for storing
dynLinkBuild = function() {
let regExp = /\=([^)]+)\'/;

// loop through buttons
$(".dyn-link").each(function(index){
let onClickAttr = $(this).attr("onclick");
let matches = regExp.exec(onClickAttr);

if (matches.length) {
// parse and store to array
let paramArray = matches[1].split(":");

dynLinkTarget.push({
id: this.id,
targetPage: paramArray[1],
clearPage:  paramArray[5],
paramTargets: paramArray[6],
paramSources: paramArray[7].replace(/\#/g,"").split(",")
});

// remove onClick handler
$(this).prop('onclick', null).off('click');

// set onClick handler
$(this).click(dynLinkRedirect);

} else {
console.log("No Link found");
}

});

/*for (var i=0; i<dynLinkTarget.length; i++){
console.log(dynLinkTarget[i]);
}*/
};

dynLinkBuild();

Als nächstes legen wir einen Application Prozess „APP_DYN_LINK“ an. Diese wird als AJAX-Callback benötigt, um aus der Javascript-Welt heraus den benötigten Link zu errechnen.

Dabei werden die einzelnen Komponenten aus dem Array erwartet und als Link wieder zusammen gefügt. Da beim Aufruf des AJAX-Calls die benutzten Pageitems submitted wurden, stehen sie uns hier über die V-Funktion auch zur Verfügung.

Declare
v_target_page varchar2(10)            := apex_application.g_x01; -- page to navigate to
v_clear_pages varchar2(100)           := apex_application.g_x02; -- clear items or pages
v_keys        varchar2(1000)          := apex_application.g_x03; -- list of pageitems to set
v_value_arr   wwv_flow_global.vc_arr2 := apex_application.g_f01; -- array of pageitems to get

v_values      varchar2(1000);
v_result      varchar2(4000);
Begin
-- loop throug page_items and genarate value list
for i in 1 .. v_value_arr.count loop
v_values :=  v(v_value_arr(i))||',';
end loop;
v_values := substr(v_values, 1, length(v_values)-1);

-- build URL
v_result := apex_util.prepare_url('f?p='||v('APP_ID')||':'||
v_target_page||':'||
v('APP_SESSION')||':'||
':'||
'NO:'||
v_clear_pages||':'||
v_keys||':'||
v_values
);

-- let's debug some vars
apex_debug.message('v_target_page: %1', v_target_page);
apex_debug.message('v_clear_pages: %1', v_clear_pages);
apex_debug.message('v_keys: %1', v_keys);
apex_debug.message('v_values: %1', v_values);

-- and pass result a json
apex_json.open_object;
apex_json.write('success', true);
apex_json.write('v_result', v_result);
apex_json.close_object;
End;

Das einzige was ihr nun noch machen müsst, ist dem jeweiligen Button die Klasse dyn-link zu verpassen und die entsprechenden dynamischen Pageitems innerhalb der Linkerstellung ausnahmsweise mit Rauten zu maskieren.

Fertig, probiert es aus.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Ich akzeptiere