简体   繁体   中英

angularjs-data from factory cannot be accessed inside the controller

I have written a factory for getting data from local websql database.The code is as below:

app.factory('readData', function () {
var localData=[];
var data=[];
var db = openDatabase("here is ma database");
var selectAllStatement = "SELECT * FROM tablename"; 

  db.transaction(function (tx) {
        tx.executeSql(selectAllStatement, [], function (tx, result) {
             dataset = result.rows;
            for (var i = dataset.length - 1; i >= 0; i--) {
             data[i]=dataset.item(i);

            }; 
              localData=data;

            console.log(data);  
            return localData; 

        });

    });
return localData ;});

This factory is used in a controller to get the data.The code is:

function tricoreContrller($scope, readData) {$scope.users = readData;console.log( $scope.users);}tricoreContrller($scope, readData);

I have used console.log to check whether the data is actually coming in factory.I get result in console from factory but not from controller.Plz tel me where i am going wrong.I have used LocalData as temperary variable to store the data from array "data".

This looks to be a problem with the factory getting it's data asynchronously. In your controller you are getting the data and then logging it straight away, but until the db.transaction call is complete the data is just an empty list.

Ie the factory will return the starting listData (which is []) straight away, and then it will modify it once the db-call is done. Your controller does not wait for this.

You will want to use a $scope.$watch in user in your controller (unless you re-write the factory to use promises), to see when it updates. This might not be necessary if you just want to use it in a template, templates handle promises pretty well by default, but if you want to use it in the javascript you need to watch or have the factory use a promise.

So with a watch:

$scope.$watch('user', function(newVal, oldVal) {
    if (newVal !== oldVal) {
        console.log('Value changed!', newVal)
    } 
}

With reservations for not having tested it right now :)

Actually, if the value gets retrieved asynchronously, you should better return a promise , instead of listening to a value change.

Also, factories should always return an object with methods that you can invoke after injecting it, not the result of a single function. This is not how factory are supposed to work.

I would rewrite your code like this:

app.factory('readData', function ($q) {

  var localData=[];
  var data=[];
  var db = openDatabase("here is ma database");
  var selectAllStatement = "SELECT * FROM tablename";

  // here starts your public API, that is the method you can invoke
  return {
    transaction: function () {

      // initialize a deferred method
      var deferred = $q.defer()

      db.transaction(function (tx) {
        tx.executeSql(selectAllStatement, [], function (tx, result) {
          // you forgot about 'var' here
          var dataset = result.rows;

          for (var i = dataset.length - 1; i >= 0; i--) {
            data[i]=dataset.item(i);
          }

          // set your data as the successful result of your promise
          deferred.resolve(data)

        })
      })

      // return the promise (that is, the async data)
      return deferred.promise
    }
  }

})

And then you can inject it in some controller and retrieve the result like this:

app.controller('myCtrl', function (readData) {

  readData.transaction()
    .success(function (data) {
      console.log(data)
    })
})

Edit: updated code to address misplaced return.promise

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM