Delete all rows from business object using groovy in vbcs

Users can navigate to Business Objects ( BO ) -> Objects -> Select Object ( ex: Department or Employee ) -> Business Rules -> Object Function -> New Object Function

In Object function we can write groovy code to do operations

Groovy code to delete all rows in business object

The following code will fetch all the data from a particular BO and delete it.

def vo = newView('EmployeeBO')
vo.executeQuery()
while (vo.hasNext()) {
  def curRow = vo.next()
  curRow.remove()
}

We can write this code in a separate Business object object function and call it using rest API.

This will be useful in scenarios where we want to delete large amount of data. Instead of calling delete API for each BO we can call the above object function to delete multiple records in one API call.

We can also customize this code by adding query to vo like below

def vo = newView('EmployeeBO')
vo.appendViewCriteria("Salary between 50000 and 75000")
vo.executeQuery()
while (vo.hasNext()) {
  def curRow = vo.next()
  curRow.remove()
}

or by checking some logic using groovy like below

def vo = newView('EmployeeBO')
vo.executeQuery()
while (vo.hasNext()) {
  def curRow = vo.next()
  if ( curRow.Salary >= 5000 && curRow.Salary <= 75000 ) {
    curRow.remove()
  }
}

You can find more code on groovy capabilities from the following reference.

https://docs.oracle.com/en/cloud/paas/app-builder-cloud/visual-builder-groovy/groovy-tips-and-techniques.html#groovy-tips-and-techniques

How to make scroll bar thicker in vbcs table or gird

Update 01-Feb-2025 02:54 AM use this code instead

#employeetable > * {
  scrollbar-width: auto;
}

Based on the default redwood theme the table and grid scoll bar are very thin

User can update it by adding the following code in app.css in vbcs application.

#employeetable::-webkit-scrollbar-track {
  border-radius: 15px;
  background-color: #e9e9e9;
  border-radius: 15px;
}

#employeetable ::-webkit-scrollbar {
  width: 15px;
  height: 15px;
  background-color: #e9e9e9;
  border-radius: 15px;
}
#employeetable ::-webkit-scrollbar-thumb {
  width: 15px;
  height: 15px;
  border-radius: 15px;
  background-color: #7b7d7f;
}

width will increase the thickness of vertical scroll bar

height will increase the thickness of horizontal scroll bar.

Screenshot without additional css

Screenshot with additional css

Live application example ( hover on the application to view scroll bar ) :

Link to view application in new tab – https://khalil232.com/apps/ojet-apps/?ojr=thick-scrollbar

To show loading spinner in VBCS

Users can add the following html code in designer to add a loading spinner in vbcs.

On button click they can call component ( #loading-dialog ) and select open method.

Now loading dialog is shown, they do some action and after action is completed, they can call component ( #loading-dialog ) and select close method.

Code for loading dialog

<oj-dialog dialog-title="Loading" id="loading-dialog" cancel-behavior="none" class="">
    <div slot="body">
        <div class="oj-flex oj-sm-justify-content-center">
            <oj-progress-circle size="md" value="-1"></oj-progress-circle>
        </div>
    </div>
    <div slot="footer">
    </div>
</oj-dialog>

View live example in new page – https://khalil232.com/apps/ojet-apps/?ojr=loading-dialog

Commonly used Buttons in VBCS

Button is element for user to interact. On button click we can call some rest API or show some message.

<oj-button label="Download" >
</oj-button>

Link for viewing the buttons code with styles – https://khalil232.com/apps/ojet-apps/?ojr=button

Here are few buttons which I regularly use

Code for button with icon

<oj-button label="Download" >
    <span class="oj-ux-ico-download" slot="startIcon"></span>
</oj-button>

Toolbar buttons Add row, Edit Row, Delete Row buttons ( generally used above a table or for each loop )

<div class="oj-flex">
  <oj-toolbar chroming="solid" class="oj-flex-item oj-sm-12 oj-md-12">
    <oj-button label="Add" class="oj-button-sm">
      <span class="oj-ux-ico-plus" slot="startIcon"></span>
    </oj-button>
    <oj-button label="Edit" class="oj-button-sm">
      <span class="oj-ux-ico-edit" slot="startIcon"></span>
    </oj-button>
    <oj-button label="Delete" class="oj-button-sm">
      <span class="oj-ux-ico-trash" slot="startIcon"></span>
    </oj-button>
  </oj-toolbar>
</div>

Save and cancel button in dialog box

<oj-dialog dialog-title="Dialog" id="add-dialog" initial-visibility="show">
  <div slot="body">
    <div class="oj-flex">
      <div class="oj-flex-item oj-sm-12 oj-md-12">
        <oj-form-layout>
          <oj-input-text label-hint="Text"></oj-input-text>
        </oj-form-layout>
      </div>
    </div>
  </div>
  <div slot="footer">
    <oj-button label="Save" class="oj-button-sm" chroming="callToAction">
      <span class="oj-ux-ico-save" slot="startIcon"></span>
    </oj-button>
    <oj-button label="Cancel" class="oj-button-sm">
      <span class="oj-ux-ico-close" slot="startIcon"></span>
    </oj-button>
  </div>
</oj-dialog>

Close button ( for message only dialog box )

<oj-dialog dialog-title="Dialog" id="add-dialog" initial-visibility="show">
  <div slot="body">
    <div class="oj-flex">
      <div class="oj-flex-item oj-sm-12 oj-md-12">
        Form Submitted successfully.
      </div>
    </div>
  </div>
  <div slot="footer">
    <oj-button label="Close" class="oj-button-sm">
      <span class="oj-ux-ico-close" slot="startIcon"></span>
    </oj-button>
  </div>
</oj-dialog>

Inline action items of table ( to provide inline edit or inline delete or to view more details )

<div class="oj-flex">
  <oj-table scroll-policy="loadMoreOnScroll" class="oj-flex-item oj-sm-12 oj-md-12"
    data="[[$variables.employeeListSDP]]"
    columns='[{"headerText":"Id","field":"id"},{"headerText":"empNumber","field":"empNumber"},{"headerText":"empName","field":"empName"},{"headerText":"Action","field":"","template":"Action"}]'>
    <template slot="Action">
      <oj-button label="Edit" class="oj-button-sm">
        <span class="oj-ux-ico-edit" slot="startIcon"></span>
      </oj-button>
      <oj-button label="Delete" class="oj-button-sm">
        <span class="oj-ux-ico-trash" slot="startIcon"></span>
      </oj-button>
    </template>
  </oj-table>
</div>

For inline navigation to a different page give link instead of button

<div class="oj-flex">
  <oj-table scroll-policy="loadMoreOnScroll" class="oj-flex-item oj-sm-12 oj-md-12"
    data="[[$variables.employeeListSDP]]"
    columns='[{"headerText":"Id","field":"id"},{"headerText":"empNumber","field":"empNumber"},{"headerText":"empName","field":"empName"},{"headerText":"departmentNumber","field":"departmentNumber"},{"headerText":"departmentNumberObject","template":"department"}]'>
    <template slot="department">
      <oj-bind-if test="[[ $current.row.departmentNumberObject.count > 0 ]]">
        <a target="_blank" class="oj-link">
          <oj-bind-text value="[[$current.row.departmentNumberObject.items[0].name]]"></oj-bind-text>
        </a>
      </oj-bind-if>
    </template>
  </oj-table>
</div>

In Form Save Cancel buttons ( Don’t give reset here ) as forms could be long and accidently clicking will remove all data

<div class="oj-flex">
  <div class="oj-flex-item oj-sm-12 oj-md-4">
    <oj-form-layout class="oj-formlayout-full-width" direction="row" label-edge="inside" columns="2"   label-width="45%" user-assistance-density="compact">
      <oj-label-value colspan="2" label-edge="start">
        <oj-label for="name-input" slot="label">Name</oj-label>
        <oj-input-text id="name-input" slot="value" ></oj-input-text>
      </oj-label-value>
      <oj-label-value colspan="2" label-edge="start">
        <oj-label for="city-input" slot="label">City</oj-label>
        <oj-input-text id="city-input" slot="value" "></oj-input-text>
      </oj-label-value>
      <oj-button label="Save" class="oj-button-sm oj-button-full-width">
        <span class="oj-ux-ico-save" slot="startIcon"></span>
      </oj-button>
      <oj-button label="Cancel" class="oj-button-sm oj-button-full-width">
        <span class="oj-ux-ico-close" slot="startIcon"></span>
      </oj-button>
    </oj-form-layout>
  </div>
</div>

In Search ( Search, Reset, Cancel ) ( Reset should reset the form to how it is shown on page load )

<div class="oj-flex">
  <div class="oj-flex-item oj-sm-12 oj-md-4">
    <oj-form-layout class="oj-formlayout-full-width" direction="row" label-edge="inside"
      user-assistance-density="compact">
      <oj-label-value label-edge="start" label-width="35%">
        <oj-label for="name-input" slot="label">Name</oj-label>
        <oj-input-text id="name-input" slot="value"></oj-input-text>
      </oj-label-value>
      <oj-label-value label-edge="start" label-width="35%">
        <oj-label for="city-input" slot="label">City
        </oj-label>
        <oj-input-text id="city-input" slot="value" "></oj-input-text>
      </oj-label-value>
      <oj-button label=" Search" class="oj-button-sm" chroming="callToAction">
        <span class="oj-ux-ico-search" slot="startIcon"></span>
      </oj-button>
      <oj-button label="Reset" class="oj-button-sm">
        <span class="oj-ux-ico-reset-variable" slot="startIcon"></span>
      </oj-button>
    </oj-form-layout>
  </div>
</div>

Commonly used buttons and icons

Download - <span class="oj-ux-ico-download" ></span>
Submit -  <span class="oj-ux-ico-check" ></span>
Save  -  <span class="oj-ux-ico-save" ></span>
Reset  -  <span class="oj-ux-ico-reset-variable" ></span>
Clear -  <span class="oj-ux-ico-close" ></span>
Add  -  <span class="oj-ux-ico-plus" ></span>
Edit  -  <span class="oj-ux-ico-edit" ></span>
Delete -  <span class="oj-ux-ico-trash" ></span>
Upload -  <span class="oj-ux-ico-upload" ></span>
View -  <span class="oj-ux-ico-view" ></span>

Link for VBCS icons – https://static.oracle.com/cdn/fnd/gallery/2401.0.0/images/preview/index.html

How to download business object data as csv file in Visual Builder Cloud Service ( VBCS )

  1. Configure business object ( Ex: Country )
  2. Load data into business object
  3. Add a download button.
  4. On button click call rest API to fetch all data in business object using action chain.
  5. Create CSV content as blob
  6. Download blob file using JavaScript function

Sample BO data

IdCountry NameCountry Short Code
21AfghanistanAF
22AlbaniaAL
23AlgeriaDZ
24American SamoaAS
25AndorraAD
26AngolaAO
27AnguillaAI

HTML Code for button

<oj-button label="Download" on-oj-action="[[$listeners.buttonAction]]">
    <span class="oj-ux-ico-download" slot="startIcon"></span>
</oj-button>

Action chain code for calling Javascript function

{
  "description": "",
  "root": "callFunctionDownloadDataFromBO",
  "actions": {
    "callFunctionDownloadDataFromBO": {
      "module": "vb/action/builtin/callModuleFunctionAction",
      "parameters": {
        "module": "[[ $functions ]]",
        "functionName": "downloadDataFromBO"
      }
    }
  },
  "variables": {}
}

JavaScript function code to call business object rest API and download as csv

define(['vb/helpers/rest'], (Rest) => {
  'use strict';

  class PageModule {

    getLineItems(prevItems) {

      if (prevItems == undefined || prevItems == null) {
        prevItems = [];
      }

      let endpointurl = "businessObjects/getall_Country";
      let queryString = "id is not null";

      var pageModuleVar = this;
      return new Promise(function (resolve, reject) {

        var ep = Rest.get(endpointurl);
        ep.parameters({ 
        "q": queryString, 
        "onlyData": true, 
        limit: 500, 
        offset: prevItems.length,
        "orderBy": "id:asc"
         });
        ep.fetch().then(function (result) {
          if (result.response.ok) {
            var currentItems = prevItems.concat(result.body.items);
            if (result.body.hasMore == true) {
              resolve(pageModuleVar.getLineItems(currentItems));
            }
            else {
              resolve(currentItems);
            }
          }
          else {
            resolve([]);
          }
        });

      });
    }

    async downloadDataFromBO() {
      let lineItems = [];
      lineItems = await this.getLineItems(lineItems);

      let fieldNames = [
        {
          "display": "Id",
          "fieldName": "id"
        }, {
          "display": "Country Name",
          "fieldName": "countryName"
        }, {
          "display": "Country Code",
          "fieldName": "countryShortCode"
        }
      ];

      let headerLine = fieldNames.map(function (fieldObj) {
        return fieldObj.display;
      }).join(",");

      let csvData = headerLine;

      for (let i = 0; i < lineItems.length; i++) {
        csvData += "\r\n";

        let csvRow = "";

        for (let j = 0; j < fieldNames.length; j++) {
          csvRow += '"' + lineItems[i][fieldNames[j].fieldName] + '"' + ",";
        }

        csvData += csvRow;
      }

      const blob = new Blob([csvData], { type: 'text/csv' });
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');

      a.setAttribute('href', url);
      a.setAttribute('download', 'download.csv');
      a.click();
    }
  }

  return PageModule;
});