Hi I am having a problem trying to reload a part of my angular page
I have a tree on my home state and a detailview on my entities state.
Whenever I update my detail view I want to reload my tree.
what I have tried is to do
$state.reload()
when I was on state app.home.entity.standard-fact-code-detail
thinking that that would reload the entire tree also.
after that I tried:
$state.go('home', {}, { reload: true });
but I am getting cannot load abstract state
any help would be much appreciated
the state hierarchy is as follows:
app (abstract)
home (tree is in the template of this state)
entity (abstract)
entity1 (views: 'entities#home') (parameter: id)
entity2 (views: 'entities#home') (parameter: id)
entity3 (views: 'entities#home') (parameter: id)
my home state is as follows:
$stateProvider.state('home', {
parent: 'app',
url: '/',
views: {
'content#': {
templateUrl: 'app/home/home.html',
controller: 'HomeController',
controllerAs: 'vm'
}
}
});
home.html
<div ng-cloak>
<div class="row">
<div class="col-md-12">
<h1>TreeExplorer</h1>
<div id="treeDiv" class="col-md-4 blue-well well">
//my tree
<node class="noselect" data="treeItems.factCodes" toggle="treeItems.factCodesToggle" title="treeItems.nodeName" child="true"></node>
</div>
// my details page
<div class="col-md-8 well" ui-view="entities">
</div>
</div>
</div>
</div>
then the entity state:
$stateProvider.state('entity', {
abstract: true,
parent: 'home'
});
and state of a random entity (all are similar) :
.state('standard-fact-code-detail', {
parent: 'entity',
url: '/standard-fact-code/{id}',
views: {
'entities#home': {
templateUrl: 'app/entities/standard-fact-code/standard-fact-code-detail.html',
controller: 'StandardFactCodeDetailController',
controllerAs: 'vm'
}
}
})
you can use $window to reload your page
angular.module('myApp', [])
.controller('myCtrl', function($scope, $state, $window) {
$window.$location.reload();
$state.go('home');
})
I managed to solve it myself. Apparently there was a different state change in progress which silently gave an exception when trying to transition to reloading the home state.
By wrapping in $timeout I was able to make sure that the transition only happened when this state transition had finished.
$scope.$on('tree-update', function(event, data) {
$timeout(function(){
$state.reload();
});
});
Related
What i'm trying to do:
<div id="chat">
<div ui-view>Here should people.htm be loaded</div>
<div ui-view="chat">Here is current person chat peopleChat.htm</div>
</div>
I already managed a nested structure. If "chat" is child of "people" - no problem.
But I want em to remain on the same level, but be in a different state. Something like.
$stateProvider
.state('people', {
url: '/people',
templateUrl: ...,
controller: ...
})
.state('people.chat', {
views: {
'chat': {
url: '/:personId',
templateUrl: ...,
controller: ...
}
}
})
My unnamed view is filling with data. After unnamed view is filling, i'm calling $state.go('people.chat', { personId: vm.personId });
But nothing is happening.
Name both views and you are ok:
<div id="chat">
<div ui-view="main">Here should people.htm be loaded</div>
<div ui-view="chat">Here is current person chat peopleChat.htm</div>
</div>
And your controler:
$stateProvider
.state('people', {
views: {
'main#': {
url: '/people',
templateUrl: ...,
controller: ...
}
}
})
.state('people.chat', {
views: {
'chat#': {
url: '/:personId',
templateUrl: ...,
controller: ...
}
}
})
Basically the # absolute targets the view.
Meaning if you use it like chat# it targets the named view chat in the root html.
If you want to nest the views you can use chat#people
which targets the ui-view loaded in the template that people state has injected.
Plunker
I'm trying to set up a fairly complex page design with multiple ui-views. I've extracted it to a plunker (http://plnkr.co/edit/DwridY).
I have a main ui-view with several possible templates being loaded. Several of these templates have multiple ui-views of their own, for example:
<h1>Workflows</h1>
<div class="well">
<div ui-view="workflow.list"></div>
</div>
<div class="well">
<div ui-view="workflow.details"></div>
</div>
The angular config lists the states like this:
.state('tasks', {
url: "/tasks",
views: {
"mainView": {
templateUrl: "tasks.html",
controller: "TaskController"
}
}
})
.state("task.list", {
url: "/taskList",
views: {
"task.list": {templateUrl: "task.list.html"},
}
})
.state("workflow", {
url: "/workflows",
views: {
"mainView": {
templateUrl: "workflow.html",
controller: "WorkflowController"
}
}
})
.state("workflow.list", {
url: "/workflowsList",
views: {
"workflow.list": {templateUrl: "workflow.list.html"},
"workflow.details": {templateUrl: "workflow.details.html"}
}
});
The problem is that it works with the workflow state and it's sub-views but not the task state.
When I call:
function TaskController($scope, $state) {
$state.transitionTo("task.list");
}
I get thrown an error:
No such state 'task.list'.
Can anyone see where I'm going wrong?
In general - if there is a . (dot) in the state name - UI-Router expects that it means:
before last dot - parent name (parents if more dots)
after last dot - current state name
so, what we are experiencing above with "task.list" is either
missing state "task" or
declaration "tasks.list" (the parent will be existing "tasks" instead of "task")
Here is the updated and working plunker, where I decided to use tasks as parent:
.state('tasks', {
url: "/tasks",
views: {
"mainView": {
templateUrl: "tasks.html",
controller: "TaskController"
}
}
})
//.state("task.list", {
.state("tasks.list", { // here we inherit from "tasks" not "task"
url: "/taskList",
views: {
"task.list": {templateUrl: "task.list.html"},
}
})
I use ui-router and have two nested views.
I’d like to hide some html-content in the parent view when the user goes to child state and show it again when the user backs to parent one.
Could anybody give an advice how to achieve that?
It’s easy to do that using root scope and state change events but it looks like a dirty way, doesn’t it?
app.js
'use strict';
var myApp = angular.module('myApp', ['ui.router']);
myApp.controller('ParentCtrl', function ($scope) {
$scope.hideIt = false;
});
myApp.controller('ChildCtrl', function ( $scope) {
$scope.$parent.hideIt = true;
});
myApp.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('parent', {
url: '/parent',
templateUrl: 'parent.html',
controller: 'ParentCtrl'
})
.state('parent.child', {
url: '/child',
template: '<h2>Child view</h2>',
controller: 'ChildCtrl'
});
});
parent.html
<h2>Parent view</h2>
<div ng-hide="hideIt">
<p>This text should be hidden when the user goes to the nested state.</p>
</div>
<a ui-sref="parent.child">Go to the nested view</a>
<div ui-view></div>
One simple solution is to fill ui-view tag in the parent template with the content that you want gone when child state is loaded.
<ui-view>
<h2>Parent view</h2>
<div ng-hide="hideIt">
<p>This text should be hidden when the user goes to the nested state.</p>
<a ui-sref="parent.child">Go to the nested view</a>
</ui-view>
You should check out named views for this. That would probably be the best way to go. https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
Also, there's another thread that answered this question over here: https://stackoverflow.com/a/19050828/1078450
Here's the working code for nested named views, taken from that thread:
angular.module('myApp', ['ui.state'])
.config(['$stateProvider', '$routeProvider',
function($stateProvider, $routeProvider) {
$stateProvider
.state('test', {
abstract: true,
url: '/test',
views: {
'main': {
template: '<h1>Hello!!!</h1>' +
'<div ui-view="view1"></div>' +
'<div ui-view="view2"></div>'
}
}
})
.state('test.subs', {
url: '',
views: {
'view1#test': {
template: "Im View1"
},
'view2#test': {
template: "Im View2"
}
}
});
}
])
.run(['$state', function($state) {
$state.transitionTo('test.subs');
}]);
http://jsfiddle.net/thardy/eD3MU/
Edit:
Adding some thoughts re the angular-breadcrumbs comment. I haven't used it myself, but at first glance it seems like subroutes shouldn't break the breadcrumbs. I'm just looking at the source code of their demo, around line 62. I'd have to spin it all up to really go about testing it, but it looks like they're doing almost the same thing with specifying views, and it works there: https://github.com/ncuillery/angular-breadcrumb/blob/master/sample/app.js#L62
.state('room', {
url: '/room',
templateUrl: 'views/room_list.html',
controller: 'RoomListCtrl',
ncyBreadcrumb: {
label: 'Rooms',
parent: 'sample'
}
})
.state('room.new', {
url: '/new',
views: {
"#" : {
templateUrl: 'views/room_form.html',
controller: 'RoomDetailCtrl'
}
},
ncyBreadcrumb: {
label: 'New room'
}
})
.state('room.detail', {
url: '/{roomId}?from',
views: {
"#" : {
templateUrl: 'views/room_detail.html',
controller: 'RoomDetailCtrl'
}
},
ncyBreadcrumb: {
label: 'Room {{room.roomNumber}}',
parent: function ($scope) {
return $scope.from || 'room';
}
}
})
Edit2:
This solution will not combine routes into one crumb
See the official demo
re: But I use angular-breadcrumb and in your solution they will be combined into one crum.
I'm using UI-router's $stateProvider for the routing on an angularjs project and find myself repeating a lot of the same configuration for the route views.
For example:
$stateProvider.state('triage', {
url: '/operations/triage',
views: {
"header": {
controller: 'CommonCtrl',
templateUrl: 'common/header.tpl.html'
},
"submenu": {
controller: 'CommonCtrl',
templateUrl: 'common/submenu.tpl.html'
},
"content": {
controller: 'TriageCtrl',
templateUrl: 'operations/triage/triage.tpl.html'
},
"footer": {
templateUrl: 'common/footer.tpl.html'
}
},
The header, submenu and footer will be the same for almost every state, the content is really the only part that is variable.
Is there a way to configure the router to always use predefined controllers and templates unless otherwise specified.
Solution here could be called: layout root state. As in detail described here:
Angular UI Router - Nested States with multiple layouts
Nested states or views for layout with leftbar in ui-router?
One of the plunkers
we can create a super parent state 'index' or 'root' (there could be few of them for different state families, e.g. standard, login, doc) which is creating unnamed target for its child/ren (ui-view="") while injecting related templates around:
.state('index', {
abstract: true,
//url: '/',
views: {
'#' : {
templateUrl: 'layout.html',
controller: 'IndexCtrl'
},
'top#index' : { templateUrl: 'tpl.top.html',},
'left#index' : { templateUrl: 'tpl.left.html',},
// this one is unnamed - a target for children
'#index' : { templateUrl: 'tpl.main.html',},
},
})
So, in this example the layout.html would look like:
<div>
<section class="left">
<div ui-view="left"></div>
</section>
<section class="right">
<section class="top">
<div ui-view="top"></div>
</section>
<section class="main">
// here is the unnamed view - filled by this state
// but later target for the child states
<div ui-view=""></div>
</section>
</section>
</div>
Now, we can inject that root state into any existing state:
.state('client', {
parent: 'index',
...
})
.state('product', {
parent: 'index',
...
})
so they will have unchanged name ('client', 'product'), i.e. without prefix 'index' or 'root' but will be injected into existing template
The example
In my app I have some main modules and each modules has sidebar.
If I click sidebar item then it will route to sidebar linking page but here if I click header again then I am not able to view my parent route page.
I have listed my problem in this plnkr.
Step to reproduce :
By default route1 is selected and dashboard is available on view. Click on Item1.
Now click on route1 : Failed to see dashboard view.
<script>
var myapp = angular.module('myapp', ["ui.router"])
myapp.config(function($stateProvider, $urlRouterProvider) {
// For any unmatched url, send to /route1
$urlRouterProvider.otherwise("/route1")
$stateProvider
.state('route1', {
url: "/route1",
templateUrl: "route1.html",
controller: function($scope, $state) {
$scope.items = ["item1", "item2"];
$state.go('route1.dashboard');
}
})
.state('route1.dashboard', {
url: "/dashboard",
templateUrl: "dashboard.html"
})
.state('route1.item1', {
url: "/item1",
templateUrl: "item1.html"
})
.state('route1.item2', {
url: "/item2",
templateUrl: "item2.html"
})
.state('route2', {
url: "/route2",
templateUrl: "route1.html",
controller: function($scope, $state) {
$scope.items = ["item3", "item4"];
$state.go('route2.dashboard');
}
})
.state('route2.dashboard', {
url: "/dashboard",
templateUrl: "dashboard.html"
})
.state('route2.item3', {
url: "/item3",
templateUrl: "item3.html"
})
.state('route2.item4', {
url: "/item4",
templateUrl: "item4.html"
})
})
</script>
The code you have in the route1 controller only runs when it's instantiated. Therefore, after you re-visit it from being inside item1, it doesn't need to reload and the $state.go() doesn't fire.
I've forked your plunker with another potential approach: http://plnkr.co/edit/7stMErnkb3rzPJD0Gj5x?p=preview
you should put the dashboard content in the route1 template, rather than attempting to forward to it via $state.go()
so, your route1.html goes from the previous ui-view statement of
<div ui-view></div>
to
<div ui-view>
<h1>Dashboard</h1>
</div>
Now you don't need the dashboard partial, and it loads every time. The item1/item2 partials will replace the content in the ui-view whenever those states activate.
Note in the updated Plunker how Route1 works as you want, while Route2 still doesn't work (as it still has the previous $state.go() approach).