Variable Scope change between AngularJs Pure web app and Ionic app?


#1

Hello !

Before I explain my problem, excuse me for my english, I’m French.

I’m new on AngularJS and I’m new on ionic. I begin learning both 2 days later, and now I’m trying to build an app to learn.

For this app I need some informations available in my server so I use $http, 2 controllers because of 2views and a factory to share the information between them.
So, this is my factory :

app.factory('ProjectFactory',function($http, $q){
    var factory = {
        projects : false,
        getProjets: function(){
            var deferred = $q.defer();

            $http.get('http://app.comandweb.org/api.php')
                .success(function (data, status){
                    factory.projects = data;
                    deferred.resolve(factory.projects);
                })
                .error(function (data, status){
                    deferred.reject('Impossible de recupéré les article');
                });

            console.log(factory.projects);
            return deferred.promise;
        },
        getProjet:function(id){
            return factory.projects[id];
        }
    };
    return factory;

});

The problem is that I doesn’t have access to my variable factory.projects in the $http.get function, like she is local in the anonymous function…
I’ve found it strange so I’ve tried the same code in a HTML/Angular web app (a clean app, without ionic or anything else) and it works …

Someone can explain me the problem ? I’ve tried to use $rootScope but it don’t work, same for window.myvar etc

Thanks you, I hope i’m understandable.

Bye !
Seb


#2

Have a look at John Papa’s Angular styleguide, you’ll see some good patterns on how to write a service.


#3

Thanks for the link, it’s interresting, but it doesn’t seems help me for the scope problem.

So now the code is :

function ProjectServiceFunc($http, $q, $ionicLoading){
    this.projects = {};
    this.getProjets = getProjets;
    this.getProjet = getProjet;

    function getProjets(){
        var deferred = $q.defer();

        $ionicLoading.show({
            template: 'Loading...'
        });

        $http.get('http://app.comandweb.org/api.php?getProjet')
            .success(function (data, status){
                this.projects = data;  // Here "this" is undefined...
                deferred.resolve(data);
            })
            .error(function (data, status){
                deferred.reject('Impossible de recupéré les projets');
            });

        $ionicLoading.hide();

       // this.projects = {test:'tt'}  Here it works

        return deferred.promise;
    };

    function getProjet(id) {
        return this.projets[id];
    }
}

#4

This works:

.factory('ProjectFactory', 
    function ProjectFactory($http, $q, $ionicLoading) {
        // interface
        var service = {
            projets: [],
            getProjets: getProjets,
            getProjet: getProjet
        };
        return service;

        // implementation
        function getProjets() {
          var def = $q.defer();

          $ionicLoading.show({
              template: 'Loading...'
          });

          $http.get('http://app.comandweb.org/api.php?getProjet')
              .success(function(data) {
                  service.projets = data;
                  def.resolve(data);
                  $ionicLoading.hide();
              })
              .error(function() {
                  def.reject('Impossible de recupérer les projets');
                  $ionicLoading.hide();
              });

            return def.promise;
        };

        function getProjet(id) {
          return service.projets[id];
        };

    });

And a controller that uses it:

.controller('DashCtrl', function($scope, ProjectFactory) {
    ProjectFactory.getProjets().then(function () {
      $scope.msg = ProjectFactory.getProjet(1);
    });
})

#5

Yes we can do like that but, the problem is the same, if we use a console.log(service.projets) at the end of the success function, it display the data, but if we use a console.log(service.projets) after the error function, just before the return, we can see that service.projets haven’t change.

I want store the data in service.projets to do less request on the server. In my app, at the openning, the data are loading from the server by the home view which list all projects, and they are use in an other view which show the details of a project. So with your method we do 2 $http.get .


#6

I don’t understand your point, that’s how promises work, it’s not a problem of scope it’s just that the value has not been resolved yet.


#7

No, in detail controller you would call only ProjectFactory.getProjet(id); so no access to backend server.
The controller code I gave is just for the intial loading and to prove you that it works and to be sure that you understand how promise returned by service could be used.


#8

aaaahhh okay !! Yeah, I understand.

So, in the controllers it’s the same thing, if I do a console.log(ProjectFactory.projets) it display [] because the promise isn’t resolved yet. But when I go in the other view, the promise is resolved so console.log(ProjectFactory.projets) display my project !

Thank you very much !
And thank you for the John Papa’s Angular styleguide, I think I need it ahah :slight_smile: