Monday, August 5, 2019

Integrando Oracle Jet 7.1 Gantt + Data dinámica + Oracle APEX 19.1 + AJAX

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






Share:

3 comments:

  1. Hi Angel,
    Great post, very informative. I tried to follow through your instructions but having issues rendering the gantt in the static content region. All i see is the CSS code. Do you know if this works on APEX 18.2?

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Hi,
    On more example for sunburst please

    ReplyDelete

Subscribe to my Newsletter

Acerca de mi:

img

Ing. Angel O. Flores Torres, soy Ingeniero de Sistemas e Ingeniero de Aplicaciones Oracle Apex, he trabajado con Oracle Apex 5 y 5.1 desde el 2017, En los ultimos años he desarrollado habilidades en CSS, JavaScript, Jquery y PlSql , I specialize in Oracle APEX (Oracle Application Express )

Followers

Popular Posts