0

I want to use $http service inside my filter. Now I get the following error

angular.js:12477 TypeError: Cannot read property 'get' of undefined
    at factory (next-schedule-occurrence.filter.js:32)
...

How can I inject $http correctly?

HTML Template:

<p>Next execution: {{watcher._source.trigger.schedule.later | nextScheduleOccurrence}}</p>

Filter code:

/* global angular */
import moment from 'moment';
import later from 'later';

/*
* Get the next occurence of from the 'later' lib text schedule
*/
class NextScheduleOccurrence {

  /*
  * @param {string} schedule in English for the 'later' text parser
  */
  constructor(schedule) {
    this.schedule = schedule;
  }

  /*
  * @return {string} the future occurrence for the schedule
  */
  next(config) {
    if (config.es.watcher.schedule_timezone === 'local') {
      later.date.localTime();
    }
    return moment(later.schedule(later.parse.text(this.schedule)).next()).format('D/M/YYYY H:m:s');
  }

  /*
  * @param {string} schedule in English for the 'later' text parser
  */
  static factory(schedule, $http) {
    const filter = new NextScheduleOccurrence(schedule);
    return $http.get('../api/sentinl/config').then((config) => {
      return filter.next(config);
    });
  }
}

NextScheduleOccurrence.factory.$inject = ['schedule', '$http'];
export default angular.module('nextScheduleOccurrence', [])
.filter('nextScheduleOccurrence', () => NextScheduleOccurrence.factory);

UPDATE

I get the same error if I use a function for the filter instead of the class.

const NextScheduleOccurrence = function (schedule, $http) {
  return $http.get('../api/config').then((config) => {
    if (config.es.watcher.schedule_timezone === 'local') {
      later.date.localTime();
    }   
    return moment(later.schedule(later.parse.text(schedule)).next()).format('D/M/YYYY H:m:s');
  }); 
};

NextScheduleOccurrence.$inject = ['schedule', '$http'];
export default angular.module('nextScheduleOccurrence', []).filter('nextScheduleOccurrence', () => NextScheduleOccurrence);
srgbnd
  • 5,404
  • 9
  • 44
  • 80
  • 1
    (1) `constructor(schedule, $http) { this.$http = $http; ...` (2) use `this.$http.get(...)` – Aleksey Solovey Nov 28 '17 at 11:06
  • @AlekseySolovey I get the same error – srgbnd Nov 28 '17 at 11:23
  • you don't need to pass it as a parameter into the function itself, it's a public variable within a class, just use `this.$http` once you declare it in your constructor – Aleksey Solovey Nov 28 '17 at 11:40
  • 2
    DI went wrong there. Considering that NextScheduleOccurrence is factory function, it should be `.filter('nextScheduleOccurrence', NextScheduleOccurrence)`. And NextScheduleOccurrence should return a filter function, not class instance. It's unclear how the thing is supposed to work in your case, because A1 wasn't designed for async filters. You likely have XY problem, because `config` shouldn't be loaded like that. See https://stackoverflow.com/questions/47391797/initialize-angularjs-app-before-calling-the-controllers/47394275#47394275 for some ideas. – Estus Flask Nov 28 '17 at 11:44
  • Do you know, that filter function runs extremely often? Do you really want to send dozen of http requests? – Drag13 Nov 28 '17 at 11:53

1 Answers1

1

I think your factory method should return a function like this

static factory($http) {
  return function(schedule) {
    const filter = new NextScheduleOccurrence(schedule);
    return $http.get('../api/sentinl/config').then((config) => {
      return filter.next(config);
    });
  }
}
szydan
  • 2,318
  • 1
  • 15
  • 16