javascriptangularjscordovaionic-frameworklokijs

Ionic +LokiJS always produces "ionic.bundle.js:26794 TypeError: Cannot read property 'insert' of undefined"


after all of my problems with SQLite, I wanted to use a different solution for my Ionic app. LokiJS was often mentioned, so I tried it. But also with LokiJS I have no luck.

At the moment I have a very basic code, which should work without problems:

.controller('ProjectsController', ['$scope', '$state', '$ionicPlatform', function($scope, $state, $ionicPlatform) {
  var pcVm = this;

  var db;
  var projects1;

  $ionicPlatform.ready(function(){

    var idbAdapter = new LokiIndexedAdapter('loki');
    db = new loki('lkr-v4', {
      autoload: true,
      autoloadCallback : getAllProjects,
      autosave: true,
      autosaveInterval: 10000,
      adapter: idbAdapter
    });

    function getAllProjects() {
      var options = {};
      db.loadDatabase(options, function() {
        projects1 = db.getCollection('projects'); // GET
        if (!projects1) {
          projects1 = db.addCollection('projects'); // ADD
        }
        console.log('Databaseinformation');
        console.log(db);
        console.log('Collectioninformation');
        console.log(projects1);
      });
    }

    console.log('Insert something');
    projects1.insert({ name : 'odin' });
  }); // End of .ready()

But I get always the message:

ionic.bundle.js:26794 TypeError: Cannot read property 'insert' of undefined
    at controllers.js:309
    at ionic.bundle.js:56230
    at Object.ready (ionic.bundle.js:2140)
    at Object.ready (ionic.bundle.js:56223)
    at new <anonymous> (controllers.js:283)
    at Object.instantiate (ionic.bundle.js:18010)
    at $controller (ionic.bundle.js:23412)
    at self.appendViewElement (ionic.bundle.js:59900)
    at Object.render (ionic.bundle.js:57893)
    at Object.init (ionic.bundle.js:57813)(anonymous function) @ ionic.bundle.js:26794(anonymous function) @ ionic.bundle.js:23507$broadcast @ ionic.bundle.js:30720$state.transition.resolved.then.$state.transition @ ionic.bundle.js:52157processQueue @ ionic.bundle.js:29127(anonymous function) @ ionic.bundle.js:29143$eval @ ionic.bundle.js:30395$digest @ ionic.bundle.js:30211$apply @ ionic.bundle.js:30503done @ ionic.bundle.js:24824completeRequest @ ionic.bundle.js:25022requestLoaded @ ionic.bundle.js:24963
controllers.js:301 Databaseinformation

Please help. Maybe I have the same problem wit SQLite and LokiJS? But I can't find the problem...

Thanks, Christian.


UPDATE - 2016-08-05

So, I spent again hours of hours with searching, trying, and always ending up with the same errors. I am wondering why all of the tutorials look the same, and seem to work, but for me it's impossible to get it running.

I completely rewrote my factory:

(function() {
  'use strict';

  angular.module('lkr-v4')

    .factory('PersistenceService', ['$q', 'Loki', PersistenceService]);

      function PersistenceService($q, Loki) {
        // Needed variables
        var lkrDb; // Database
        var projects; // Collection of JSON strings

        // Accessible Members Up Top
        // https://github.com/johnpapa/angular-styleguide/tree/master/a1#style-y052
        var pService = {
          initDB: initDB,
          getAllProjects: getAllProjects,
          addProject: addProject,
          updateProject: updateProject,
          deleteProject: deleteProject
        };
        return pService;

        // Initialization of the database
        function initDB() {
          var idbAdapter = new LokiIndexedAdapter('loki');
          lkrDb = new loki('lkr-v4', {
            autoload: true,
            autoloadCallback: getAllProjects,
            autosave: true,
            autosaveInterval: 10000,
            adapter: idbAdapter
          });
        }

        // Function to return a collection of JSON strings (all found projects) in the LokiJS database file
        function getAllProjects() {
          // What is $q? See https://docs.angularjs.org/api/ng/service/$q
          return $q(function (resolve, reject) {
            var options = {};
            lkrDb.loadDatabase(options, function () {
              projects = lkrDb.getCollection('projects'); // GET!
              // If the database file is empty
              if (!projects) {
                projects = lkrDb.addCollection('projects'); // ADD!
              }
              resolve(projects.data);
            });
          });
        }

        // Function to add a project
        function addProject(project) {
          if(lkrDebug) {
            console.log('Inside of addProject from the factory');
            console.log('This is the projects object');
            console.log(this.projects);
            console.log('This is the given value of the new project');
            console.log(project);
          }
          projects.insert(project);
        }

        // Function to update a project
        function updateProject(project) {
          projects.update(project);
        }

        // Function to delete a project
        function deleteProject(project) {
          projects.remove(project);
        }

      } // End of function PersistenceService

})(); // End of IIFE

I call the PersistenceService.initDB() in the run() of my app.js. THIS WORKS!

All of my pages (4) have their own controller, used over controller as. In the controller of my first page, I tried this code:

  // Test #1: Get data
  PersistenceService.getAllProjects().then(function(projects) {
    pcVm.projects = projects;
    if(lkrDebug) {
      console.log('Inside of getAllProjects().then() from the controller');
      console.log('This is the project object from the PersistenceService');
      console.log(projects);
      console.log('And this ist the pcVm.projects object from the controller');
      console.log(pcVm.projects);
    }
  });

IT WORKS! I can see the correct information in the consloe, and I don't get any error.

The next code is placed directly after the code above in the same controller:

  // Test #2: Add a project
  PersistenceService.addProject({ name : 'odin' });

And it produces the following lines (and erros) on the console

Inside of addProject from the factory
persistence.services.js:65 This is the projects object
persistence.services.js:66 undefined
persistence.services.js:67 This is the given value of the new project
persistence.services.js:68 Object {name: "odin"}
ionic.bundle.js:26794 TypeError: Cannot read property 'insert' of undefined
    at Object.addProject (persistence.services.js:70)
    at new ProjectsController (projects.controller.js:31)
    at Object.instantiate (ionic.bundle.js:18010)
    at $controller (ionic.bundle.js:23412)
    at self.appendViewElement (ionic.bundle.js:59900)
    at Object.render (ionic.bundle.js:57893)
    at Object.init (ionic.bundle.js:57813)
    at self.render (ionic.bundle.js:59759)
    at self.register (ionic.bundle.js:59717)
    at updateView (ionic.bundle.js:65398)(anonymous function) @ ionic.bundle.js:26794(anonymous function) @ ionic.bundle.js:23507$broadcast @ ionic.bundle.js:30720$state.transition.resolved.then.$state.transition @ ionic.bundle.js:52157processQueue @ ionic.bundle.js:29127(anonymous function) @ ionic.bundle.js:29143$eval @ ionic.bundle.js:30395$digest @ ionic.bundle.js:30211$apply @ ionic.bundle.js:30503done @ ionic.bundle.js:24824completeRequest @ ionic.bundle.js:25022requestLoaded @ ionic.bundle.js:24963
projects.controller.js:22 Inside of getAllProjects().then() from the controller
projects.controller.js:23 This is the project object from the PersistenceService
projects.controller.js:24 [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
projects.controller.js:25 And this ist the pcVm.projects object from the controller
projects.controller.js:26 [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]

That's a little bit strange, because for me it looks like addProject() is called bevore getAllProjects()?

So I added the line console.log(lkrDb); in the addProject-function, to see if the database is loaded, and I did some more tests. It turned out, that the the initDB in the app.js is working, and that the addProject-function can also work with the opened database.

My conclusion is, that I do something wrong in the controller, or with the getAllProjects-function!?

I'll keep on searching, but I would be realy thankfull for any hint...

Thanks, Christian.


Solution

  • Now I understand the promises thing! This helped me a lot: http://andyshora.com/promises-angularjs-explained-as-cartoon.html

    But, even if this is something I have to really take care of, this is not the problem. The problem is based on the tutorials I used. I don't know why and how, but the tutorilas work, and my app doesn't simply because: as long as I don't call the getAllProjects() function, the projects1 variable has no data. The autoloadCallback doesn't call the function automatically!? I opened an Issue at the LokiJS project to ask what I do wrong, or if this is not the idea of the autoloadCallback.

    When I have a complete working solution, I will post it here...