TypeError: function (...) .then is not a function

3

When trying to obtain the information stored in the localstorage by means of a factory injecting it into the controller, the following error occurs.

  

TypeError: get GroupsProf.DataGroups (...). then is not a function

The code is as follows:

angular.module('gruposProfesor', ['ionic', 'ngCordova'])
    .controller('mostrarGruposProf', mostrarGruposProf)
    .factory('obtenerGruposProf', obtenerGruposProf);


mostrarGruposProf.$inject = ['$scope', 'obtenerGruposProf'];

function mostrarGruposProf($scope, obtenerGruposProf) {

    obtenerGruposProf.datosGrupos().then(function(data) {
        console.log(data);
    });

}

function obtenerGruposProf() {   

   return {

    datosGrupos: function() {

        var getGrupos, infoGrupos;

        getGrupos = localStorage.getItem('GruposProf');
        infoGrupos = JSON.parse(getGrupos);

        return infoGrupos;

    }

  };

}

Thanks in advance for any help.

    
asked by Pedro Miguel Pimienta Morales 25.05.2016 в 00:28
source

1 answer

3

If you are using a .then method it is most likely that the object that precedes it is a thenable (or an object that has a then method ). Usually those who implement this type of method are Promises . Looking at your code more closely we have

datosGrupos: function() {

    var getGrupos, infoGrupos;

    getGrupos = localStorage.getItem('GruposProf');
    infoGrupos = JSON.parse(getGrupos);

    return infoGrupos;

}

which you then call

obtenerGruposProf.datosGrupos().then(//....

The error occurs because the datosGrupos function does not return a promise and therefore there is no .then method. What returns that function as such is the data you have in the localStorage, a common and ordinary object.

To get a promise back you must do something like

angular.module('gruposProfesor', ['ionic', 'ngCordova'])
    .factory('obtenerGruposProf', obtenerGruposProf);

obtenerGruposProf.$inject = ['$q'];

function obtenerGruposProf($q) {       
   return {    
    datosGrupos: function() {
        var defer = $q.defer(); 
        // creas un objeto Deferred que tiene un método resolve y reject   
        var getGrupos, infoGrupos;    
        getGrupos = localStorage.getItem('GruposProf');
        infoGrupos = JSON.parse(getGrupos);  
        // resuelves la promesa con el valor obtenido
        defer.resolve(infoGrupos) ;
        // devuelves el .promise que es el que tiene el método then 
        return defer.promise;    
    }    
  };    
}

You would basically be returning a promise with the future result already resolved. This is an error for two reasons

  • You are creating asynchrony in an operation that is inevitably synchronous.

    Operations in localStorage are synchronous. The method getItem immediately returns a string, that is, the result of the operation, not a future result.

    It's much simpler to write

    var data = obtenerGruposProf.datosGrupos();
    console.log(data);
    

    what to write

    obtenerGruposProf.datosGrupos().then(function(data) {
        console.log(data);
    });
    

    since you are creating unnecessary nesting. This puts you one step closer to the callback-hell which is one of the reasons why promises exist.

  • Usually writing promises in that way is considered a antipatron since

      

    Promises serve to make the asynchronous code retain most of the lost properties of the synchronous code such as flat indentation and a single channel for errors.

    As you saw previously, you do not need to create indentation and in case of error you can use a simple try ... catch

      

    In the Deferred antipattern, "deferred" objects are created for no reason, complicating the code.

  • There is a case in which yes you should write the code in this way and that is when, for example, you have to make an ajax call or return a stored result already. Basically you have two options, one is synchronous and the other asynchronous. In this case you can do this.

    angular.module('gruposProfesor', ['ionic', 'ngCordova'])
        .factory('obtenerGruposProf', obtenerGruposProf);
    
    obtenerGruposProf.$inject = ['$q', '$http'];
    
    function obtenerGruposProf($q, $http) {       
       return {    
        datosGrupos: function() {
            var getGrupos, infoGrupos;    
            getGrupos = localStorage.getItem('GruposProf');
            if (getGrupos) {
                infoGrupos = JSON.parse(getGrupos);
                var defer = $q.defer();
                defer.resolve(infoGrupos);
                return defer.promise;
            } else {
                return $http.get('/miapi/gruposprof');    
            }    
        }    
      };    
    }
    

    Then you manipulate your data using

    obtenerGruposProf.datosGrupos().then(function(data) {
        localStorage.setItem('GruposProf', JSON.stringify(data));
        console.log(data);
    });
    

    In this case the deferred if necessary since you can not know for sure if the call will be asynchronous or not and the use of .then is fully justified.

    Finally, keep in mind that if you want to cache the result of your ajax calls in the localStorage, there is already a service to do that.

    Check out link .

        
    answered by 25.05.2016 / 19:16
    source