I’m trying to sync offline data with the server after a user comes back online. I’m trying to follow these steps that I have found doing research on this. This information I’m using as a guide.
To sync IndexedDB to a server in the background using service workers,
you can use the background sync feature of service workers. This
feature allows you to defer actions until the user has stable
connectivity. Here are the steps to follow:Register a service worker in your application’s JavaScript file using
feature detection. You can use the following code snippet: JavaScript
AI-generated code. Review and use carefully. More info on FAQ.
I have this function in my app.js file and it is called at the bottom of every page for offline capabilities
if (navigator.serviceWorker) {
navigator.serviceWorker.register('serviceworker.js');
}
In your
service worker, add an event listener for the sync event. This event
is triggered when the user has stable connectivity. You can use the
following code snippet: JavaScript AI-generated code. Review and use
carefully. More info on FAQ.
I have this function in my sw.js file
self.addEventListener('sync', function(event) {
if (event.tag === 'sync_date_time') {
console.log('sync event has been fired');
// event.waitUntil(syncData());
}
});
In the syncData function, retrieve the data from IndexedDB and send it to the server using the
fetch API. You can use the following code snippet: JavaScript
AI-generated code. Review and use carefully. More info on FAQ.
This is the easy part, just sending the information to the server that I get pulled from IndexedDB. Although my function will be a little different
function syncData() {
return getIndexedDBData().then(function(data) {
return fetch('/sync', {
method: 'POST'
body: JSON.stringify(data),
headers: {'Content-Type': 'application/json'}
});
});
}
In your application’s frontend code, request a sync by calling the register() method on the SyncManager interface. You can
use the following code snippet: JavaScript AI-generated code. Review
and use carefully. More info on FAQ.
This function I have in my dateTimeJS.js file.
async function requestBackgroundSync() {
const registration = await navigator.serviceWorker.ready;
await registration.sync.register(BACKGROUND_QUERY_DATE_TIME);
}
Finally, handle the sync
event in your server-side code and update the server-side database
with the data sent from the client.
I have my sw registered, I have the function requestBackgroundSync in the js file that is loaded with page that has the form. Here is my dateTime.js file:
const BACKGROUND_QUERY_DATE_TIME = 'sync_date_time';
const IDB = function init() {
let db = null;
let DBOpenReq = indexedDB.open('dateTimeDB',1);
DBOpenReq.addEventListener('success', evt => {
db = evt.target.result;
});
DBOpenReq.addEventListener('upgradeneeded', evt => {
db = evt.target.result;
const objectStore = db.createObjectStore('date_time',{
autoIncrement: true
})
})
let form = document.getElementById('date_time_form');
form.addEventListener('submit', async evt => {
evt.preventDefault();
let fm = document.getElementById('form_msg');
fm.innerHTML = '';
const data = new FormData(form);
const formData = Object.fromEntries(data.entries());
let userData = {
uID: formData.uID,
tz: formData.time_zone,
tf: formData.time_format,
df: formData.date_format
}
try{
const req = await fetch('../date-time-format/src/inc/dateTimeAPI.php',{
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify(userData)
});
const res = await req.json();
if(res.status === 'ok'){
fm.classList.remove('w3-text-red');
fm.classList.add('w3-text-green');
fm.innerHTML = res.msg;
}
else if(res.status === 'error'){
fm.classList.remove('w3-text-green');
fm.classList.add('w3-text-red');
fm.innerHTML = res.msg;
}
}
catch{
// Clear any data previously saved in the store
clearStore(db,'date_time');
let tx = db.transaction('date_time','readwrite');
let store = tx.objectStore('date_time');
let req = store.add(userData);
req.onsuccess = evt => {
fm.classList.remove('w3-text-red');
fm.classList.add('w3-text-green');
fm.innerHTML = 'Date/Time Options have been set.';
}
}
})
}
async function requestBackgroundSync() {
const registration = await navigator.serviceWorker.ready;
await registration.sync.register(BACKGROUND_QUERY_DATE_TIME);
}
IDB();
requestBackgroundSync();
When I go to the page with the form, I use the devTools to go into offline mode. This puts the form data into the IndexedDB after the form submission. This works as expected. Then I click on the checkbox to make the page be “online” but nothing happens. I would expect that the console.log would fire to let me know that there was a sync event.
Question
What am I missing to have the sync event fire when I bring the browser back online?
I have found these similar questions. The first two were not helpful. The third link here and I tried to follow how they implemented the sync, but it is still not firing.
When and how are sync events fired in service workers?
Background sync not firing event in serviceworker
Call Back not fired when listening to ‘sync’ event in service worker
If ya’ll need more information/code, please let me know.
Just an Update
In the devTools I started recording background sync events. I used the “sync” button with the tag name under the “service worker” to try to trigger the sync event. Nothing happened. No indication of the sync event being fired. The only thing showing up is that the sync event has been registered.