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;
8
  • You are importing ListIterator class in MyService file. Why don't you use this ListIterator class directly? Commented Nov 16, 2017 at 11:53
  • I've added an edit explaining that the answers in this question didn't help me solve my issue. Commented Nov 16, 2017 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. Commented Nov 16, 2017 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. Commented Nov 16, 2017 at 13:31
  • 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. Commented Nov 16, 2017 at 14:22

2 Answers 2

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);
})
Sign up to request clarification or add additional context in comments.

2 Comments

I'm not injecting an angular service, but just like to use a javascript constructor available in the global scope.
I'm accepting this as the correct answer as it's a nicer way to rewrite my code.
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.

1 Comment

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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.