Here is the code which i have written so as to change my view (without any change in the url)
<a ui-sref="chat.menu" ng-click="click1();">Latest</a>
<a ui-sref="chat.menu" ng-click="click2();">Mail</a>
<div ui-view="{{item}}"></div>
var app = angular.module('myApp',['ui.router'])
.run(['$rootScope','$state','$stateParams', function($rootScope,$state,$stateParams){
$rootScope.$state = $state;
$state.$stateParams = $stateParams;
}]);
app.config(function($stateProvider,$urlRouterProvider){
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home',{
url:'/',
templateUrl:'templates/main.html',
})
.state('chat',{
url:'/chat',
templateUrl:'templates/chatPage.html',
controller: 'chatController',
})
.state('chat.menu',{
views: {
'':{
template: '<h1>Blank</h1>',
},
'latest': {
template: '<h1>Latest</h1>',
},
'mail': {
template: '<h1>Mail</h1>',
}
}
});
});
app.controller('Controller', function($scope,$state, authentication){
$scope.item='';
$scope.click1 = function(){
$scope.item = "latest";
}
$scope.click2 = function(){
$scope.item = "mail";
}
});
Its working fine, but the problem is that I change the the view only once. Once a view is loaded in the ui-view, then another view is not getting loaded in it on the click of the button.
All i want is that, when the user click the button the view should be changed according to the click of the button without any change in the url.
So I'd trying something like this: having two states instead of one. If you want to keep only one state, you'd need to pass parameters to that state, but for a simple example like this, two states will work just fine:
myApp.config(function ($stateProvider){
$stateProvider
.state("latest", {
url: "#",
template: "<h1>Latest</h1>",
controller: "Ctrl1"
})
.state("mail", {
url: "#",
template: "<h1>Mail</h1>",
controller: "Ctrl2"
});
});
What we are doing here is either setting the URL to the same in both states, or setting no URL at all. Also, if you want to assign controllers to your views, here is were we do it. You can assign no controllers, two different controllers, or the same controller if you would like.
Then setup your view like this:
<nav>
<a ui-sref="latest">Latest</a>
<a ui-sref="mail">Mail</a>
</nav>
<div ui-view></div>
Here is a working JSFiddle
Related
I am trying to make a nested views, here is the plunker https://embed.plnkr.co/oRMnMW4QoWwhSkm9maHf/. The state changes but the template not changes.
Can anyone correct me what have I done wrong
Goto Link > Second Nested .
On Clicking the button , state changes successfully but the content is not injected. I want the link page content to be replaced by the second-nested content
Try to put abstract:true on the 'father' root like:
var routerApp = angular.module('routerApp', ['ui.router','ncy-angular-breadcrumb']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home/list');
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('home', {
url: '/home',
abstract: true,
templateUrl: './partial-home.html'
})
// nested list with custom controller
.state('home.list', {
url: '/list',
templateUrl: './partial-home-list.html',
controller: function($scope) {
$scope.dogs = ['Bernese', 'Husky', 'Goldendoodle'];
}
})
.state('home.second', {
url: '/second',
templateUrl: './second.html',
});
});
routerApp.run(['$rootScope', '$state', function ($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function (event, toState) {
console.log("state Change")
});
}]);
but Remember .. if you put abstract: true .. the url is not a real one .. it's a prefix .. or as i call it .. a father of other routing ..so you can not call it in the .otherwise()
And in your link (and routing) of the second view .. just remove the .list ... so like this:
.state('home.second', { //<-- HERE .. REMOVE THE .list
url: '/second',
templateUrl: './second.html',
});
and in the link:
// AND HERE ..
<a ui-sref="home.second" class="btn btn-danger">Second Nested</a>
Answer is pretty simple - you are initializing 3rd level of nesting states but in ./partial-home-list.html you've didn't add ui-view directive.
Add <ui-view></ui-view> in ./partial-home-list.html and you will see that it works as you defined.
If you want to display home.list.second as separate page then define second state like this
.state('home.second', {
url: '/home/list/second',
templateUrl: 'second.html',
});
Remember to update ui-sref to home.second on button
--
Just to get nested breadcrumb I have not "nice" solution but will work.
-- Partial home list html
<div ng-if="state.current.name != 'home.list.second'">
<ul>
<li ng-repeat="dog in dogs">{{ dog }}</li>
</ul>
<div ncy-breadcrumb></div>
<a ui-sref="home.list.second" class="btn btn-danger">Second Nested</a>
</div>
<ui-view></ui-view>
App js
// nested list with custom controller
.state('home.list', {
url: '/list',
templateUrl: 'partial-home-list.html',
controller: function($scope, $state) {
$scope.state = $state;
$scope.dogs = ['Bernese', 'Husky', 'Goldendoodle'];
}
})
.state('home.list.second', {
url: '/second',
templateUrl: 'second.html',
});
I am using ui-router and I try to create several views inside one of my nested states.
In my logic, all of the views should be visible whenever the parent state is active.
I have read the wiki page on multiple named views multiple times, but could not get anything working yet.
My state template would show up, but my views never do.
Here is a working plunker
(You have to click on "Followers" in the navbar for the view to show up. Haven't figured why yet).
Important parts are the config
app.config([
'$stateProvider',
'$urlRouterProvider',
function ($stateProvider, $urlRouterProvider){
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard.html',
controller: 'DashboardCtrl',
authenticate: true
}).state('dashboard.followers', {
url: '/followers',
templateUrl: 'dashboard.followers.html',
controller: 'DFollowersCtrl',
authenticate: true
}).state('dashboard.followers.add', {
views: {
'add': {
templateUrl: 'dashboard.followers.add.html',
controller: 'DFollowersAddCtrl',
authenticate: true
}
},
});
$urlRouterProvider.otherwise('dashboard');
}
]);
The main dashboard template (level 2, using a generic ui-view)
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<div class="flash-area">
<flash-message duration="2000" show-close="true"></flash-message>
</div>
<ui-view></ui-view>
</div>
and the dashobard.followers specific level 3 view, that has a specific name
<div>
<h1 class="page-header">Followers</h1>
<div ui-view="add"></div>
</div>
The trick is coming from, I think, a combination of :
I want to use level 3 nesting
Level 2 uses a generic ui-view, because it may contains my dashboard or something else.
Level 3 contains specific views, as it is where I want to use "views" and not "states" (as far as I understood, at least).
The final aim is to have more than one view in my template, but for now I reduced the attempts to only show the 'add' view.
I have seen several similar questions on SO already, such as this one or this other one but so far my attempts have not been fruitful.
I can access my "add" view directly if I reach its URL (when I try setting one)
But the dashboard.followers state does not get populated by the views.
I think there are several mistakes here you made:
if you want the url of dashboard.followers state and dashboard.followers.add state to be same, the child state dashboard.followers.add does not need the url option
probably can be a mistake(I am not sure because no code is provided), if you don't use the
views: { ... }
named views, but just directly use
url: '/followers',
templateUrl: '/partials/dashboard.followers.html'
angular just assume you want to insert the template in an unnamed <div ui-view></div> in the parents state's template not the root template. for example, in my example code, for state dashboard.followers, since it is a child state of dashboard, if I want to insert the template in root html template, I have to use
views: {
'#': {
template: '<div><h1 class="page-header">Followers</h1><a ui-sref="dashboard.followers.add">add</a><div ui-view="add"></div></div>'
}
}
/* myApp module */
var myApp = angular.module('myApp', ['ui.router'])
.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('landing', {
url: '/',
template: '<p>landing</p><a ui-sref="dashboard">dashboard</a>'
})
.state('dashboard', {
url: '/dashboard',
template: '<p>landing</p><a ui-sref="dashboard.followers">followers</a>'
})
.state('dashboard.followers', {
url: '/followers',
views: {
'#': {
template: '<div><h1 class="page-header">Followers</h1><a ui-sref="dashboard.followers.add">add</a><div ui-view="add"></div></div>'
}
}
})
.state('dashboard.followers.add', {
views: {
'add': {
template: '<p>followers</p>'
}
}
});
}])
.controller('MyAppCtrl', function($scope, $state /*, $stateParams*/ ) {
$state.go("landing");
});
<body ng-app="myApp" ng-controller="MyAppCtrl">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.js"></script>
<div ui-view></div>
</body>
update
I made two plunkers to fit two different situation:
if you want to dynamically load add state to ui-view="add" by a
link, check
this out.
if you just want a sub template to be loaded always on dashboard.followers state, simply remove add states, and use views: {...} to load the add template in. here is the plunker.
I have a list of articles in this tableofcontent.html file, and they are all clickable links. This page works correctly, and is showing a list of all of the titles. When I click on the links though, it goes to the right template file, but none of the right data is populated in the article.html file. How do I get the data for each link to show up correctly in the articles.html page?
tableofcontent.html
<div class="row" ng-controller="TableofContentController">
// non relevant code removed
<ul>
<li ng-repeat="article in data">
<a ui-sref="article">{{article.title}}</a>
</li>
</ul>
article.html
<div class="row" ng-controller="ArticlesController">
// non relevant code removed
<h3>{{article.title}}</h3>
<h6>Author: {{article.author}} on {{article.date}}</h6>
<p>{{article.body}}</p>
//etc
app.js
// service to retrieve and share data
articleApp.factory('Data', function ($timeout, $http) {
var articles = {
fetch: function() {
return $timeout(function() {
return $http.get('articles.json')
.then(function(response) {
return response.data;
});
}, 30);
}
}
return articles;
});
articleApp.controller('TableofContentController', function ($scope, Data) {
Data.fetch().then(function(data) {
$scope.data = data;
});
});
articleApp.controller('ArticlesController', function ($scope, Data) {
Data.fetch().then(function(data) {
$scope.data = data;
});
});
also in app.js
// table of content state
.state('tableofcontent', {
url: '/index',
templateUrl: 'templates/tableofcontent.html'
})
// main articles page state
.state('article', {
url: '/{{article.title}}',
templateUrl: 'templates/articles.html',
controller: 'ArticlesController',
controllerAs: 'articles',
})
There are actually a bunch of issues here, what you want to do is, when someone clicks on the list of these links, instead of doing
<a ui-sref="article">{{article.title}}</a>
You probably want to do
<a ui-sref="article({id : article.id})">{{article.title}}</a>
Now that you are passing the id of the article, the modules state definition needs to be modified to accept this article id as follows.
.state('article', {
url: 'article/:id',
templateUrl: 'templates/articles.html',
controller: 'ArticlesController',
controllerAs: 'articles',
})
So now when you click on the articles, you should see a network request that looks like this : article/1234 where 1234 is the id of the selected article.
In this example you always seem to be loading the same article.json data, but when interacting with the server you can access the selected article id by using the $stateParams service which you can just inject into your controller.
Using Angular UI router, I have a route set up as follows
$stateProvider.state('edit', {
url: '/:file/:page',
...
}
if I change the route from /edit/file1/page1 to /edit/file1/page2, the view doesn't refresh. I'm calling $state.go, and I can easily redraw the page, but by not running this through the router things like the back button don't update the route.
Can someone advise how to update the route so the view is updated?
Thanks.
If I understand your intention here, it is to have your templateUrl be based on the :file and :page $stateParams.
Since you haven't shown how you are actually using $state.go, I put together an example that shows a few of the ways you can change between states with and without { reload: true }.
angular.module('exampleApp', ['ui.router'])
.config(function($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/file1/page1');
$stateProvider
.state('edit', {
url: '/:file/:page',
controller: 'FilePageCtrl',
templateUrl: function($stateParams) {
return $stateParams.file + "-" + $stateParams.page + ".html";
}
});
})
.controller('FilePageCtrl', function($scope, $state) {});
Here are some example links that change the state (but will not re-run the controller and template if it's already the current state):
<a ui-sref="edit({ file: 'file1', page: 'page2' })">/file1/page2</a>
Is more or less the same as (whether inline with ng-click or within a controller):
<a href ng-click="$state.go('edit', { file: 'file1', page: 'page2' })">/file1/page2</a>
The following two will force the controller and templateUrl to run, regardless if the current state is the same:
<a ui-sref="edit({ file: 'file1', page: 'page2' })" ui-sref-opts="{ reload: true }">/file1/page2</a>
<a href ng-click="$state.go('edit', { file: 'file1', page: 'page2' }, { reload: true })">/file1/page2</a>
You can read more about using a dynamic templateUrl here: https://github.com/angular-ui/ui-router/wiki#templates
Here is a working example: http://plnkr.co/edit/JUgUB3I675Kh7kKkitgJ?p=preview
Though the states are changing successfully, I can't get the ui-view to update:
HTML
<a ui-sref="promo.foo">Foo state</a>
<a ui-sref="promo.bar">Bar state</a>
<div ui-view=""></div>
JavaScript
$urlRouterProvider.otherwise("/");
$stateProvider
.state('promo', {
url: "/",
abstract: true
})
.state('promo.foo', {
url: "promo/foo",
template: "'<h3>Foo</h3>'",
controller: function($scope) {
$scope.value = 'foo';
}
})
.state('promo.bar', {
url: "promo/bar",
template: "'<h3>Bar</h3>'",
controller: function($scope) {
$scope.value = 'bar';
}
})
Plnkr (with bootstrap styling)
I have also tried setting ui-view to equal specific states also; and to dynamically change its RHS from my $scope.
Since you're trying to create nested views, the home state should have a template with an ui-view-element in it.
Also you have both double and single quotes in the template
template: "'<h3>Foo</h3>'"
Is this Plunker what you had in mind?
Give your abstract state a template containing inside which your sub states will render ... eg http://scotch.io/tutorials/javascript/angular-routing-using-ui-router