cjs1976 cjs1976 - 3 months ago 25
AngularJS Question

AngularJS +how to wait for task to finish before running next task

I have still problems with my database, but I found out, that the problems come from the fact, that opening the database takes some time, but the app is not waiting till this task has finished.

Is there a way to make angular wait till the database is opened correctly before it starts the next task?

Thanks,
Christian.




Update: 2016-08-08 - 03:13 pm

Thanks for all the answers. As I can see, my first idea with promises ($q) was right, but:

My app has an app.js, which is my main file. It only calls the InitDB. This should open the database. Then it should call the CreateTables, this creates the table, if it doensn't exist.

The rest of my app is splitted in 4 pages (templates). Every page has it's own controller.

So the idea was to init the db, to create the table, and then work with the database, but used over different controllers.

This won't work, because I would always need to put all of my stuff in the .then() of my initDB in the app.js???

This is my first AngularJS app, maybe this is the reason why I do a lot of mistakes...

Thanks,
Christian.

Answer

One of the core concepts of Angular is working with services/factories. There is ample documentation and blogs about how these work and how to use them, but the basic idea is that these are singleton "controllers" that handle shared data and methods across your entire application. Used in combination with promises, you can easily create a service that will manage communications with your database.

angular
  .module('myApp')
  .service('DBService', DBService)
  .controller('Ctrl1', Ctrl1)
  .controller('Ctrl2', Ctrl2)
  .controller('Ctrl3', Ctrl3)
  .controller('Ctrl4', Ctrl4);

DBService.$inject = ['$q'];
function DBService($q) {
  var DBService = this;
  var DBServiceDeferred = $q.defer();
  DBService.ready = DBServiceDeferred.promise;

  // a service is only initialized once, so this will only ever be run once
  (function() {
    init();
  })();

  function init() {
    // you can use promise chaining to control order of events
    // the chain will halt if any function is rejected
    initDB()
    .then(createTablesUnlessExist)
    .then(setDbReady);
  }

  function initDB() { 
    var deferred = $q.defer();
    // simulate async db initialization
    $timeout(function() {
      deferred.resolve();
      // or reject if there is an error
      // deferred.reject();
    }, 5000);
    return deferred.promise;
  };

  function createTablesUnlessExist() {
    //create tables if needed (only happens once)
    var deferred = $q.defer();
    // simulate async table creation
    $timeout(function() {
      deferred.resolve();
      // or reject if there is an error
      // deferred.reject();
    }, 5000);
    return deferred.promise;
  }

  function setDbReady() {
    DBServiceDeferred.resolve();
  }
}

Now you have your DB setup and you don't have to worry about it anymore. You can access the DB from any controller using the service. None of the queries will run until the DB has been initialized and the tables have been created.

Ctrl1.$inject = ['DBService', '$q'];
function Ctrl1(DBService, $q) {
  $q.when(DBService.ready).then(function() {
    DBService.conn.query("Select something");
  });
}
Ctrl2.$inject = ['DBService', '$q'];
function Ctrl2(DBService, $q) {
  $q.when(DBService.ready).then(function() {
    DBService.conn.query("Select something");
  });
}
Ctrl3.$inject = ['DBService', '$q'];
function Ctrl3(DBService, $q) {
  $q.when(DBService.ready).then(function() {
    DBService.conn.query("Select something");
  });
}
Ctrl4.$inject = ['DBService', '$q'];
function Ctrl4(DBService, $q) {
  $q.when(DBService.ready).then(function() {
    DBService.conn.query("Select something");
  });
}