Question

Below is my code. It runs fine for the first time but once I refresh the page it generates an uncaught TypeError: Cannot call method 'transaction' of undefined.

Basically I retrieve from data from a database and encode it into a usable JSON datatype to avoid insert issues into my tables.

$(document).ready( function() {

//prefixes of implementation that we want to test
window.indexedDB = window.indexedDB ||
                   window.mozIndexedDB ||
                   window.webkitIndexedDB ||
                   window.msIndexedDB;

//prefixes of window.IDB objects
window.IDBTransaction = window.IDBTransaction ||
                        window.webkitIDBTransaction ||
                        window.msIDBTransaction;

window.IDBKeyRange = window.IDBKeyRange ||
                     window.webkitIDBKeyRange ||
                     window.msIDBKeyRange

if(!window.indexedDB){ //alert user if browser does not support
    window.alert("Your browser doesn't support a stable version of IndexedDB.")
}

var request = window.indexedDB.open("runningClub", 1); //create a runningClub database

var browserDB;

request.onsuccess = function(event){
    browserDB = request.result;
};

var raceIDs = [];

$(".raceID").each( function () {
    raceIDs.push(" raceID = " + $(this).val());
});

$.ajax({
    url: 'controller/AJAX/userAction.php',
    type: 'post',
    dataType: 'json',
    data: { statement : "getRaceResult", raceIDs : raceIDs },
    success: function(data) {

        const results = data;

        request.onupgradeneeded = function(event){
            var browserDB = event.target.result;
            var objectStore = browserDB.createObjectStore("raceResult", {keyPath: "resultID"});
            for(var i in results){
                objectStore.add(results[i]);       
            }
        }

        var objectStore = browserDB.transaction("raceResult").objectStore("raceResult");

        objectStore.openCursor().onsuccess = function(event){
            var cursor = event.target.result;
            if (cursor){
                $("#memberName").append("<option>" + cursor.value.memberName + "</option>");
                cursor.continue();
            }
        };
    }
});
});
Était-ce utile?

La solution

Thanks for posting the (almost) entirety of your code. Unfortunately I can't fully replicate your issue without knowing the structure of the data object coming from your backend. Mind publishing that as well?

That said, I'm rather certain your issue is the use of const.

const results = data;

I do not believe this type of data to be "structured clone"-able. Given that JSON is fully clonable, which is what I imagine to be returned from your API (vs. e.g. JavaScript that could be evaulated to produce a function), the usage of this keyword seems the likely culprit of your issues.

Update 1 Working through this, quite a few issues with your async programming.

  • database is opened before ajax request, rather than after successful callback. seems prudent to move this into the callback.
  • browserDB is defined in a success callback that isn't guaranteed to run before the async operation completes (thus browserDB becomes undefined)
  • request.onsuccess is called twice (you may not have realized this, because it's weird behavior): both when no upgradeneeded event fires and when an upgradeneeded event fires, so you're redefining browserDB perhaps accidentally when the DB doesn't yet exist

Update 2 Here's a mostly working, simplified Fiddle. I'm sad at how much time I spent making your code work.

More issues (beyond const):

  • hardcoded database version
  • reusing versionchange event for adding/getting data is a bad idea
  • need to use a readwrite transaction to add data
  • openCursor - but don't supply parameters for resultID keypath
  • you are not listening for successful adds before getting the data
  • you are not chaining your success events for adds before getting the data

The current loop approach was untenable. But I got it working with a single add and a cursor get. You can refactor back into a multiple-add approach but you'll need to watch your async (based on what I see, I'd suggest you stick with simple).

$.ajax({
  url: '/echo/json/',
  type: 'post',
  dataType: 'json',
  data: {
    json: JSON.stringify({
      resultID: new Date().getTime(),
      raceID: "1",
      memberID: "824",
      runtime: "00:31:26",
      memberName‌: "Mark Hudspith"
    })
  },
  success: function (data) {
    var request,
      upgrade = false,
      doTx = function (db, entry) {
        addData(db, entry, function () {
          getData(db);
        });
      },
      getData = function (db) {
        db.transaction(["raceResult"], "readonly").objectStore("raceResult").openCursor(IDBKeyRange.lowerBound("0")).onsuccess = function (event) {
          var cursor = event.target.result;
          if (null !== cursor) {
            console.log("YOUR DATA IS HERE", cursor.value.memberName‌);
            cursor.continue();
          }
        };
      },
      addData = function (db, entry, finished) {
        var tx = db.transaction(["raceResult"], "readwrite");
        tx.addEventListener('complete', function (e) {
          finished();
        });
        tx.objectStore("raceResult").add(entry);
      };
    request = window.indexedDB.open("runningClub");
    request.onsuccess = function (event) {
      if (!upgrade) {
        doTx(request.result, data);
      }
    };
    request.onupgradeneeded = function (event) {
      var db = event.target.result;
      db.createObjectStore("raceResult", {
        keyPath: "resultID"
      });
      setTimeout(function () {
        doTx(db, data);
      }, 5000);
    }
  }
});
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top