AngularJS : sharing controller between states in angular-ui router - angularjs

I have these router.js inside my ionic app ,
myapp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'AppCtrl'
})
.state('app.myprofile', {
url: "/myprofile",
abstract: true,
views: {
'menuContent': {
controller : "myprofileCtrl",
templateUrl: "templates/myprofile.html"
}
}
})
.state('app.myprofile.info', {
url: "/info",
controller: "profileinfoCtrl",
templateUrl: "templates/profile/info.html"
})
.state('app.myprofile.location', {
url: "/location",
controller: "profilelocationCtrl",
templateUrl: "templates/profile/location.html"
})
$urlRouterProvider.otherwise('/');
});
I need a way to share controller scopes between myprofile state and myprofile.location state and myprofile.info state too .
I am using ionic framework
in myprofileCtrl
myapp.controller("myprofileCtrl",function($scope,Authy ,Auth,$http ,$rootScope){
$scope.view_loading = true;
Authy.can_go().then(function(data){
$scope.profile =data.profile;
});
});
in profilelocationCtrl
myapp.controller("profilelocationCtrl",function($scope,Authy ,Auth,$http ,$rootScope){
console.log($scope.profile);
});
I got undefined in the console

I think the problem is that since $scope.profile is set after an ajax call, when the myprofile.location state is reached initially, then profile variable is still undefined on the parent $scope, what you could do is $watch the profile variable, or better just broadcast an event downwards when you receive it fro the server call using $broadcast.
$broadcast dispatches the event downwards to all child scopes, so you could do:
myapp.controller("myprofileCtrl",function($scope,Authy ,Auth,$http ,$rootScope){
$scope.view_loading = true;
Authy.can_go().then(function(data){
$scope.profile =data.profile;
$scope.$broadcast('profileSet', data.profile);
});
});
and in the myprofile.location` state:
myapp.controller("profilelocationCtrl",function($scope,Authy,Auth,$http,$rootScope){
$scope.$on('profileSet', function(event, data) {
console.log(data);
});
}
});
Have a look at this demo plunk I just made.

Related

ui-router nested states, basic understanding

I'm trying to create a nested state config. When I go with the simple non-nested it works, but when I attempt to do it in a nested fashion it fails.
Below is the working code: (Notice the last state 'new')
app.config(
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: '/views/home.html',
controller: 'MainCtrl',
resolve: {
qstnrPromise: ['qstnrs', function(qstnrs) {
return qstnrs.getAll();
}]
}
})
.state('questionnaires', {
url: '/questionnaires/{id}',
templateUrl: '/views/questionnaire.html',
controller: 'QuestionsCtrl',
resolve: {
questionnaire: ['$stateParams', 'qstnrs', function($stateParams, qstnrs){
return qstnrs.get($stateParams.id);
}]
}
})
.state('new', {
url: '/questionnaires/{id}/new',
template: '<h3> testy </h3>'
});
//$urlRouterProvider.otherwise('home');
$urlRouterProvider.otherwise(function($injector, $location){
$injector.invoke(['$state', function($state) {
$state.go('home');
}]);
});
});
If I attempt to change it with the following, it fails. The URL on browser changes but I don't receive the template.
.state('questionnaires.new', {
url: '/new',
template: '<h3>New question</h3>'
});
Have I understood states incorrectly? Or where have I gone wrong?
Try changing your new state to:
.state('new', {
url: '/new',
parent: 'questionnaires',
template: '<h3>New question</h3>'
})
See if that works for you.
You can make the questionnaires state abstract.
$stateProvider
.state('questionnaires', {
abstract: true,
url: '/questionnaires',
})
.state('questionnaires.new', {
// url will become '/questionnaires/new'
url: '/new'
//...more
})
But in this case you will need to add one additional nested state in order to implement the functionality you need for the $stateParams.id.

Redirect to different ui-router state with same url from server?

Currently I have a state 'home' which resides at the url '/'. After a user connects, the 'client' state is loaded, which also resides at the url '/' and the session is updated. Is it possible to make it so that if the user reloads the page, the 'client' state is loaded immediately instead of the 'home' state? If they were at different urls, I could simply have the server perform a redirect but I would like them both to be at the base url '/'. Is there some functionality in ui-router that would let me achieve this?
Here are my states:
app.config(function($stateProvider, $urlRouterProvider,$locationProvider) {
$stateProvider
.state('home', {
url: '/',
controller: 'HomePageConroller as homeCtrl',
templateUrl: '/views/partials/home.html',
onEnter: function($http,$state) {
$http.post('/checkconnected')
.success(function(data,status) {
if (data) {$state.go('client');}
});
}
})
.state('client', {
url: '/',
controller: 'ClientController as clientCtrl',
templateUrl: '/views/partials/client.html'
});
As you can see I am currently posting a check to the server to see if the client is connected and then doing a redirect from within the angular application, but I am not happy with this solution at all. The post takes time and so the home page is fully loaded and seen by the user before the client page is shown.
One solution I have considered is having another state called 'client redirect' that does reside at '/client' and has the same template as the 'client' state, which does the same $state.go on enter without the need of an $http.post (because the server already redirected based on the updated session). This would remove the delay and not flash the homescreen, however it does not seem elegant.
var app = angular.module("app", [
"ui.router"
]);
app.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/index');
$stateProvider
.state("app", {
abstract: true,
url: '/app',
templateUrl: "views/layout/app-body.html"
})
.state("index", {
url: "/index",
templateUrl: "views/home.html",
controller: 'signinController'
})
.state("signin", {
url: "/signin",
templateUrl: "views/pages/signin.html",
controller: 'signinController'
})
.state("signup", {
url: "/signup",
templateUrl: "views/pages/signup.html",
controller: 'signupController'
})
.state('app.home', {
url: '/home',
templateUrl: 'views/home/home.html',
controller: 'homeController'
})
.state('app.dashboard', {
url: '/dashboard',
templateUrl: 'views/dashboard/dashboard.html',
controller: 'dashboardController'
})
.state('app.profile', {
url: '/profile',
templateUrl: 'views/pages/profile.html',
controller: 'profileController'
});
});
Visit http://embed.plnkr.co/IzimSVsstarlFviAm7S7/preview?
Okay here is how I solved this. I renamed the url of 'client' from '/' to '/client'. On my server the get request checks if the user is connected and redirects to get '/client' if so (which renders the exact same angular app only the url is different). Then I modified my client to state to onEnter change $location.path(). Realizing this is practically the same as $state.go, I used the event handler for $stateChangeStart to prevent the state transition. Final code looks like this:
app.config(function($stateProvider, $urlRouterProvider,$locationProvider) {
$stateProvider
.state('home', {
url: '/',
controller: 'HomePageConroller as homeCtrl',
templateUrl: '/views/partials/home.html'
})
.state('client', {
url: '/client',
controller: 'ClientController as clientCtrl',
templateUrl: '/views/partials/client.html',
onEnter: function($location){$location.path('/');}
});
$urlRouterProvider.otherwise('/');
$locationProvider.html5Mode(true);
});
app.run(['$rootScope', function($rootScope) {
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
if (fromState.name == 'client' && toState.name == 'home') {
event.preventDefault();
}
});
}]);
If I can clean this up further please comment below.

Ionic $state.go not working on device

I'm currently working on an app, build using Ionic. My problem is that $state.go is only working in the browser but not on the phone. This seem to be a common problem, but after reading a lot of answers to the same questions, I still can't figure out how to fix it.
The general fix seems to be to ensure you're using relative URLs as explained here: Using Angular UI-Router with Phonegap but I still can't get it to work. What am I missing?
Link to plunker: http://plnkr.co/edit/qFJ1Ld6bhKvKMkSmYQC8?p=preview
App.js structure:
....
$stateProvider
.state('parent', {
url: "/",
templateUrl: "parent.html"
})
.state('parent.child', {
url: "child",
templateUrl: "child.html"
})
$urlRouterProvider.otherwise("/")
})
....
For state.go to work you have to inject $state dependency to your controller
app.controller('ParentCtrl', ['$scope', '$state', function($scope, $state) {
$scope.$state = $state
}]);
app.controller('MenuCtrl', ['$scope', '$state', function($scope, $state){
$scope.goTo = function(){
$state.go('menu.kategorier');
}
}]);
and you have to register the state you want to goto in $stateProvider
$stateProvider
.state('menu.kategorier', {...})
and to get to that state you have to go from parent state like 'menu' in this case. you cannot change state from 'parent' to 'menu.kategorier' but you can goto 'parent.child' from 'parent'
I solved it by changing my setup for the nested views, based on this example: http://codepen.io/mhartington/pen/Bicmo
Here is my plunker, for those who are interested:
Plunker: http://plnkr.co/edit/2m5bljMntpq4P2ccLrPD?p=preview
app.js structure:
$stateProvider
.state('eventmenu', {
url: "/event",
abstract: true,
template: "<ion-nav-view name='menuContent'></ion-nav-view>"
})
.state('eventmenu.home', {
url: "/home",
views: {
'menuContent' :{
templateUrl: "home.html"
}
}
})
.state('eventmenu.home.home1', {
url: "/home1",
views: {
'inception' :{
templateUrl: "home1.html"
}
}
})

tell ui-router to not change location on state defintion

In ui-router, when you call state.go, you can define options to prevent the location from changing by passing {location:false}. However, how do I define a state using $stateProvider.state so it doesn't change the location? I've defined a rule for custom URL handling, but now it is changing the location value.
I have foo state -
$stateProvider
.state('foo', {
url: '/foo'
templateUrl: '',
controller: function($scope) {
console.log('made it!');
}
});
I have a custom rule -
$urlRouterProvider.rule(function ($injector, $location) {
// some logic
return '/foo';
});
This works exactly how I want it to except that is changes the location and appends #/foo to the location. I don't want it appended.
I created working example here. It is extended version of the solution presented here: How not to change url when show 404 error page with ui-router
There is a snippet of code, which should show how to use "foo" state without url change.
Firstly, there is our rule, which will redirect to 'foo' state - just in case if the /home is passed as url (an example of decision)
$urlRouterProvider.rule(function($injector, $location) {
if ($location.path() == !"/home") {
return false;
}
var $state = $injector.get("$state");
// move to state, but do not change url
$state.go("foo", {
location: false
})
return true;
});
Here are our example states, which do have url setting
// States
$stateProvider
.state('home', {
url: "/home",
templateUrl: 'tpl.html',
})
.state('parent', {
url: "/parent",
templateUrl: 'tpl.html',
})
.state('parent.child', {
url: "/child",
templateUrl: 'tpl.html',
controller: 'ChildCtrl',
})
Foo does not have url
.state('foo', {
//url: '/foo',
templateUrl: 'tpl.html',
});
Check it here

AngularJS keep template data when switching route?

In state llantas.ordenes I have a jqGrid and other controls as well as in llantas.inventarios
so whenever I switch from #/llantas/ordenes to #/llantas/inventarios I loose the controls data and the jqGrid table is being redraw, so the question is if its possible to keep view data when switching from route to route?
This is my router.js:
ng.route(function($stateProvider, $urlRouterProvider){
// Now set up the states
$stateProvider
.state('llantas', {
url: "/Llantas",
templateUrl: "templates/llantas/index.html"
})
// Ordenes
.state('llantas.ordenes', {
url: "/ordenes",
templateUrl: "templates/llantas/ordenes/index.html",
controller: function($scope, $injector) {
require(['js/controllers/llantas/ordenes/index'], function(llantasOrdenesIndexCtrl) {
$injector.invoke(llantasOrdenesIndexCtrl, this, {'$scope': $scope});
});
}
})
// Inventarios
.state('llantas.inventarios', {
url: "/inventarios",
templateUrl: "templates/llantas/inventarios/index.html",
controller: function($scope, $injector) {
require(['js/controllers/llantas/inventarios/index'], function(llantasInventariosIndexCtrl) {
$injector.invoke(llantasInventariosIndexCtrl, this, {'$scope': $scope});
});
}
})
});
I removed the UI Router and set reloadOnSearch = false on every route.

Resources