Different view depending on which state - angularjs

I have an Angular page which has a login page, a register account page, and the rest of the page. Login/register looks different from the other pages, as they have no sidebar, toolbar, and so on. Totally different layout. I have an index page and an index controller, which determines which view to load currently. Something like this:
<body ng-app="myApp" ng-controller="IndexController as vm">
<div ui-view ng-if="$state.current.name === 'home'"></div>
<div ng-if="$state.current.name !== 'home'">
<!--TOOLBAR-->
<!--SIDEBAR-->
<div ui-view></div>
</div>
</body>
So basically if the current state is home, it should load the first view (with no toolbar, sidenav etc.). If the current state is not set to home, it should show the toolbar, sidebar, and so on. I thought this would work, but is there a better way to do it? I have all my states inside my app.js.
Let me know if there's a better way of separating the different views. Why I'm doing this, is because I want to keep all the includes (models, views, controllers) and other scripts on one page (my index.html which contains the above) and just change the view accordingly. Thanks.

Using the controller as syntax, i'm assuming $state isn't defined. You should add it to the controller scope (not $scope) (this.$state = $state) and call it using vm.$state.current....
Ideally you wouldn't do this though and use ui-routers nested states which solves this problem exactly.
https://github.com/angular-ui/ui-router/wiki/nested-states-%26-nested-views
There are a number of ways to do this. One is to fork the states so home does not inherit parent views.
$stateProvider.state('home', {})
.state('app', {}) // has parent views like menu
.state('app.foo', {}) // inherits views from app
Or used named views
<body>
<div ui-view="menu"></div>
<div ui-view="content"></div>
</body>
$stateProvider.state('app' { views: { menu: { ... } } } )
.state('app.home', { views: { 'menu#app': { /* inject empty tpl */ }, 'content#app' : { ... } } )
.state('app.foo', { views: { 'content#app' : { ... } } } );

Related

how to add different head two tags or different head information for my two directive

I have main.cshtml file
It has a head tag which includes css and js references.
I have two directives / templates.
I want to have different two title. When page1 opened (has template1) I want page's title to be Page-1.
When page2 opened (has template2) I want page's title to be Page-2.
I tried to put head tags to directive but it doesn't read title and icon-for-title.
<div style="height: 100%">
<head>
<title>{{::title}}</title>}}
<link rel="shortcut icon" href="../../../../icons/icon1.ico">
</head>
<div class="..." >
<div class="...">
<div>...............
It doesn't work neither like that or head tag is over the main div.
I tried to do with routing, in route giving title property but in config file rootScope can not be read.
So I tried to run() with module. But it didn't work too.
module.run(function($rootScope){
$rootScope.$on("$routeChangeSuccess", function(currentRoute,
previousRoute){
//Change page title, based on Route information
$rootScope.title = $route.current.title; }) ;});
Can you please help how can I have these two different title and icons. Or if it has to be two different head tag to see them, how can I create these?
I don't have a lot of information to go on for your specific use case,
but we set the title programmatically like this:
$document.prop('title', title);
You could trigger this code on $stateChangeSuccess.
In this example, you define the title in the state definition and update it when the state changes:
var module = angular.module('someModule', ['ui.router']);
module.run(function($rootScope, $stateProvider, $document) {
// use ui-router additional route data to configure the title of the state
$stateProvider.state('someState', {
url: 'someUrl',
controller: 'SomeCtrl',
templateUrl: 'some.tpl.html',
data: {
title: 'Your states title goes here'
}
});
$rootScope.$on("$stateChangeSuccess", function(event, currentState) {
//Change page title, based on title found in route definition
$document.prop('title', currentState.data.title);
});
});
This examples assumes you're using ui-router for routing.

AngularJS UI Router Update Sibling View

I am working with angular and using ui router. The structure of my views are something like this:
<div ui-view>
<div ui-view="left">
-- list of items
</div>
<div ui-view="right">
-- details of item
</div>
</div>
Now if i select an item from left panel, an api is called to get the details of that item. Now want to load that information in right view.
All the view states have their own controller. Can someone please help me to pass the returned data from api tosecond view?
This is a pretty straightforward and common use case with ui-router. The main concept is of nested states and multiple named-views.
I would set this up with some states that look something like:
$stateProvider
.state('user', {
url: '/user',
views: {
'left': {
templateUrl: '/templates/states/user-list.tpl.html'
},
'right': {
template: '<p>This is default content that would appear in the right view until a user is selected. This is nice, but is completely optional.</p>'
}
}
})
.state('user.details', {
url: '/:userId',
views: {
'right': {
templateUrl: '/templates/states/user-details.tpl.html'
}
}
});
In the user-list template, you would use links something like:
<a ui-sref="user.details({userId: user.id})">{{user.name}}</a>
Because user.details is a child state of user, the user-list stays loaded into the left view while navigating through different users in the right view.

How to target specific ui-view elements when nested ui-views exist

Imagine some html as follows:
<body ng-app="blocksApp">
Some content goes here
<div ui-view="monty">
<div ui-view="dave">Aaa</div>
<div ui-view="pete">Bbb</div>
<div ui-view="steve">Ccc</div>
</div>
</body>
Using ui-router, is there any way to code a state that will set "dave" to a new snippet of html, whilst leaving everything else untouched.
e.g. I'd like to do this:
$stateProvider
.state('daveonly',{
url: "/dave",
views:{
'dave':{template:"Dave now has content"}
}
})
I can't get it to work. The reason I want to do this is that sometimes I'd like to replace 'Dave' with a partial update, other times I'd like to replace the entire 'monty' with a partial update. It seems that ui-router does not like having nested ui-views in the same snippet of html.
From one point of view I'd like to suggest:
move html code to '.tpl.html' files
use 'templateUrl' instead of 'template'
And check if the following is suitable for you:
$stateProvider.state("daveonly", {
views: {
"dave": {
templateUrl: 'daveonly.tpl.html',
},
"pete": {
templateUrl: 'pete.tpl.html',
},
"steve": {
templateUrl: 'steve.tpl.html',
},
}
});
Take a look at page1 and page2 for more details.
But from another point of view it could be more useful to use only one ui-view and to redesign current ui-views to become the appropriate directives with controllers/services: usage of directives with controllers/services could help to manage partial reload correctly and to write unit-tests.
Yes it can be done easily with the help of abstract states and yes you are correct ui-router doesn't like direct nested views directly but it works fine if the views are in any child template.
Now consider this main page(index.html)
<body ng-app="app">
<div ng-view=""></div>
</body>
Now this template which will appear in this unnamed view. (parent.html)
<h3>This is the parent template</h3>
<div ng-view="child1"></div>
<div ng-view="child2"></div>
Now the JS file
$stateProvide.state('home',{
url:'/',
abstract:true,
views:{
"":{
templateUrl:'parent.html'
}
}
})
.state('home.child',{
url:"",
views:{
'child1#home':{
templateUrl:'child1.html'
},
'child2#home':{
template:'Child2'
}
}
})
.state('home.child.child1',{
url:"child1#home.child",
views:{
'child1#home':{
templateUrl:'child1viewchange.html'
}
}
});
(Now the manipulation part)
(child1.html)
<button ui-sref="home.child.child1">Child</button>
Now child1viewchange.html pe jana padega and wo dekhne wali hai kaunsi kaisi thi/......
(child1viewchange.html)
<h3>Child1's view change</h3>
So now when we click on the button in child view1 the content in the first view changes and if we assign controllers then they can use them to control data.

Add/Remove CSS Class on Route Change in Angularjs

I am not sure how this can be achieved in Angular. I want to add and remove CSS class on route change. I am trying to Show and Hide vertical menu. Currently I am using ui-route. Any Suggestion or link to example would be appreciated or any other suggestion on different approach to my problem is also welcome
Easiest and most efficient way:
angular.module(...).run(function($rootScope, $state) {
$rootScope.$state = $state;
});
<div ng-if="$state.contains('someState')">...</div>
This will remove the DOM which will improve performance if the menu has lots of bindings.
However, I constantly tell people to consider leveraging named views for navigation:
<body>
<nav ui-view="nav"></nav>
<div class="container" ui-view></div>
</body>
$stateProvider.state('home', {
views: {
'nav#': {
templateUrl: 'nav.html'
}
'': {
// normal templateUrl and controller goes here.
}
}
});
The cool part about this is that children states can override and control what nav file to use, and can even setup resolves and controllers that share data between the nav and the content. No directives/services needed!
Finally, you can do these too:
<nav ng-show="$state.contains('somestate')"></nav>
<nav ng-class="{someClass:$state.contains('somestate')}"></nav>
Alternatively checkout ui-sref-active
All of my suggestions primarily assume you're using UI-Router since it's the best!
Try this:
app.run(function ($rootScope) {
$rootScope.$on("$stateChangeStart", function(event, toState, fromState){
if (toState.url === "/path") {
$('div').addClass('className');
} else {
$('div').removeClass('className');
}
});
});
You can register the route changed and add this css to your DOM:
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
// Add your logic, for instance:
$('body').addClass('hide-menu');
});
Obviously there are events raised before the route has been changed: "$locationChangeStart", here.
/Edit/ - Better approach
Also I would rather using the ng-class attribute and simple bind a certain value from your main controller to it.
app.controller('MainController', function ($scope) {
$scope.toggleMenu = function(isToShow) {
$scope.isVisibleMenu = isToShow == true;
};
});
then in your html:
<!-- Menu toggle button-->
<button ng-click="toggleMenu()"></button>
<div class="toggleable-menu" ng-class="{'visible-menu': isVisibleMenu}">
<!-- The menu content-->
</div>
and the simplest CSS possbile (you can obviously add animations or any other thing to toggle this menu.)
.toggelable-menu {
display: none;
}
.toggelable-menu.visible-menu {
display: block;
}

Angular ui-router parallel view with child states

I've been looking around and perhaps I'm missing something, but I've been totally unable to figure out how to get this working. Basically, I want a state with three parallel views. Lets call them header, body, and footer. Header and footer work just fine as simple parallel views, but I haven't been able to figure out how to automatically render the body child state, so that I can use it to manage other views.
app.js
.state('main', {
url: '/',
views: {
mainModule: { templateUrl: 'partials/main.html'},
"header#main": {
templateUrl: "partials/header.html",
},
"footer#orders": {
templateUrl: "partials/footer.html",
},
}
})
.state('main.body',{
url:'/',
template:"<p>Test!</p>"
})
main.html
<div ui-view="header"></div>
<div ui-view></div>
<div ui-view="footer"></div>
I have a feeling that the ui-view section of the html is not the way to go, and that the answer might have to do with abstract states, but thus far I haven't managed to get it working. Any help would be appreciated.
I have also attempted to reference a view as if it were a state, but that also rendered nothing.
This answer seems to come close, but I haven't been able to get what is suggested in the comments working.
I've looked at other questions that are layout related, but none of the solutions I've come across have worked for me. Thanks!
There is a working plunker, showing all the small adjustments described below in action.
Firstly, we must be sure, that our index.html, the root view, has the place for our 'mainModule' view template. So this is a snippet of the index.html:
<body>
<div ui-view="mainModule" ></div>
...
That, means, that our core view (one of views defined in 'main' state) will be properly injected into root view.
Now, our header and footer should both be using absolute names, but their suffix must be 'main' (not 'orders' like above for footer). That is saying to UI-Router: place them inside of views defined in this state (main.html)
Also, we can (as part of this 'main' state) define some default content of the "body". It could be let's say some list view...
.state('main', {
url: '/',
views: {
// it could be "mainModule" as well... so it needs its: ui-view="mainModule"
mainModule: { templateUrl: 'tpl.main.html'},
"header#main": {
...
},
// wrong absolute name
// "footer#orders": {
// we need the 'main' as well
"footer#main": {
...
},
// even the body, unnamed view could have some default
"#main": {
templateUrl: "tpl.list.html", // e.g. list
},
}
Next, we can defined few more states as children of the 'main'. They will (by default) use the unnamed view of the main. And what's more - replace the list view used above:
.state('main.body',{
url:'/body',
...
})
.state('main.detail',{
url:'/detail:/id',
...
})
Observe it here, it should give all the answers...
The name of the views used in the ui-view directive should match the view names defined in your route configuration section:
<div ui-view="mainModule"></div>
<div ui-view="header#main"></div>
<div ui-view="footer#orders"></div>
I'm not entirely sure if the "#" symbol will give you trouble - if it does, try removing it from the view names.

Resources