Access scope variable from the other controller within the nested state - angularjs

How to access other state scope variable from another state ctrl?
If in 'session.index.detail' state, I want to access leftPanel scope variable from rightPanel Ctrl is it possible? What I want to do is I have a form in rightPanel, when I click save, I want to add the new data object back to leftPanel list and refresh it after it is successfully added to the database.
.state('session', {
abstract: true,
templateUrl: '/schedule/_session.html'
})
.state('session.index', {
url: '/sessionmang',
views: {
'leftPanel#session': {
controller: 'SessionCtrl',
controllerAs: 'vm',
templateUrl: '/schedule/_sessionPanel.html'
},
'rightPanel#session': {
templateUrl: '/schedule/_sessionDetailPanel.html'
}
}
})
.state('session.index.detail', {
params: {
sessionObj: null,
sessionTypeObj: null
},
views: {
'rightPanel#session': {
controller: 'SessionDetailCtrl',
controllerAs: 'vm',
templateUrl: '/schedule/_sessionDetailPanel.html',
resolve: {
sessionObj: ['$stateParams', function ($stateParams) {
return $stateParams.sessionObj;
}],
sessionTypeObj: ['$stateParams', function ($stateParams) {
return $stateParams.sessionTypeObj;
}]
}
}
}
});

I think the best way is to create a service that holds the data you want to share.
And share it between the controllers.
Or use broadcasting to talk between the controllers and pass data over that way

the simplest way is, you could use events like this.
when you click save, you will do
$scope.$broadcast('myevent', data);
from the rightCtrl and from the leftCtrl you could do
$scope.$on('myevent', function(event,data) {
//do your updates here
})

Related

ui.router nested States, nested Views: $rootScope.$on $rootScope.$broadcast doesnt connect

i use $rootScope to send data to a controller from a nested state and view
It works between 'items' and rootSelector,
It does not work between 'detail' and rootSelector
something blocks my rootScope events.
var listState = {
name: 'playlist.list',
parent: 'playlist',
url: '/list?',
resolve: {
playlistsDb: resolvePlaylistsFromDb,
},
views: {
// target the unnamed view in the playlist state
'#playlist': {
templateUrl: 'app/playlists/list/list.html',
controller: 'PlaylistListController',
controllerAs: 'list'
},
// target the content view in the playlist.list state
'content#playlist.list': {
templateUrl: 'app/playlists/list/items/items.html',
controller: 'PlaylistItemsController',
controllerAs: 'items'
},
// target the rootSelector view in the playlist state
'rootSelector#playlist.list': {
templateUrl: 'app/selector/rootSelector.html',
controller: 'rootSelectorController',
controllerAs: 'rootSelector',
resolve: {
selectedPlaylistId: resolveSelectedPlaylistId,
}
}
}
};
I can send and receive events via $rootScope.broadcast and $scope.$on
from PlaylistItemsController "items" to rootSelector
but i can't receive them if they come from the nested "detailState"
var detailState = {
name: 'playlist.list.detail',
parent: 'playlist.list',
url: '/detail/:id',
views: {
'detail#playlist.list': {
templateUrl: 'app/playlists/list/detail/detail.html',
controller: 'PlaylistDetailController',
controllerAs: 'detail',
resolve: {
playlistDb: resolvePlaylistDb,
}
}
}
};
Ok, events didnt go through cause
$scope.$on('removeTrackFromPlaylist'), function (event, args) { }
was no code error in VS2015

ui-router automatically redirects out of state

I've got the following route:
.state('app.base.patient', {
url: '/store/:storeID/patient/:patientID',
template: template,
controller: patientCtrl,
controllerAs: 'vm',
resolve: {
patientObj: ['$stateParams', 'patientResource', function($stateParams, patientResource) {
if ($stateParams.patientID !== '') {
return patientResource.get($stateParams.patientID);
}
return null;
}]
}
});
I'm able to navigate to it through the app perfectly fine (using $state.go)
which gets me to (for example):
'/store/105/patient/8a7f7e785279bc1f015279be7cb40001'
But when I try to refresh the page on with the same url I get redirected to:
'/store/105/patient/'
Any ideas what might be causing this? I've been adding more and more logging but I can't see anything that looks obviously wrong
The "parent" view is the store select view:
$stateProvider
.state('app.base.store', {
url: '/store',
template: template,
controller: storeCtrl,
controllerAs: 'vm'
});
Your URLs indicate the states should be nested, but the state definitions do not reflect that. Your patient state should be nested in your store state. The patient state would change to something like this:
.state('app.base.store.patient', {
url: '/patient/:patientID',
template: template,
controller: patientCtrl,
controllerAs: 'vm',
resolve: {
patientObj: ['$stateParams', 'patientResource', function($stateParams, patientResource) {
if ($stateParams.patientID !== '') {
return patientResource.get($stateParams.patientID);
}
return null;
}]
}
});
Meanwhile, your store state would look like this:
$stateProvider
.state('app.base.store', {
url: '/store/:storeID',
template: template,
controller: storeCtrl,
controllerAs: 'vm'
});
Then, as long as your views are nested properly, you can navigate to the patient state from the store view like so:
ui-sref="app.base.store.patient({patientID: vm.patientID})"
Or in controller code like so:
$state.go("app.base.store.patient", { storeID: vm.storeID, patientID: vm.patientID });
The problem turned out to be a rogue
this.$state.go('app.base.patient', {storeID: value.id, patientID: null});
I originally added the explicit patientID: null as I thought it's needed - it's not and will cause the said problem during load.

controller doesn't work in ui-router

I have this home state in my router config,
.state('home', {
url: '',
controller: 'addMovieCtrl',
views: {
"frontpage": {
templateUrl: '../assets/angular-app/templates/_frontpage.html',
// controller: 'addMovieCtrl'
},
"movieoverview": {
templateUrl: '../assets/angular-app/templates/_movieTemplate.html',
// controller: 'addMovieCtrl'
}
}
})
I want both my views to work with the addMovieCtrl controller, but if I assign the controller in the state (like in the example above) the controller doesn't get called.
When I assign the controller in the view (which I now have commented out) it does get called, but I'm pretty sure I should be able to asign a controller to a state and that adds the controller to all the views. Right?
No, you need to assign a controller to each view. So, your commented out code is the right way to do it.
views: {
"frontpage": {
templateUrl: '../assets/angular-app/templates/_frontpage.html',
controller: 'addMovieCtrl'
},
"movieoverview": {
templateUrl: '../assets/angular-app/templates/_movieTemplate.html',
controller: 'addMovieCtrl'
}
}

angular state get param child

How can I get a param from child?
This is what I do:
$state.go('demo.content', {proces: '10'})
And then in controller 'Main' I need the value of param proces.
.state('demo', {
url: '/',
abstract: true,
views: {
'main': {
templateUrl: './App/main.html',
controller: 'Main'
}
})
.state('demo.content', {
url: '/monitoring',
views: {
'chart': {
templateUrl: './App/chart.html',
controller: 'Chart'
},
'grid': {
templateUrl: './App/grid.html',
controller: 'Grid'
},
params: {proces: '4'}
})
The point here is, that any call to 'demo.content' with different param process should re-call/re-init the controller of such state view.
Other words, only controllers which are part of this state, could consume the process as a part of injected params.
So, if there is really any part in main controller, which needs handle (changing) process id, it should be moved to the demo.content state, as another view
If this is the true, the best we can do is to move that view from parent into state:
.state('demo.content', {
url: '/monitoring',
views: {
'chart': {
templateUrl: './App/chart.html',
controller: 'Chart'
},
'grid': {
templateUrl: './App/grid.html',
controller: 'Grid'
},
// this would do the stuff fro main controller
// based on changing params
'mainProcessor': {
templateUrl: './App/mainProcessor.html',
controller: 'mainProcessor'
}
This, and only this way, you can be sure, that different param value will trigger the "mainProcessor" controller and allow him to do the job

Angular ui-router to accomplish a conditional view

I am asking a similar question to this question: UI Router conditional ui views?, but my situation is a little more complex and I cannot seem to get the provided answer to work.
Basically, I have a url that can be rendered two very different ways, depending on the type of entity that the url points to.
Here is what I am currently trying
$stateProvider
.state('home', {
url : '/{id}',
resolve: {
entity: function($stateParams, RestService) {
return RestService.getEntity($stateParams.id);
}
},
template: 'Home Template <ui-view></ui-view>',
onEnter: function($state, entity) {
if (entity.Type == 'first') {
$state.transitionTo('home.first');
} else {
$state.transitionTo('home.second');
}
}
})
.state('home.first', {
url: '',
templateUrl: 'first.html',
controller: 'FirstController'
})
.state('home.second', {
url: '',
templateUrl: 'second.html',
controller: 'SecondController'
});
I set up a Resolve to fetch the actual entity from a restful service.
Every thing seems to be working until I actually get to the transitionTo based on the type.
The transition seems to work, except the resolve re-fires and the getEntity fails because the id is null.
I've tried to send the id to the transitionTo calls, but then it still tries to do a second resolve, meaning the entity is fetched from the rest service twice.
What seems to be happening is that in the onEnter handler, the state hasn't actually changed yet, so when the transition happens, it thinks it is transitioning to a whole new state rather than to a child state. This is further evidenced because when I remove the entity. from the state name in the transitionTo, it believes the current state is root, rather than home. This also prevents me from using 'go' instead of transitionTo.
Any ideas?
The templateUrl can be a function as well so you check the type and return a different view and define the controller in the view rather than as part of the state configuration. You cannot inject parameters to templateUrl so you might have to use templateProvider.
$stateProvider.state('home', {
templateProvider: ['$stateParams', 'restService' , function ($stateParams, restService) {
restService.getEntity($stateParams.id).then(function(entity) {
if (entity.Type == 'first') {
return '<div ng-include="first.html"></div>;
} else {
return '<div ng-include="second.html"></div>';
}
});
}]
})
You can also do the following :
$stateProvider
.state('home', {
url : '/{id}',
resolve: {
entity: function($stateParams, RestService) {
return RestService.getEntity($stateParams.id);
}
},
template: 'Home Template <ui-view></ui-view>',
onEnter: function($state, entity) {
if (entity.Type == 'first') {
$timeout(function() {
$state.go('home.first');
}, 0);
} else {
$timeout(function() {
$state.go('home.second');
}, 0);
}
}
})
.state('home.first', {
url: '',
templateUrl: 'first.html',
controller: 'FirstController'
})
.state('home.second', {
url: '',
templateUrl: 'second.html',
controller: 'SecondController'
});
I ended up making the home controller a sibling of first and second, rather than a parent, and then had the controller of home do a $state.go to first or second depending on the results of the resolve.
Use verified code for conditional view in ui-route
$stateProvider.state('dashboard.home', {
url: '/dashboard',
controller: 'MainCtrl',
// templateUrl: $rootScope.active_admin_template,
templateProvider: ['$stateParams', '$templateRequest','$rootScope', function ($stateParams, templateRequest,$rootScope) {
var templateUrl ='';
if ($rootScope.current_user.role == 'MANAGER'){
templateUrl ='views/manager_portal/dashboard.html';
}else{
templateUrl ='views/dashboard/home.html';
}
return templateRequest(templateUrl);
}]
});

Resources