66

I am new to AngularJS and find it very interesting, but I am a bit unclear about the following situation.

app.factory('deleteFac', function($http){

var factory = {}; 

factory.edit = function(id){
  $http.get('?controller=store&action=getDetail&id=' + id).
    success(function(data, status){
        /** 
        got an error on the following 
        when i use return data; and i get data undefined 
        in the controller which i get it because its doing a ajax call
        you don't get data until the call first.
        **/
        $scope.detail = data;
      })
    }

return factory;
})

I am getting error when I assign to $scope and use return data, is there anyway I can assign the return data to the $scope?

7
  • You didnt inject $scope Commented Mar 3, 2014 at 22:48
  • 7
    Uhh... what scope are you talking about? A factory doesn't have a scope - it's a service. You should make edit return the promise on the AJAX call and call it from wherever you need that has scopes. Commented Mar 3, 2014 at 22:49
  • 4
    Are you using this factory from inside a controller? If so, just pass the controller's scope as a parameter to edit, or accept a callback that passes data along. You can't inject $scope since it'd have no idea what scope to inject. Commented Mar 3, 2014 at 22:50
  • @BenjaminGruenbaum i am talking about the $scope as in the controller? can you provide me with an example how to approach this kind situation? Thanks heaps for your explanation. Commented Mar 3, 2014 at 22:51
  • 1
    @Dudi not good idea refer to the correct answer Commented Nov 5, 2015 at 23:55

7 Answers 7

83

You don't typically use $scope inside a factory, service or provider. Usually, you would return the promise (returned by $http) and then handle the promise in a controller (where you do have $scope).

factory.edit = function(id){
    return $http.get('?controller=store&action=getDetail&id=' + id);
}

Controller function:

$scope.edit = function(id) {

    deleteFac.edit(id).then(function(response) {
        $scope.something = response.model;
    });
}
Sign up to request clarification or add additional context in comments.

3 Comments

@bluebill1049 this is what I meant in my comment. It is the correct answer in this case - I'd use .done or .then instead of .success but other than that it's good imo.
Would be good to update this answer with then instead of success as success is now deprecated: docs.angularjs.org/api/ng/service/$http#deprecation-notice
Why not pass the $scope as a parameter to the function edit() as follows factory.edit = function(id, $scope){ return $http.get('?controller=store&action=getDetail&id=' + id); } then you can do whatever you want with $scope within the factory function.
14

I guess you meant this:

app.factory('deleteFac', function($http){

  var service = {}; 

   factory.edit = function(id, success, error){
        var promise = $http.get('?controller=store&action=getDetail&id=' + id);
        if(success)
           promise.success(success);
        if(error)
           promise.error(error);
   };

   return service;
});

Then in your controller you do:

function MyController($scope, deleteFac){
   deleteFac.edit($scope.id, function(data){
       //here you have access to your scope.
   });
}

8 Comments

Yes Thanks Edwin i mean this, thanks for the example
-1 This is a promise anti pattern. Returning the promise is a lot less error prone and is generally preferable.
@BenjaminGruenbaum Mind to provide any references?
Sure, I left this here before but removed it as as it's really straightforward. This is using promises as glorified callbacks, not to mention the redundant if checks there. I think David's solution works well.
@EdwinDalorzo If someone were to write a (good) book about promises in JS, changes are it would be one of ~100 very specific people. The three I listed above are likely at the top 10 of that list. Kris who popularized promises in JS, authored the amazing Q library that made it all possible, Domenic who did an amazing amount of work on the A+ spec and getting promises into ES6 and the DOM and Petka who has written the first fast promise implementation that made them really viable in tight places in NodeJS. The problem is this area is evolving really fast in JS and books wouldn't work well :)
|
10

The following trick is a very bad practice, but you can use it if you are in a hurry:

Exchange the $scope with: angular.element('[ng-controller=CtrlName]').scope()

2 Comments

This looks dirty but could be a small trick :) Thanks for the answer anyhow (plus u said it's a badddddd practice)
This is 2017. If this answer helps You, and You just started your project, You might want to consider vue.js.
6

Personally I would like to use scope from the factory, so, instead of moving all out I would pass the scope as parameter from the client which is calling to the factory.function().

Also I was having this same issue when trying to use $scope.watch(...) since we cannot use directly $scope from factories or services but I wanted to have this working in this way, so that is why I just updated my function to have scope as parameter and let the factory's client to send the $scope. So, this would be my solution:

var app = angular.module("myApp", []);

app.factory('MyFactory', function($http) {

      var factory = {};
      //This is only for my own issue I faced.
      factory.Images = {};

      factory.myFunction = function(id, scope) {
        //This is an example of how we would use scope inside a factory definition
        scope.details = "Initial Value";
        //In my case I was having this issue while using watch
        scope.$watch('details' , function(newValue, oldValue) {
          if(oldValue){
             scope.log = "Details was updated to : " +newValue;
            }
        });
        
        scope.details = "My Id is: "+id;
       };
        return factory;
});

//Controller: Factory's Client.
app.controller("MyController", ['$scope', 'MyFactory', function($scope, MyFactory) {
  
        MyFactory.myFunction(5, $scope);
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
  <span>{{details}} </span>
  <hr>
  <p>{{log}} </p>
</div>

I hope this can help. Regards.

Comments

1

I think this is the cleanest solution:

Let me know if there is problem or improvement.

(function(){
  angular.controller('controllerName', controllerName);
  controllerName.$inject = ['$scope', factory];

  function controllerName($scope, factory){
    var vm = this;

    vm.data = factory.alertPopup();
  }

  angular.factory('factory', factory);
  factory.$inject = ['externalServices'];

  function factory(externalServices){
    return {
      returnData : returnData
    }

    function returnData(){
      return externalServices.whatever();
    }
  }
})();

Comments

0
.factory('POPUP', function($ionicLoading, $ionicPopup) {
  var self = this;
  // THIS BLOCK SCREEN ! for loading ! Be carefoull !! ( deprecated: assign this to a var for security)
  self.showLoading = function(title, message, scope){
  scope.loading = true;
  return $ionicLoading.show({ content: message, showBackdrop: false });
  };
  self.hideLoading = function(title, message, scope){
  scope.loading = false;
  return $ionicLoading.hide();
};

// NOT BLOCK SCREEN- SIMPLE ALERTS - Standards popups
self.showAlert = function(title, message, callback){
  var alertPopup = $ionicPopup.alert({ title: title, template: message });
  alertPopup.then(function(res) {
      console.log('callback popup');
      if (callback){ callback(); }
  });
};
 self.showConfirm = function(objectPopup, callback){
 if (objectPopup === undefined){ objectPopup = { title: 'test confirm    Popup', template: 'Message test Confirm POPUP' }; }
 var alertPopup = $ionicPopup.confirm(objectPopup);
 alertPopup.then(function(res) {
   if (res) { callback(true); }
    else { callback(false); }
 });
 };
   return self;
   }) 

1 Comment

Note: community wiki doesn't give reputation when it's upvoted.
0

I know this question is old, but this is what worked for me

app.factory('myFactory',function(){

    let toRet = {
        foo: foo
    }

    return toRet;

    function foo(){ // This function needs to use passed scope.
        let $scope = toRet.$scope;
        // Do stuff with $scope.
    }
});

app.controller('myController',function($scope,myFactory){

    myFactory.$scope = $scope;
    /*
        We could just pass $scope as a parameter to foo, but this is
        for cases where for whatever reason, you cannot do this.
    */
    myFactory.foo();

});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.