Oracle Apex interactive grid i dynamiczne sumowanie kolum

Czasami w projekcie, w widoku inteactive grid mamy potrzebę dynamicznego podsumowania wartości wszystkich wierszy w kolumnie (np. by obliczyć wartość faktury) lub wykonania operacji przeliczenia wszystkich składników dokumentu jeśli zmienimy którekolwiek pole w formularzu. Gdyby była to wspomniana wcześniej faktura to np. po zmienie lilości w którymkolwiek wierszu potrzebowalibyśmy obliczyć wartość total tego wiersza na nowo i dokonać wyliczenia podatku, sumy netto i brutto całej faktury.

API apex.region zapewnia pojedynczy interfejs dla wszystkich popularnych funkcji Application Express związanych z regionami. Ten interfejs API zwraca obiekt regionu Application Express, który jest używany do uzyskiwania dostępu do funkcji i właściwości związanych z regionem.

Za pomocą tego API (JavaScript) możemy odczytywać wartość pól i je modyfikować.

Opiszemy przykład który zademonstruje jak zliczyć wartość wszystkich wierszy kolumny i jak wyliczyć  wartość jednej z kolumn na podstawie wartości odczytanych z dwóch innych kolumn, dla każdego wiersza.

Tworzymy Dynamic Action kolumny.

Nasz przykład zademonstruje jak po zmianie ceny wyliczy się suma netto dla linii i jednocześnie przeliczy się wartość całej faktury. Rozpoczynamy od utworzenia "item" => "Number field" które w którym kolwiek regionie strony.  Załóżmy że nazywa sie P20_NET_TOTAL. To pole będzie pełnić dwie funkcje; spowoduje wykonanie operacji zapisu co uaktualni wartość w polu które jest naszym celem (patrz problem z brakiem aktualizacji wartości) oraz wyswietli sume netto dla wszystkich wierszy kolumny "NET_TOTAL"

Następnie tworzymy Dynamic Action dla kolumny "NET_PRICE". "Event type" = change. Tworzymy dwie TRUE actions. Pierwsza akcja to "Set value" i PL/SQL Expression. W polu wyrażenia wpisujemy ":NET_PRICE". Druga TRUE action to "Execute JavaScript code". Treść kody wygląda następująco:


 var model = apex.region("invoice_details").widget().interactiveGrid("getViews", "grid").model;
 var o_amt, o_totamt = 0;
 col_quantity = model.getFieldKey("ARTICLE_QUANTITY");
 col_netprice = model.getFieldKey("NET_PRICE");

 model.forEach(function(igrow) {
    //Update total
    var net_total;
    net_total = parseInt(igrow[col_quantity]) * parseFloat(igrow[col_netprice], 10);
    if (isFinite(net_total)){
      model.setValue(igrow, "NET_TOTAL", net_total.toFixed(2));
    }else{
      model.setValue(igrow, "NET_TOTAL", '');
    }
    
//Take to total only if product type is...
    var product_type =  model.getValue(igrow, "PRODUCT_TYPE" );
    if(product_type == "oryginal"){
     //net sum:
     o_amt = parseFloat(igrow[col_netprice], 10);
      if (!isNaN(o_amt)) {
         o_totamt += o_amt;
      }
    }else{
     //net sum:
     s_amt = parseFloat(igrow[col_netprice], 10);
      if (!isNaN(s_amt)) {
         s_totamt += s_amt;
      }
    }
//Write sum to
  apex.item("P20_NET_TOTAL").setValue(o_totamt.toFixed(2));
}

Możemy też zawrzeć ten kod w funkcji, funkcję umieścić w pliku i wgrać do Static Files. Następnie link do pliku wklejamy we właściwościach strony "JavaScript" => "File URLs" - np. #APP_IMAGES#recalculate_all.js. W oknie DA, JavaScript, Code wpisujemy "recalculate_all();"

function recalculate_all(){
 var model =...

..

}

Jeśli chcemy kod wykonwał się także po "focus lost" i podobnie, musimy utoworzyć DA dla każdego z tych zachowań. Przeniesienie kodu do zewnetrznego pliku JS daje nam możliwość obejscia ograniczeń ilości znaków (4000?) i daje większą elastyczność - możemy odwoływać się do tej samej funkcji bez powielania kodu.