Kamis, 26 September 2013

Implementasi jQuery Sortable pada APEX Classic Report (AJAX)

Sebelumnya silahkan pelajari UI dokumentasi disini dan demonya disini.
Contoh kasus kita terapkan pada tabel EMP.
Kita bisa lakukan dengan memakai konsep AJAX atau Dynamic Action.

Langkah implementasi dalam APEX untuk AJAX sbb:

  • Tambahkan kolom ORDER_BY number(3);
  • Buatlah report dengan memakai collection contoh nama collection : 'R_SORT'
    1. Buat process pl/sql before header
    2. declare
       l_col_name varchar2(100):='R_SORT';
       l_query varchar2(4000);
      begin
        l_query:='select a.EMPNO,a.ENAME,a.JOB,a.MGR,a.HIREDATE,a.SAL,a.COMM,a.DEPTNO,a.ORDER_BY from emp a order by a.ORDER_BY';
       if not APEX_COLLECTION.COLLECTION_EXISTS(p_collection_name => l_col_name) then
        APEX_COLLECTION.CREATE_COLLECTION_FROM_QUERY_B(
                p_collection_name => l_col_name
              , p_query => l_query
            );
       end if;
      end;
            
    3. Buat calssic report dengan query
    4. SELECT coll.seq_id No
           , coll.c001 empno
           , coll.c002 ename
           , coll.c003 job
           , coll.c004 mgr
           , coll.c005 hiredate
           , coll.c006 comm
           , coll.c007 sal
           , coll.c008 deptno
      FROM APEX_collections coll
      WHERE coll.collection_name = 'R_SORT'
      ORDER BY to_number(coll.seq_id)
          
  • Buatlah Application Process : REORDER dengan process point : on demand
  • declare
      -- ajax call to move a seq_id collection
     l_seq     number(5);
     l_seq_id     number(5); 
     l_old        number(5); 
     l_new        number(5); 
     l_counter    number(5);
     l_abscounter    number(5);
    begin
     l_seq_id    := to_number(wwv_flow.g_x01);
     l_counter   := to_number(wwv_flow.g_x02);
     l_abscounter  :=abs(l_counter);
          if l_counter < 0 then
          -- Move UP
            for i in 1 .. l_abscounter loop
            apex_collection.move_member_down(
                p_collection_name => 'R_SORT'
              , p_seq             => l_seq_id
            );     
              l_seq_id := l_seq_id - 1;
            end loop;
          elsif l_counter > 0 then
          -- Move DOWN
            for i in 1 .. l_abscounter loop
              apex_collection.move_member_up(
                  p_collection_name => 'R_SORT'
                , p_seq             => l_seq_id
              );        
              l_seq_id := l_seq_id + 1;        
            end loop;      
          end if;    
    htp.prn('success');
    end;
      
  • Buatlah sebuah function jQuery untuk setup preparation Sortable dan AJAX memanggil application process REORDER:
  • function setSortable() {
        var vStart = 0;
        var vEnd = 0;
        var vCounter = 0;
        var vSeqId = 0;
        var sortRegion = '#report_RSORT_1 .report-standard tbody:first'; // selector tergantung report yg anda pakai
        $(sortRegion).sortable({
           cursor      : 'wait',
           distance    : 15,
           revert      : 500,
           start       : function (event, ui) {
            vStart = Number(ui.item.index()) + 1;
            vSeqId = Number($(this).find('td[headers="NO"]')[ui.item.index()].innerHTML);},
           stop        : function (event, ui) {
            vEnd = Number(ui.item.index()) + 1;
            vCounter = vEnd - vStart;
            apex.server.process("REORDER"
                  , { x01: vSeqId, x02: vCounter }
                  , {
                      dataType: 'text'
                      , success: function (pData) {
                      if (pData != 'success') {
                               alert(pData);
                       }
                      else {
                         // refresh report id tergantung report yg anda pakai
                        $('#report_28558823308938595811_catch').trigger('apexrefresh');
                      }
            }
           }
        );
        }
       });
       $(sortRegion).disableSelection();
    }
    
  • tambahkan function setup preparation Sortable pada  bagian on load : setSortable();
  • Buatlah DA after refresh pada report sortable execute javascript : setSortable();
Liat demo hasilnya disini.

Rabu, 05 Juni 2013

Beberapa hal yang harus diperhatikan saat memakai apex_mail

Salah satu API yang disediakan oleh APEX adalah send email melalui APEX_MAIL. Dari contoh API kita bisa mengirimkan email baik text atau format html. Contoh :
DECLARE
 l_body CLOB;
 l_body_html CLOB;
BEGIN
 l_body := 'To view the content of this message, please use an HTML enabled mail client.'||utl_tcp.crlf;
 l_body_html := '<html>
                 <head>
                 <style type="text/css">
                 body{font-family: Arial, Helvetica, sans-serif;
                 font-size:10pt;
                 margin:30px;
                 background-color:#ffffff;}
                 span.sig{font-style:italic;
                 font-weight:bold;
                 color:#811919;}
                 </style>
                 </head>
                 <body>'||utl_tcp.crlf;
 l_body_html := l_body_html ||'<p>Thank you for your interest in the <strong>APEX_MAIL</strong> package.</p>'||utl_tcp.crlf;
 l_body_html := l_body_html ||' Sincerely,<br />'||utl_tcp.crlf;
 l_body_html := l_body_html ||' <span class="sig">The APEX Dev Team</span><br/>'||utl_tcp.crlf;
 l_body_html := l_body_html ||'</body></html>';
 apex_mail.send( p_to => 'some_user@somewhere.com', -- change to your email address
                 p_from => 'some_sender@somewhere.com', -- change to a real senders email address
                 p_body => l_body,
                 p_body_html => l_body_html,
                 p_subj => 'APEX_MAIL Package - HTML formatted message');
END;
/

Beberapa error yang muncul seperti :

  • PLS-00307: too many declarations of 'SEND'
  • Hal ini terjadi jika type yang tidak sama anda berikan pada value p_body dan p_body_html pastikan jika memakai varchar2 semua atau clob semua

  • ORA-06502: PL/SQL: numeric or value error
  • Hal ini terjadi kita memakai clob dengan data memakai concate '||'yang melebihi kapasitas varchar2(32767)

    Solusinya kita dapat mengganti dengan tipe data CLOB dengan memakai DBMS_LOB.APPEND, pada contoh diatas dapat dimodifikasi dengan cara

    DECLARE
     l_body CLOB;
     l_body_html CLOB;
    BEGIN
     l_body := 'To view the content of this message, please use an HTML enabled mail client.'||utl_tcp.crlf;
     dbms_lob.createtemporary (l_body_html,true);
     DBMS_LOB.append (l_body_html,'<html>
                     <head>
                     <style type="text/css">
                     body{font-family: Arial, Helvetica, sans-serif;
                     font-size:10pt;
                     margin:30px;
                     background-color:#ffffff;}
                     span.sig{font-style:italic;
                     font-weight:bold;
                     color:#811919;}
                     </style>
                     </head>
                     <body>');
     DBMS_LOB.append (l_body_html,'<p>Thank you for your interest in the <strong>APEX_MAIL</strong> package.</p>');
     DBMS_LOB.append (l_body_html,' Sincerely,<br />');
     DBMS_LOB.append (l_body_html,' <span class="sig">The APEX Dev Team</span><br/>');
     DBMS_LOB.append (l_body_html,'</body></html>');
     apex_mail.send(p_to => 'some_user@somewhere.com', -- change to your email address
                    p_from => 'some_sender@somewhere.com', -- change to a real senders email address
                    p_body => l_body,
                    p_body_html => l_body_html,
                    p_subj => 'APEX_MAIL Package - HTML formatted message');
     dbms_lob.freetemporary (l_body_html);  
    END;
    /
    

Selasa, 14 Mei 2013

Multiple Interactive Report with Synchronize Link

Beberapa pertanyaan tentang bagaimana memanipulasi interactive report (IR) dalam satu page sambil menunggu APEX 5. kita bisa lakukan dengan cara berikut.
Contoh kasus kita akan membuat sebuah 3 IR dalam satu page.

  • Page 27 adalah IR1 (DEMO_CUSTOMERS).
  • Page 29 adalah IR2 (DEMO_ORDERS).
  • Page 30 adalah IR3 (DEMO_ORDERS).

Pada page 27 buatlah 3 region seperti gambar berikut :

  • Region IR 1 : IR report dengan link: redirect ke page 27 dengan ngisi item P27_CUSTOMER_ID dengan value #CUSTOMER_ID# dengan request REDIR
  • Region IR 2 : dengan subregion Frame 2.
    • Bagian header
    • <iframe src="f?p=&APP_ID.:29:&SESSION."
            style="width:500px;height:500px"
            name="details"
            scrolling="no" marginwidth="0" marginheight="0"
            frameborder="0" vspace="0" hspace="0" >
      
    • Bagian footer
    • </iframe>
      
  • Region IR 3 : dengan subregion Frame 3.
    • Bagian header
    • <iframe src="f?p=&APP_ID.:30:&SESSION."
            style="width:500px;height:500px"
            name="details1"
            scrolling="no" marginwidth="0" marginheight="0"
            frameborder="0" vspace="0" hspace="0" >
      
    • Bagian footer
    • </iframe>
      

Lalu pada page 29 dan 30 buatlah IR dengan hidden item P29_CUSTOMER_ID dan P30_CUSTOMER_ID dengan query report:
select ORDER_ID, CUSTOMER_ID, ORDER_TOTAL, ORDER_TIMESTAMP
from DEMO_ORDERS
where customer_id=:P29_CUSTOMER_ID

Lalu langkah terakhir pada page 27 buatlah sebuah dynamic action
  • Event:Page Load
  • Condition: Request=Expression1 dengan Expression 1 =REDIR
  • True Actions : Execute javascript Code
  • code :
  • top.frames['details'].location.href = 'f?p=&APP_ID.:29:&SESSION.::&DEBUG.::P29_CUSTOMER_ID:&P27_CUSTOMER_ID.';top.frames['details1'].location.href = 'f?p=&APP_ID.:30:&SESSION.::&DEBUG.::P30_CUSTOMER_ID:&P27_CUSTOMER_ID.';
    

Demo aplikasi bisa lihat disini.

Rabu, 10 April 2013

Checkbox heading on report for check all / uncheck all

Untuk implementasi checkbox heading seperti layaknya ketika anda membuat tabular form dapat di-implementasikan dalam dua cara yaitu:
  1. Classic Report
  2. <input type="checkbox" onclick="$f_CheckFirstColumn(this);" >
    
  3. Interactive Report
  4. Cara dari Jeffrey Kemp

Jumat, 05 April 2013

The macro cannot be found or has been disabled

Tiba-tiba saja setelah lama gak buka BI publisher word template jadi gak bisa login ke dalam BI Publisher dengan symptom error : "The macro cannot be found or has been disabled".
Untung ada mbah gugel. anda bisa coba resep dari http://damir-vadas.blogspot.com/2011/02/macro-cannot-be-found-or-has-been.html. Terbukti manjur kekeke.

Sabtu, 30 Maret 2013

Merubah cookie APP_USER secara permanen

Cookie APP_USER adalah sebuah penampung yang dibuat APEX untuk menyimpan nama user Aunthenticated. contoh username kita entry lutfi hedir. Lalu cookies tersebut bisa kita ubah didalam aplikasi menjadi lutfi.hedir dengan cara membuat sebuah proses dengan block seperti ini.
begin
--set user menjadi nama tertentu cara 1
apex_custom_auth.set_user('lutfi.hedir');
--set user menjadi nama tertentu cara 2
wwv_flow.g_user := 'lutfi.hedir';
end;

Yang harus diperhatikan adalah dimana akan dijalankan code tersebut. Jika anda tidak ingin secara permanen maka dapat dilakukan di proses page on load before header atau tempat lain sesuai keinginan. Namun jika ingin merubah secara permanen maka satu-satunya cara harus di lakukan pada Post-Authentication Procedure Name. Karena jika dilakukan diluar itu maka APP_USER akan tetap seperti USERNAME dimana kita entry pada saat login. meskipun kita lakukan proses di application proses on load before header, tetap APP_USER tidak berubah yang berubah disaat proses render saja, tapi jika digunakan dalam proses authorization APP_USER kembali seperti semula, atau jika digunakan dalam database trigger dengan memanggil v('APP_USER') maka kembali APP_USER akan dikenali sebagai lutfi hedir bukan lutfi.hedir.
Jadi anda harus buat sebuah procedure dalam database contoh my_post_login dengan code sbb:
create or replace procedure my_post_login is 
 begin 
   apex_custom_auth.set_user('lutfi.hedir'); 
 end my_post_login;

lalu gunakan my_post_login dalam Post-Authentication Procedure Name. Selamat mencoba
Sumber : Oracle APEX Forum

Rabu, 27 Maret 2013

Delete multiple file on APEX metadata

Untuk keperluan delete file yang ada di aplikasi APEX, APEX telah menyediakan tool untuk melakukan delete file, cuma masih harus satu persatu. jadi kalau kita ingin melakukan banyak file itu yang jadi masalah.

Namun di dalam apex sendiri telah diberikan script untuk melakukan delete metadata tsb contoh saat kita ingin menghapus image "xxx.jpg" maka scriptnya adalah
begin
    wwv_flow_api.create_or_remove_file( 
        p_location => 'APPLICATION',
        p_name     => 'xxx.jpg',
        p_mode     => 'REMOVE',
        p_type     => 'IMAGE');
end;
/

Yang perlu diperhatikan adalah p_type bisa 'IMAGE','CSS'atau 'STATIC'. jadi untuk hapus secara banyak contoh satu WS maka kita harus modifikasi seperti ini. contoh dibawah adalah saya ingin menghapus seluruh image yang tersimpan dalam WS='TEST'.

declare
 v_id number;
 v_ws varchar2(100):='TEST';
begin
--- cari workspace ID
select workspace_id into v_id
from apex_workspaces
where WORKSPACE=upper(v_ws);
---set security supaya bisa di exsekusi diluar apex 
wwv_flow_api.set_security_group_id(v_id);
---cursor 
FOR x IN (select *
from APEX_WORKSPACE_FILES
where MIME_TYPE like 'image/%') LOOP
    wwv_flow_api.create_or_remove_file( 
        p_location => 'WORKSPACE',
        p_name     => x.FILE_NAME,
        p_mode     => 'REMOVE',
        p_type     => 'IMAGE');
END LOOP;
commit;
end;
/