ng-classify icon indicating copy to clipboard operation
ng-classify copied to clipboard

Lost "this" reference in factory method when I tried to "ng-classify" it.

Open rlrhett opened this issue 9 years ago • 1 comments

I am sure this is a simple issue, but confusing nonetheless. I have an angular factory that I am trying to "ng-classify". The existing code looks something like this:


app.factory 'Data', [
  '$log'
  "$q'
  ($log, $q) ->
    getData1: ->
      data1 = $q.defer()
      . . .
      return data1.promise
    getData2: ->
      data2 = $q.defer()
      . . .
      return data2.promise
    getSomeComboData: ->
       comboData = $q.defer()
      $q.all(@getData1, @getData2).then (Data1, Data2) ->
      . . . 
      return ComboData.promise
    . . .
    ]

This works. No problem. Sometimes my controllers need Data1, sometimes Data2, sometimes ComboData. I can imagine other scenarios where a factory method might need to call another public method of the same factory.

This is what I did to "ng-classify" it:


class Data extends Factory
  constructor:  ($log, $q) ->
    return: {
      getData1: ->
        data1 = $q.defer()
        . . .
        return data1.promise
      getData2: ->
        data2 = $q.defer()
        . . .
        return data2.promise
      getSomeComboData: ->
        comboData = $q.defer()
        $q.all(@getData1, @getData2).then (Data1, Data2) ->
        . . . 
        return ComboData.promise
    . . .
    }

The problem is now @getData1 and @getData2 are undefined. Somehow the "this" reference to the factory singleton has been lost. Am I missing something?

rlrhett avatar Aug 24 '15 04:08 rlrhett

I'm not exactly sure why the two would behave differently; however, I did notice a few typos.

Typos fixed

app.factory 'Data', [
  '$log'
  '$q'
  ($log, $q) ->
    getData1: ->
      data1 = $q.defer()

      return data1.promise
    getData2: ->
      data2 = $q.defer()

      return data2.promise
    getSomeComboData: ->
      comboData = $q.defer()
      $q.all(@getData1, @getData2).then (Data1, Data2) ->

      return ComboData.promise

compiles to

app.factory('Data', [
  '$log', '$q', function($log, $q) {
    return {
      getData1: function() {
        var data1;
        data1 = $q.defer();
        return data1.promise;
      },
      getData2: function() {
        var data2;
        data2 = $q.defer();
        return data2.promise;
      },
      getSomeComboData: function() {
        var comboData;
        comboData = $q.defer();
        $q.all(this.getData1, this.getData2).then(function(Data1, Data2) {});
        return ComboData.promise;
      }
    };
  }
]);

and

class Data extends Factory
  constructor:  ($log, $q) ->
    return {
      getData1: ->
        data1 = $q.defer()

        return data1.promise
      getData2: ->
        data2 = $q.defer()

        return data2.promise
      getSomeComboData: ->
        comboData = $q.defer()
        $q.all(@getData1, @getData2).then (Data1, Data2) ->

        return ComboData.promise
    }

compiles to

var Data;

Data = (function() {
  function Data($log, $q) {
    return {
      getData1: function() {
        var data1;
        data1 = $q.defer();
        return data1.promise;
      },
      getData2: function() {
        var data2;
        data2 = $q.defer();
        return data2.promise;
      },
      getSomeComboData: function() {
        var comboData;
        comboData = $q.defer();
        $q.all(this.getData1, this.getData2).then(function(Data1, Data2) {});
        return ComboData.promise;
      }
    };
  }

  return Data;

})();

angular.module('app').factory('Data', ['$log', '$q', Data]);

They are virtually identical.

Another way would be to use the Revealing Module Pattern

class Data extends Factory
  constructor:  ($log, $q) ->
    getData1 = ->
      data1 = $q.defer()

      data1.promise

    getData2 = ->
      data2 = $q.defer()

      data2.promise

    getSomeComboData = ->
      comboData = $q.defer()
      $q.all(getData1, getData2).then (Data1, Data2) ->

      ComboData.promise

    return {getData1, getData2, getSomeComboData}

compiles to

var Data;

Data = (function() {
  function Data($log, $q) {
    var getData1, getData2, getSomeComboData;
    getData1 = function() {
      var data1;
      data1 = $q.defer();
      return data1.promise;
    };
    getData2 = function() {
      var data2;
      data2 = $q.defer();
      return data2.promise;
    };
    getSomeComboData = function() {
      var comboData;
      comboData = $q.defer();
      $q.all(getData1, getData2).then(function(Data1, Data2) {});
      return ComboData.promise;
    };
    return {
      getData1: getData1,
      getData2: getData2,
      getSomeComboData: getSomeComboData
    };
  }

  return Data;

})();

angular.module('app').factory('Data', ['$log', '$q', Data]);

This way you need not worry about the this context, and it becomes evident what the exposed API is by observing the return statement.

CaryLandholt avatar Aug 30 '15 01:08 CaryLandholt