0

I've got a little angular (v1.5.11) app where I'm trying to instantiate an object from a string variable. This code used to work in my old setup but after changing from bower/gulp to webpack (3.8.1), I'm now getting the error below. I'm not sure whether this is caused by my new import statement or something.

A similar question (Javascript "Not a Constructor" Exception while creating objects) dicussed the problem but I wasn't able to get get any of the solutions to work in my example which is why I'm thinking it might be down to the import or the pojo structure itself?

Error:

TypeError: $window[iteratorType] is not a constructor

Code:

MyService.js

import ListIterator from './util/listiterator.pojo.js';

MyService.$inject = ['$log', '$window'];

function MyService($log, $window) {
  ...
  // this variable is obviously dynamic but for now I made it a static string
  var iteratorType = 'ListIterator';
  var iterator = new $window[iteratorType](); //<-- breaks as $window[iteratorType] is undefined
  //var iterator = new ListIterator();  <-- this works just fine
  ...

listiterator.pojo.js

var ListIterator = function() {
    this.executedIterations = 0;
    this.iter = null;
};
...
export default ListIterator;
jimmy
  • 3,481
  • 3
  • 16
  • 27
  • You are importing `ListIterator` class in `MyService` file. Why don't you use this `ListIterator` class directly? – sphirate.thremer Nov 16 '17 at 11:53
  • I've added an edit explaining that the answers in this question didn't help me solve my issue. – jimmy Nov 16 '17 at 12:18
  • You used global function before. And switched to import. It's no longer available on window. And you already stated that `var iterator = new ListIterator()` works fine. It's unclear what the problem is. – Estus Flask Nov 16 '17 at 13:03
  • @estus The line: var iterator = new $window[iteratorType](); doesn't work and creates the error above. The line after that is just to show that the function is available in general. – jimmy Nov 16 '17 at 13:31
  • So what is the question exactly? – Estus Flask Nov 16 '17 at 13:39
  • How can I fix the error so this line `var iterator = new $window[iteratorType]();` works? – jimmy Nov 16 '17 at 14:06
  • 1
    You can either expose functions you need to use there as globals like `window.ListIterator = ListIterator` (which doesn't look good), or switch from globals to idiomatic Angular alternatives, as one of the answer suggests. – Estus Flask Nov 16 '17 at 14:22
  • Got it, my confusion came from the fact that I thought ListIterator was already globally available. But I had to add `window.ListIterator = ListIterator;` after my import. At least I understand why now and can look for a better option (e.g. angular injection) – jimmy Nov 16 '17 at 15:49

2 Answers2

1

If you don't want to change any of your code, you could tell webpack to provide your service. This will make it available under window scope:

rules: [{
    test: require.resolve('./util/listiterator.pojo.js'), //the correct absolute path
    use: [{
        loader: 'expose-loader',
        options: 'ListIterator'
      }
    ]
  }
]

This is untested with your example, but works fine in my setup with Highcharts and AngularJS.

EDIT

You have to install npm i -D expose-loader of course.

scipper
  • 2,314
  • 1
  • 12
  • 31
  • I'm fine with changing my code which is why I added the import statement that should basically end up doing the same just more local to this service in my opinion. – jimmy Nov 16 '17 at 12:18
1

This is angular way:

app.factory('F1', function() {...})
app.factory('F2', function() {...})
app.factory('F3', function() {...})

app.factory('MyService', function($injector) {
  var name = 'F1';
  var someFactory = $injector.get(name);
})
Petr Averyanov
  • 8,421
  • 2
  • 18
  • 30
  • I'm not injecting an angular service, but just like to use a javascript constructor available in the global scope. – jimmy Nov 16 '17 at 12:27
  • I'm accepting this as the correct answer as it's a nicer way to rewrite my code. – jimmy Nov 16 '17 at 16:07