Kenzo
Kenzo

Reputation: 1837

Failed to execute 'add' on 'IDBObjectStore'

I am trying to add a javascript object (function constructor) to the IndexedDB but i am getting an error

Failed to execute 'add' on 'IDBObjectStore': function () { this.mapHierachyString = this.mapHierachyString.replace(/>/g, "|"); //CHUSJ|Bloc 5|B...... } could not be cloned.

Is there anything wrong in the following code :

      $.ajax({
          url: '/Review/GetDynamicPositions',
          type: 'POST',
          data: {
              ProfileId: profileId,
              DateDebut: dateDebut,
              DateFin: dateFin
          },
          
          success: function (reponse) {

              if (reponse.indexOf("Erreur") < 0) 
              {
                  review = new Review(profileId);
                  const dynamicPositions = JSON.parse(reponse);
                  dynamicPositions.forEach(dynamic => {
                      const dynamicPosition = new DynamicPosition();
                      dynamicPosition.positionX = dynamic.PositionX;
                      dynamicPosition.positionY = dynamic.PositionY;
                      dynamicPosition.floorId = dynamic.FloorId;
                      dynamicPosition.zoneId = dynamic.ZoneId;
                      dynamicPosition.mapHierachyString = dynamic.MapHierchString;

                      dynamicPosition.changeMapString();
                      review.addDynamicPosition(dynamicPosition);
                  });

                  //..Sauvegarder le review dans la BD
                  sauvegarderReview(review);
              }

          }

      });



function sauvegarderReview(review) 
{
        const transcation = db.transaction('ReviewStore', 'readwrite');
        const store = transcation.objectStore('ReviewStore');

        //..Ajouter dans la BD
        const request = store.add(review);

        request.onsuccess = function (e) 
        {
            console.log('Sauvegarder avec success');
        };

        request.onerror = function (e) {
            console.log("Error", e.target.error.name);

        };
}

//Review object 
function Review(profileId)
{
        this.profileId = profileId;
        this.dynamicPositions = [];

        this.addDynamicPosition = function (dynamicPosition) 
        {
            this.dynamicPositions.push(dynamicPosition);
        }

}

//DynamicPosition object 
function DynamicPosition() 
{
      this.positionX = 0;
      this.positionY = 0;
      this.mapHierachyString = ''; //CHUSJ>Bloc 5>B
      this.floorId = 0;
      this.zoneId = '';

      this.changeMapString = function () {
          this.mapHierachyString = this.mapHierachyString.replace(/>/g, "|"); 
          this.mapHierachyString = this.mapHierachyString.replace(/ /g, "_");
      }


}

Upvotes: 0

Views: 6373

Answers (2)

Dudi
Dudi

Reputation: 3079

You have to serialize first your JS functions (only) in your data and then add them as serialized data to the IndexedDB:

function serialize(value) {
    if (typeof value === 'function') {
        return value.toString();
    }
    if (typeof value === 'object') {
        var serializeObject = {};
        for (const [objectKey, objectValue] of Object.entries(value)) {
            console.log(`objectKey=${objectKey}  value=${objectValue}`);
            serializeObject[objectKey] = serialize(objectValue);
        }
        return serializeObject;
    }
        
    return value;
}

And then deserialize:

function deserialize(valueNew) {
    if (valueNew.toLowerCase().startsWith( 'function(' ) ) {
        return Function('"use strict";return ' + valueNew);
    }
    if (typeof valueNew === 'object') {
        var deserializeObject = {};
        for (const [objectKey, objectValue] of Object.entries(valueNew)) {
            console.log(`objectKey=${objectKey}  value=${objectValue}`);
            deserializeObject[objectKey] = deserialize(objectValue);
        }
        return deserializeObject;
    }
        
    return value;
}

In your IndexedDB code, it will be something like that:

function addItem(name, item) {
    var itemObject = { name: name };

    itemObject.item = serialize(item);

    var transaction = db.transaction(['store'], 'readwrite');
    var store = transaction.objectStore('store');
    var request = store.add(itemObject);

    request.onerror = function(e) {
        console.log('Error', e.target.error.name);
    };
      
    request.onsuccess = function(e) {
        console.log('Woot! added it');
    };
      
    transaction.oncomplete = function(e) {
        console.log('Woot! trans oncomplete');
    }; 
}

And after, get the keyData of your key:

deserialize(keyData);

Upvotes: 0

dumbmatter
dumbmatter

Reputation: 9683

The spec says:

Each record is associated with a value. User agents must support any serializable object. This includes simple types such as String primitive values and Date objects as well as Object and Array instances, File objects, Blob objects, ImageData objects, and so on.

Basically this means that the objects you store to IndexedDB can only contain a limited subset of all possible variables. Functions are one of the things that can't be stored in IndexedDB. And according to the error message you posted, there must be a function in your review object.

If you want to store the data from review in IndexedDB, you'll have to somehow transform it so that it doesn't include functions or any other problematic data types.

Upvotes: 2

Related Questions