Nikita Zhuykov
Nikita Zhuykov

Reputation: 31

Cannot read property 'injector' of null when downgrading angular 2 service

everyone. I need help with such problem.

I have such code for my angular 1.x app.js:

angular.module('app', []);

angular.module('app.test', ['app'])
    .config(($stateProvider) => 
        $stateProvider.state('base', {
                url: '/',
                controller: 'TestStateCtrl',
                resolve: {
                    authenticationCheck: ['angularNg1Service', angularNg1Service=> {
                        angularNg1Service.test1();
                    }]
                }
            })
        })
    .run((angularNg1Service) => {
        angularNg1Service.test2();

    });

Here is the code of my angularNg1Service:

    angular.module('app')
    .service('angularNg1Service',
        function (angularNg2Service} {
            //some code here 
}

My angularNg2Service is downgraded before .run function of angular 1.x module starts:

window['angular']
        .module('app')
        .factory(
            'angularNg2Service',
            upgradeAdapter.downgradeNg2Provider(AngularNg2Service)
        );

But, I have an error message :

Cannot read property 'injector' of null

When .run function of angular 1.x module starts.

Here is my main.ts file:

import { upgradeAdapter } from './upgradeAdapter';
import { bootstrapNg1Components } from './app/ng1Components';    
bootstrapNg1Components(upgradeAdapter);// this function downgarades my AngularNg2Service

upgradeAdapter.bootstrap(document.querySelector('html'), ['app.start']);

I have read some similar problems but don't find any solution.

Also I have a lot of Angular2 Services which are downgraded.But the problem is just for one particular service that is injected into Angular1 Service that is used in .run function.

Upvotes: 3

Views: 272

Answers (1)

Roman Makarov
Roman Makarov

Reputation: 11

You can use workaround described here https://github.com/angular/angular/issues/10992: put your run code in setTimeout function.

angular.module('app.test', ['app'])
...
    .run(($injector) => {
        setTimeout(function() {
           var angularNg1Service = $injector.get('angularNg1Service');
           angularNg1Service.doSmth();
           // downgraded angularNg2Service is available here
           // inside of async function that will run after module.run method
           var angularNg2Service = $injector.get('angularNg2Service');
        },0);
    });

To be sure the application state does not start before application is configured (that performed in run method) you can add resolve for every state.

angular.module('app.test', ['app'])
    .config(($stateProvider) => 
        $stateProvider.state('base', {
            url: '/',
            controller: 'TestStateCtrl',
            resolve: {
                appBootstrapped: ['appBootstrapStateService', () => {
                    return appBootstrapStateService.statePromise;
                ]},
                authenticationCheck: ['angularNg1Service', 'appBootstrapped', (angularNg1Service, appBootstrapped) => {
                    angularNg1Service.test1();
                }]
            }
        })
    })

And to make it works you should change bootstraped state at the end of module.run method

angular.module('app.test', ['app'])
    ...
    .run(($injector) => {
        setTimeout(function() {
            ...
            var appBootstrapStateService = $injector.get('appBootstrapStateService');
            appBootstrapStateService.complete(); // allow state work
        },0);
    });

appBootstrapStateService is angularJS service like

angular.module('app')
    .service('appBootstrapStateService', function () {
        const stateSubject = new Rx.Subject();
        this.statePromise = stateSubject.asObservable().toPromise();

        this.complete = () => {
            stateSubject.complete();
        };
    });

Upvotes: 1

Related Questions