Video Recording (English):https://youtu.be/5Pt7KwLKujI
This Progressive Web Application (PWA) demo showcases an offline-first approach, enabling users to save data locally even when there’s no active connection to the database. The app provides a seamless experience for data entry and management, allowing users to continue working without disruption. Once connectivity is reestablished, all offline-saved data is automatically synchronized with the database, ensuring that the latest updates are reflected across all systems. This feature is ideal for scenarios where users frequently encounter connectivity issues but still need reliable data management capabilities. info@erpstuff.com
Code: Select all
// sw.js Cache Name to keep in browser and session settings
const CACHE_NAME = 'offline-first-v1';
let sessionId = null;
self.addEventListener('message', (event) => {
if (event.data && event.data.sessionId) {
sessionId = event.data.sessionId;
}
});
// This is install listner to keep pages in alive in cache
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then(function(cache) {
if (sessionId) {
return cache.addAll([
'/',
'https://gfd19a0655d8326-jsss.adb.ap-singapore-1.oraclecloudapps.com/ords/r/jsss/pwa-offline/login?session=' + sessionId,
'https://gfd19a0655d8326-jsss.adb.ap-singapore-1.oraclecloudapps.com/ords/r/jsss/pwa-offline/home?session=' + sessionId,
]);
} else {
return Promise.resolve();
}
})
);
});
// This is activate listner
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.filter(function(cacheName) {
return cacheName.startsWith('offline-first-') &&
cacheName !== CACHE_NAME;
}).map(function(cacheName) {
return caches.delete(cacheName);
})
);
})
);
});
// This is fetch listner
self.addEventListener('fetch', (event) => {
if (!navigator.onLine) {
event.respondWith(fetchFromCache(event.request));
} else {
event.respondWith(fetchFromServer(event.request));
}
});
// This listner is to request cache
async function fetchFromCache(request) {
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(request);
return cachedResponse || fetch(request);
}
// This listner is to request server
async function fetchFromServer(request) {
const cache = await caches.open(CACHE_NAME);
try {
const response = await fetch(request);
cache.put(request, response.clone());
return response;
} catch (error) {
const cachedResponse = await cache.match(request);
return cachedResponse || new Response('Offline');
}
}
Code: Select all
// App.JS
// Listner to check if online status
window.addEventListener('online', function() {
apex.message.showPageSuccess('You are back online!');
uploadOfflineFormData();
});
// Listner to check if offline status
window.addEventListener('offline', function() {
$('#t_Alert_Success').remove();
apex.message.clearErrors();
apex.message.showErrors([{
type: 'error',
location: 'page',
message: 'You have lost connection'
}]);
});
// Process call to insert data offline data back to server
function submitIndexdbData(formData) {
apex.server.process( "syncInsertion", {
x01: formData.get('name'),
x02: formData.get('sal'),
x03: formData.get('deptno')
}, {
success: function(data) {
},
error: function( jqXHR, textStatus, errorThrown ) {
apex.page.submit();
$('#t_Alert_Success').remove();
apex.message.showPageSuccess("Submitted Offline Data")
}
});
}
// Cache management
function uploadOfflineFormData() {
const request = indexedDB.open('offline-forms', 1);
request.onerror = function(event) {
console.error('Error opening IndexedDB:', event.target.error);
};
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['forms'], 'readwrite');
const objectStore = transaction.objectStore('forms');
const getAllRequest = objectStore.getAll();
getAllRequest.onerror = function(event) {
console.error('Error retrieving form data from IndexedDB:', event.target.error);
};
getAllRequest.onsuccess = async function(event) {
const formDataArray = event.target.result;
for (const formDataEntry of formDataArray) {
const formData = new FormData();
Object.entries(formDataEntry).forEach(([key, value]) => {
formData.append(key, value);
});
try {
await submitIndexdbData(formData);
objectStore.delete(formDataEntry.id);
} catch (error) {
console.error('Error uploading form data:', error.message);
}
}
};
};
}
Code: Select all
DECLARE
v_name VARCHAR2(50);
v_sal number;
v_deptno NUMBER;
BEGIN
v_name := apex_application.g_x01;
v_sal := apex_application.g_x02;
v_deptno := apex_application.g_x03;
INSERT INTO emp (ename, sal, deptno)
VALUES (v_name, v_sal, v_deptno);
COMMIT;
END;
Code: Select all
DECLARE
v_name VARCHAR2(50);
v_sal number;
v_deptno NUMBER;
BEGIN
v_name := apex_application.g_x01;
v_sal := apex_application.g_x02;
v_deptno := apex_application.g_x03;
INSERT INTO emp (ename, sal, deptno)
VALUES (v_name, v_sal, v_deptno);
COMMIT;
END;