En este post integraremos la actual versión de Oracle JET 7.1 en Oracle APEX y usaremos AJAX para cargar la información de forma dinámica.
Demo
Descarga App:
GDrive
Para este ejemplo usaremos el control
Gantt del CookBook de JET
En la hoja creamos una variable que será nuestro enlace de la data.
Agregamos la referencia de CSS
#JET_CSS_DIRECTORY#/alta/oj-alta-notag-min.css
Agregamos la librería de requireJS
APEX_JAVASCRIPT.add_requirejs();
En el page load creamos dos acciones dinámicas, en una cargamos las librerías de JET 7.1
requirejs.config({
"baseUrl": "https://static.oracle.com/cdn/jet/v7.1.0",
// Path mappings for the logical module names
paths: {
'knockout': '3rdparty/knockout/knockout-3.5.0',
'jquery': '3rdparty/jquery/jquery-3.4.1.min',
'jqueryui-amd': '3rdparty/jquery/jqueryui-amd-1.12.1.min',
'promise': '3rdparty/es6-promise/es6-promise.min',
'hammerjs': '3rdparty/hammer/hammer-2.0.8.min',
'ojdnd': '3rdparty/dnd-polyfill/dnd-polyfill-1.0.0.min',
'ojs': 'default/js/min',
'ojL10n': 'default/js/ojL10n',
'ojtranslations': 'default/js/resources',
'text': '3rdparty/require/text',
'signals': '3rdparty/js-signals/signals.min',
'customElements': '3rdparty/webcomponents/custom-elements.min',
'proj4': '3rdparty/proj4js/dist/proj4',
'css': '3rdparty/require-css/css.min',
'touchr': '3rdparty/touchr/touchr'
},
// Shim configurations for modules that do not expose AMD
shim: {
'jquery': {
exports: ['jQuery', '$']
}
}
});
Y en otra acción dinámica el código del ViewModel, el código fue extraído de la guía del cookbook de Oracle JET.
Aquí se han modificado los siguientes puntos:
-- La función recibe un parámetro que es la data para usar en el Gantt
function ViewModel(dataArray)
-- El construcctor recibe el parametro de la data.
this.dataProvider = new ArrayDataProvider(dataArray, {keyAttributes: 'id'});
-- Para los path de las images se estan usando link de images online
this.rowLabelImagePath = { 'Flag1' ....
-- dataArray se inicializa como:
dataArray = ko.observableArray([]);
Código ViewModel
require(['knockout', 'ojs/ojbootstrap', 'ojs/ojarraydataprovider', 'ojs/ojknockout', 'ojs/ojgantt'],
function(ko, Bootstrap, ArrayDataProvider)
{
function ViewModel(dataArray)
{
this.dataProvider = new ArrayDataProvider(dataArray, {keyAttributes: 'id'});
this.projectStartDate = new Date("Jan 1, 2019");
this.projectEndDate = new Date("Dec 31, 2019");
this.currentDateString = "Apr 15, 2019";
this.currentDate = new Date(this.currentDateString);
// set viewport to center around the reference object
var month = 1000 * 60 * 60 * 24 * 30;
this.viewportStart = new Date(Math.max(this.projectStartDate.getTime(), this.currentDate.getTime() - 3*month));
this.viewportEnd = new Date(Math.min(this.projectEndDate.getTime(), this.currentDate.getTime() + 3*month));
// Helper function to get appropriate row label image x position depending on document reading direction
this.getRowImageX = function() {
var dir = document.documentElement.getAttribute("dir");
return dir === 'ltr' ? '0' : '0';
};
// Helper function to get appropriate row label text x position depending on document reading direction
this.getRowTextX = function() {
var dir = document.documentElement.getAttribute("dir");
return dir === 'ltr' ? '30' : '25';
};
this.getRowTextAnchor = function() {
var dir = document.documentElement.getAttribute("dir");
var userAgent = navigator.userAgent.toLowerCase();
var isIE = userAgent.indexOf('trident') != -1 || userAgent.indexOf('msie') != -1 || userAgent.indexOf('edge') != -1;
// Unlike other browsers, IE11 and Edge treats left side of svg text as start in RTL,
// so set text-anchor to end to achieve consistent behavior
return dir === 'rtl' && isIE ? 'end' : 'start';
};
this.rowLabelImagePath = {
'Flag1': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//pe.png',
'Flag2': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//pw.png',
'Flag3': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//aq.png',
'Flag4': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//bg.png',
'Flag5': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//bl.png',
'Flag6': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//ch.png',
'Flag7': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//es.png',
'Flag8': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//gg.png',
'Flag9': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//id.png',
'Flag10': 'https://raw.githubusercontent.com/stefangabos/world_countries/master/flags/24x24//lt.png',
};
}
Bootstrap.whenDocumentReady().then(
function()
{
dataArray = ko.observableArray([]);
ko.applyBindings(new ViewModel(dataArray), document.getElementById('gantt'));
}
);
}
);
Creamos una región estática y agregamos el CSS de la región Gantt
<div id="componentDemoContent" style="width: 1px; min-width: 100%;">
<oj-gantt id="gantt"
axis-position="bottom"
start="[[projectStartDate.toISOString()]]"
end="[[projectEndDate.toISOString()]]"
gridlines.horizontal="visible"
gridlines.vertical="visible"
major-axis.scale="months"
major-axis.zoom-order='["quarters", "months", "weeks", "days"]'
minor-axis.scale="weeks"
minor-axis.zoom-order='["quarters", "months", "weeks", "days"]'
row-axis.rendered="on"
selection-mode="single"
reference-objects='[[[{"value": currentDate.toISOString()}]]]'
viewport-start="[[viewportStart.toISOString()]]"
viewport-end="[[viewportEnd.toISOString()]]"
task-data="[[dataProvider]]"
:aria-label='[["Gantt Chart. Current date is " + currentDateString]]'
style="width:100%;height:500px">
<template slot="rowTemplate" data-oj-as="row">
<oj-gantt-row
label="[[row.id]]">
</oj-gantt-row>
</template>
<template slot="taskTemplate" data-oj-as="task">
<oj-gantt-task
row-id="[[task.data.resource]]"
start="[[task.data.begin]]"
end="[[task.data.finish]]"
label="[[task.data.name]]">
</oj-gantt-task>
</template>
<template slot="rowAxisLabelTemplate" data-oj-as="rowAxisLabel">
<svg style="overflow:visible">
<g>
<image
:xlink:href='[[rowLabelImagePath[rowAxisLabel.rowData.id.replace(" ", "")]]]'
xlink:href=""
:x="[[getRowImageX()]]"
width="24" height="24">
</image>
<text
:x="[[getRowTextX()]]"
y="16"
:text-anchor="[[getRowTextAnchor()]]">
<oj-bind-text value="[[rowAxisLabel.rowData.label]]"></oj-bind-text>
</text>
</g>
</svg>
</template>
</oj-gantt>
</div>
Creamos un botón y lo definimos con una acción dinámica que ejecutara un JavaScript, la cual es la llamada AJAX
apex.server.process("LOAD_DATA", {
},
{
success: function(pData) {
console.log(pData);
dataArray(pData);
}
}
); // apex process
Creamos nuestro AjaxCallback
Por motivos didáctivos estoy usando unos select dentro de un for para generar data de forma dinámica.
declare
l_begin_date date;
l_end_date date;
begin
apex_json.open_array();
-- for generate random data
for i in 1..20
loop
-- tasks 1
select TO_DATE(TRUNC(DBMS_RANDOM.VALUE(TO_CHAR(DATE '2019-01-01','J'),TO_CHAR(DATE '2019-12-31','J'))),'J' ) random_date
into l_begin_date
from dual;
select TO_DATE(TRUNC(DBMS_RANDOM.VALUE(TO_CHAR(l_begin_date,'J'),TO_CHAR(DATE '2019-12-31','J'))),'J' ) random_date
into l_end_date
from dual;
apex_json.open_object;
apex_json.write('id', 'task1-'||i);
apex_json.write('begin', l_begin_date );
apex_json.write('finish', l_end_date);
apex_json.write('name', 'Label 1-'||i);
apex_json.write('resource', 'Flag'||i);
apex_json.close_object;
-- tasks 2
select TO_DATE(TRUNC(DBMS_RANDOM.VALUE(TO_CHAR(DATE '2019-01-01','J'),TO_CHAR(DATE '2019-12-31','J'))),'J' ) random_date
into l_begin_date
from dual;
select TO_DATE(TRUNC(DBMS_RANDOM.VALUE(TO_CHAR(l_begin_date,'J'),TO_CHAR(DATE '2019-12-31','J'))),'J' ) random_date
into l_end_date
from dual;
apex_json.open_object;
apex_json.write('id', 'task1-'||i);
apex_json.write('begin', l_begin_date );
apex_json.write('finish', l_end_date);
apex_json.write('name', 'Label 1-'||i);
apex_json.write('resource', 'Flag'||i);
apex_json.close_object;
end loop;
apex_json.close_array();
end;
En el network la llamada ajax debe tener la siguiente estructura, la misma del ejemplo del cookbook.
Y finalmente el resultado