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

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.

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();
};
});

Related

Angular js cycle when declare component

I have an Angular js module
var appModule = angular.module('appModule', ['datatables','ngMaterial', 'ui.select'])
when i declare a new component using my appModule, I refresh my app in browser but it creates a request load cycle in XHR and my app breaks
appModule.component('myCustomTable', {
templateUrl: 'table-component',
controller: function () {
this.user = {
name: 'user name'
};
}
});
Am using AngularJS 1.65
It might happen because your controller is an anonymous function.
(According to: https://docs.angularjs.org/tutorial/step_03)
appModule.component('myCustomTable', {
templateUrl: 'table-component',
controller: function () { // <- Here
this.user = {
name: 'user name'
};
}
});

How do i inject $transition$ to write jasmine test cases for component based routing to test resolve object?

I want to write test case for resolve object which has $transition$ as dependency.
Here is my config:
angular.module("testing")
.config(function($stateProvider) {
$stateProvider.state({
name: 'component.view',
url: '/:componentName',
resolve: {
componentName: ($transition$) => $transition$.params().componentName
}
});
});
So i want to test the resolve object using jasmine. Please suggest me a work around . Thanks in advance.
Got the solution. We can solve this by creating a provider. Here it is:
beforeEach(module('testing', function ($provide) {
$provide.provider("$transition$", function () {
this.$get = function () {
return {
'params':function(){
return {
'componentName':'Component one'
};
}
};
}
})
}));

Angular js controller with factory service

Is it possible to call a factory service from a controller that it's been located on a different js file (an example will be nice), or the controller and factory service have to be on the same file ?
Thanks
You can include both scripts in index.html and then use the service in your controller:
index.html
<script src="js/pictures/picture.service.js"></script>
<script src="js/pictures/controllers/pictures.js"></script>
Here is the service picture.service.js:
(() => {
angular.module('gallery').factory('Picture', ['$http', 'Upload', function ($http, Upload) {
return {
all: () => {
return $http.get('/api/pictures');
},
findById: (id) => {
return $http.get(`/api/pictures/${id}`);
},
create: (picture) => {
return Upload.upload({
url: '/api/pictures/create',
data: picture
});
}
};
}]);
})();
Here is the controller where I am injecting the service:
(() => {
angular.module('gallery').controller('Pictures', ['Picture', function (Picture) {
let pictures = this;
// You might want to use .then instead of .success (deprecated)
Picture.all().success((data) => {
pictures.pictures = data;
});
}]);
})();
Here is an example github repo with a simple MEAN stack project.
https://github.com/NikolayKolibarov/MEAN-Simple-Gallery

How can I mock a provider when testing a config function in AngularJS?

I have a config function with this signature:
tmsNav = angular.module('tmsNav', ['tmsAuthSvc', 'tmsConfig', 'ui.router'])
tmsNav.config(function ($stateProvider, $urlRouterProvider, statesConfig) {
// uses the constant statesConfig to configure $stateProvider and $urlRouterProvider
});
Here is my describe block:
describe('tmsNav.config() >', function () {
it('configures states correctly', function () {
module('tmsConfig', function ($provide) {
$provide.constant('statesConfig', states1);
$provide.factory('$state', function () {
return {
state: function () {
console.log('state()!!!');
}
};
});
});
module('tmsNav');
inject(function ($state) {
expect($state.get().length).toBe(4);
});
});
});
The constant is successfully overwritten, but $stateProvider isn't. I've tried using $provide.factory('$state', ...), $provide.constant('$stateProvider', ...), $provide.value('$state', ...), etc... Nothing has worked.
I need to mock $stateProvider because once it's configured it retains that configuration going into the next test. So when I run subsequent tests I get errors about duplicate configuration values when I shouldn't.
The answer lies in the module() statements. I was trying to overwrite $stateProvider on the wrong module.
module('tmsConfig', function ($provide) {
$provide.constant('statesConfig', states1);
});
module('ui.router', function ($provide) {
$provide.provider('$state', function () {
this.state = function () {
console.log('state()!!!');
};
this.$get = function () {
return {
get: function () {
return [];
}
};
};
});
});
module('tmsNav');
This edit causes the test to pass if I reduce the length expectation to zero. That's not really the test I want anyway so I'll write a more robust mock with spies and such now that the provider issue is resolved.

Firebase + angularfire getting current user before controller loads

I'm following the official examples to fetch the user before the angular controller is fired but the controller is never fired when using this method. If I remove the resolve: state_resolver line the controller fires which means my resolver has something wrong. Any ideas what am I doing wrong here?
.config(function($stateProvider) {
var state_resolver;
state_resolver = {
"current_user": [
"simpleLogin", function(simpleLogin) {
return simpleLogin.$getCurrentUser();
}
]
};
return $stateProvider.state("dash", {
url: "/dash",
templateUrl: "templates/dash.html",
controller: "DashCtrl",
resolve: state_resolver
});
});
If the following example using $timeout works, then you probably have an issue with your simpleLogin service which does not respond.
.config(function($stateProvider) {
var state_resolver;
state_resolver = {
"current_user": function($timeout) {
return $timeout(function () {console.log('OK');}, 5000);
}
};

Resources