Firebase + angularfire getting current user before controller loads - angularjs

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

Related

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

angular 1.5 component wait data

i am trying to use au component in order to display my data.
In my template i have :
{{myDatas}}
<my-cmp data="myDatas"></my-cmp>
i displayed {{myDatas}} to be sure there was data
here is my code for my component :
(function() {
'use strict';
angular
.module('myApp.test')
.controller('TestController', TestController)
.component('myCmp', {
templateUrl: 'myTemplate.html',
bindings: {
data: '='
},
controller: myController
});
function TestController($scope, $stateParams, ResidencesFactory) {
$scope.myDatas = TestFactory.read({id: $id});
}
function myController($scope) {
console.log($scope.$ctrl.data.nbElements);
}
})();
This code doesn't works.
But if i replace $scope.myDatas with the expected JSON, it works.
here is the code of TestFactory :
(function () {
'use strict';
angular
.module('core.test')
.factory('TestFactory', TestFactory);
function TestFactory($resource) {
return $resource(
'/api/test/:id',
{
id: '#id'
},
{
query: {
method: 'GET',
isArray: true
},
read: {
method: 'GET'
}
}
);
}
})();
So i think i have to wait the data from the $resource of my TestFactory but how can i do this ?
Thanks
EDIT
here is what i did. i replaced
$scope.myDatas = TestFactory.read({id: $id});
with
TestFactory.read({id: $id}).$promise.then(function(response){
$scope.myDatas = response;
});
And in my component controller, i had the $onInit like this :
this.$onInit = function () {
console.log($scope.$ctrl.data);
$scope.percent = parseFloat(($scope.$ctrl.data.nbElements/ $scope.$ctrl.data.nbAllElements * 100).toFixed(2))
}
But in the chrome console, it tells me that $scope.$ctrl.data is undefined, and the error "TypeError: Cannot read property 'nbElements' of undefined
if i do
console.log($scope.$ctrl);
i have this in chrome console :
>myController
>$onInit: function()
>data: m
>__proto__:Object
Chrome tell me myCotroller was evaluated so i think myCotroller is not waiting the data before building my properties. What am i doing wrong ?
problem solved adding an ng-if condition in my template
<my-cmp ng-if="myDatas" data="myDatas"></my-cmp>
thanks for your help

angular how to prevent user typing url directly to access pages when he is logout

I am using $stateProvider, so I have lots of states.
considering below scenario:
user is already logout, and he types url in the browser directly, like www.example.com/home, I should redirect it to the login page, which is www.example.com/login
how to implement this? one of the methods is to check if the session is active in run block. is it a good practice to call backend API in the run block?
UPDATE:
According to Ryan's suggestion, it calls backend api to check if user is logged in
$transitions.onBefore({to: 'home'}, function(transition) {
var $state = transition.router.stateService;
let promise = jsonService.heartBeat()
promise.then(data => {
if(!data.hasOwnProperty('data')) {
$state.go('login')
}
}, () => {
$state.go('login')
})
});
Levi's answer is correct for UI-Router pre-version 1.0. For UI-Router 1.0, the state change events such as $stateChangeStart are deprecated and this will no longer work. You can use the $transitions service instead.
function run ($transitions, Auth) {
// 'to' param is the state name; 'main.**' will match 'main' and all sub-states
$transitions.onBefore({to: 'main.**'}, function (transition) {
var $state = transition.router.stateService;
if (!Auth.isAuthenticated()) {
$state.go('login');
}
});
}
run.$inject = ['$transitions', 'Auth'];
app.run(run);
I ran into same problem months ago. Instead of using resolve, I check if the user is logged when state changes, defining run module and listening $stateChangeStart event, then check if the current state required authentication. If so, check if the user is logged in.
angular.module('portfolio.manager').config(function ($logProvider, $stateProvider) {
'use strict';
$stateProvider
.state('portfolio.manager', {
url: '/manager',
resolve: {
portfolioAuthService: 'portfolioAuthService',
User: function(portfolioAuthService){
return portfolioAuthService.getUser();
},
Portfolios: function (User, portfolioManagerService) {
return portfolioManagerService.getPortfolios();
}
},
data: {
requiredAuthentication: true
},
views: {
'main#': {
templateUrl: 'app/portfolio/manager/portfolio-manager.html',
controller: 'PortfolioManagerCtrl'
},
'no-portfolios#portfolio.manager': {
templateUrl: 'app/portfolio/manager/partials/no-portfolios.html'
},
'create#portfolio.manager': {
templateUrl: 'app/portfolio/manager/partials/create.html'
}
}
})
})
.run(run);
run.$inject = ['$rootScope','$state','loggedIn'];
function run($rootScope,$state,loggedIn){
$rootScope.$on('$stateChangeStart',function(e,toState){
if ( !(toState.data) ) return;
if ( !(toState.data.requiredAuthentication) ) return;
var _requiredAuthentication = toState.data.requiredAuthentication;
if (_requiredAuthentication && !loggedIn.checkUser() ){
e.preventDefault();
$state.go('portfolio.login', { notify: false });
console.log('not authorized');
}
return;
});
};

Angular ui router undefined function in controller

I have a ui route that looks like the following
.state('question', {
url: '/question',
templateUrl: 'views/templates/question.view.htm',
controller: 'QuestionController',
resolve: {
questions_preload: function(Question) {
return Question.query();
}
}
});
The Question.query() function looks like
Question.query = function () {
var deferred = $http.get(HATEOAS_URL);
return SpringDataRestAdapter.processWithPromise(deferred).then(function (data) {
Question.resources = data._resources("self");
return _.map(data._embeddedItems, function (question) {
return new Question(question);
});
});
};
and the controller that should have the questions preloaded at the start beings like this
angular.module('myapp').controller('QuestionController', function ($scope, Question) {
$scope.questions = questions_preload;
Unfortunately while the Question.query() method runs correctly the questions_preload which I figured would house the array is undefined when the controller executes.
I believe it's something to do with the deferred in the query function?
Would anyone have any idea?
Thanks,
Mark.
You have to inject the questions_preload value into your controller:
angular.module('myapp')
.controller('QuestionController',
function ($scope, Question, questions_preload) {
...
$scope.questions = questions_preload;
As you had it you were simply accessing an undefined variable.
The use of a promise in Question.query() doesn't matter here as angular ui-router will wait until the promise has resolved before it instantiates your controller.

passing complex type as param

Angular js / angular ui router 0.2.15
I am trying to pass complex js array into the controller using $state.go
Following is my code can you help. looks like following code throwing error
Error: [$injector:unpr] http://errors.angularjs.org/1.2.28/$injector/unpr?p0=servicesProvider%20%3C-%20services
.js file
var services = {complex type};
$state.go("linearOfferProcess", {'services': services});
in my route.js
state('linearOfferProcess', {
url: '/linearOfferProcessor',
templateUrl: '/partials/linear_process.html',
controller: 'linearProcessController',
services:
function($stateParams) {
return $stateParams.services;
}
}
controller
angular.module('app').controller('linearOfferProcessController',function($scope) {
$scope.services = services;
});
Unfortunately I don't know any possible of accomplishing this, but you could try doing it using a Factory. I made a small mockup for you, in the container I'm storing the services and creating a unique ID for every complex object. So you can retrieve it whenever you want.
angular.module('app').factory('ServicesContainer', function() {
var counter = 1;
return {
container: {},
add: function(services) {
container[counter] = services;
return counter;
}
};
});
angular.module('app').controller('SomeController', function(ServicesContainer, $state) {
var id = ServicesContainer.add({ complex object });
$state.go('services', {
id: id
});
});
angular.module('app').config(function($stateProvider) {
$stateProvider.state('services', {
url: '/{id}',
onEnter: function(ServicesContainer, $stateParams, $log) {
$log.info('Services', ServicesContainer[$stateParams.id]);
}
});
});

Resources