Angular Ui-Router with Jade Nested Views Broken - angularjs

Angular UI-Router works as expected as long as I do not use nested states. For example, this works:
$urlRouterProvider.otherwise("/marketing");
$stateProvider
.state('marketing', {
url: '/marketing',
templateUrl: 'partials/marketing',
})
.state('landing', {
url: '/landing',
templateUrl: 'partials/marketing-landing',
})
.state('features', {
url: '/features',
templateUrl: 'partials/marketing-features',
})
And this doesn't:
$urlRouterProvider.otherwise("/marketing");
$stateProvider
.state('marketing', {
url: '/marketing',
templateUrl: 'partials/marketing',
})
.state('marketing.landing', {
url: '/landing',
templateUrl: 'partials/marketing-landing',
})
.state('marketing.features', {
url: '/features',
templateUrl: 'partials/marketing-features',
})
In any case where a child URL (ie. /marketing/landing) is loaded either via a sref link or direct URL entry, only the parent partial (partials/marketing) is displayed, despite the address bar changing to the child's URL.
Index.jade:
div(ui-view)
marketing.jade:
h1 marketing layout
div(ui-view)
marketing-landing.jade:
h1 This is the landing page
marketing-features.jade:
h1 This is the features page
This is my first time using AngularUI. Let me know any other relevant information I can provide.

Turned out to be a bug in Jade / bad assumption made by UI-Router (not sure which). From: https://github.com/angular-ui/ui-router/issues/247
Use HTML in your jade file. Jade won't expand it.

First .ui-view - work correct!
But nested ui-view must be markup by plain HTML like this:
.row
.col-md-12
h4 Nested UI-VIEW
<div ui-view></div>

Assigning an empty string to the ui-view attribute seems to work for me. This keeps plain HTML out of the jade template and provides the ability to nest default jade content within the ui-view.
.row
.col-md-12
h4 Nested UI-VIEW
div(ui-view='')
p Using this approach we can have default content before ui-view is loaded

Related

Components aren't being injected into my ui-view

I'm just trying to setup a boilerplate for angular 1.5.9 with UI Router 1.0.0. I can display my parent state component within the ui-view, however when I nest states within my parent, my components aren't being injected into my ui-view.
This is my index.html
<body ng-app="app">
<ui-view></ui-view>
</body>
This is the main component
<div class="main-container">
<banner></banner>
<div ui-view='ui-view></div>
</div>
It is at this point where in I'm unable to inject anything into the ui-view.
This is my javascript file
$stateProvider
.state('app', {
url: '/',
component: 'main'
})
.state('app.login', {
url: '/login',
views: {
'ui-view': {
templateUrl: './app/login/login.html'
}
}
});
I'm not sure what I'm doing wrong, any help/direction to the right path would be appreciated.
EDIT
Additional Info that might be helpful
When I reference login as a parent state everything works as expected.
The login component is part of a separate module that I've included in my main module.
For nesting one child state in each parent component, there is no need to use named views as you did by adding a value of "ui-view" for the ui-view directive used in your main component template. Those named views are only required when you want to address more than one ui-view. Then you need to reference them by name.
In your sample, you will not see any content because you also don't target the named view correctly. There are some rules on how to address those named views if the named views are defined in a template which is not the root file. In that case you need to be more specific by referencing the ui-view with a "ui-view-name#state" syntax which would mean "ui-view#app" in your case.
But as already mentioned: In your simple case, just leave out the name for the ui-view and replace the views section in your state config with a plain template (or a component reference).
.state('app.login', {
url: '/login',
templateUrl: './app/login/login.html'
});
For details on nesting views, please have a look at the great sample apps in the ui-router docs.
So this one is really strange, I've no explanation as to why it worked the way it did. All I did was change the javascript file to the one below
$stateProvider
.state('login', {
url: '/login',
component: 'main'
})
.state('login.default', {
url: '/default',
component: 'login'
});
Instead of my parent having '/', changed it to '/login'. I'd be keen to know if someone knows the reason behind this behaviour.
$stateProvider
.state('app', {
url: '/',
templateUrl: path/to/main_component.html
})
.state('app.login', {
url: '/login',
views: {
'ui-view': {
templateUrl: './app/login/login.html'
}
}
});
When you are in app.login view(state) ui-view will be checked in its parent states template. If you don't have a template, it doesn't know where to render.
'ui-view':{} is targetted to its parent view.
'ui-view#':{} is targetted to the root component that is index.html

angular material animations and ui-router

I'm using angular-material and ui-router within an angular-meteor project. I managed to successfully use ui-router with angular-material and everything's working except for one thing: if you notice, angular material tabs have a tiny animation making each tab's content slide from left or right when clicking on the tab. Using ui-router this animation is lost. Is there any way to keep it using ui-router? Thanks beforehand.
First of all you need to use 'ui-sref' attribute with states in your tabs instead of this pastebin.com/x4MJLfBE 'ui-view' to display your templates from the states.
<md-tabs md-selected="selectedIndex" md-border-bottom md-autoselect>
<md-tab label="Configuration" ui-sref="admin.configurations"></md-tab>
<md-tab label="Users" ui-sref="admin.users.list"></md-tab>
<md-tab label="Songs" ui-sref="admin.songs"></md-tab>
</md-tabs>
<div ui-view></div>
ui-sref it's your states
.state('admin.configurations', {
url: '/configurations',
templateUrl: 'app/admin/configurations/configurations.tmpl.html',
controller: 'ConfigurationsController as ctrl',
})
.state('admin.users.list', {
url: '/list',
templateUrl: 'app/admin/users/users.tmpl.html',
controller: 'UsersListController as ctrl'
})
Plus your parent state must be abstract. It means that now you in admin state where you have template with your tabs
.state('admin', {
url: '/admin',
templateUrl: 'app/admin/admin.tmpl.html',
controller: 'AdminController as ctrl'
})
Ok I solved this way: it is sufficient avoiding "template" or "templateUrl" inside the router state definition and embed each content inside md-tab itself. Let the router state definition just change the url and everything will work.

Nested states UI Router

I am struggling to get nested states working with UI router
I want a page to view a device to be have a URL like /device/SERIAL_NUMBER/info where
/device is fixed
/SERIAL_NUMBER is variable aka :id
/info refers to a nested state
I have a number of nested states I want, but for simplicity I'm only showing a one state. Note that for info it shares the same controller as the parent view, other nested views do not.
State setup
.state('device', {
url: '/device/:id',
templateUrl: '/views/devices/device.html',
controller: 'viewDeviceController'
})
.state('device.info', {
url: 'info',
templateUrl: '/views/devices/device_info.html'
})
My main HTML looks something like this
<body>
<header><h1>Title</h1></header>
<div ui-view>
<!-- This is where /views/devices/device.html goes -->
</div>
/views/devices/device.html looks like so:
<div>General text about a device</div>
<div ui-view>
<!-- This is where /views/devices/device_info.html should go -->
</div>
If I navigate to /#/device/L340009 I see the main page and the device.html, I do not see device_info.html - this is expected but ideally I'd like the default to be to load the first route (info)
If I navigate to /#/device/L340009/info it redirects me to home (which is my otherwise) so something is wrong with the route
Where am I going wrong?
The url here should start with '/'
.state('device.info', {
// instead of this
// url: 'info',
// we need this
url: '/info',
templateUrl: '/views/devices/device_info.html'
})
that will support url concatenation
'/#/device/L340009' + '/info'
is '/#/device/L340009/info'

ui-route how to render multi ui-view when route to template

my requirement is:
index.html
-- /login
-- /main/tab1
-- /main/tab2
-- /userinfo
And the ui will be like:
header: logo, userinfo
left-nav: switch tab1/tab2/tabN
right content: ui-view to change, and multi sub ui-view,
And UI detail:
login will be a independent page, no header, left-nav, right content
main/tab will only change the right content
/userinfo will replace the left-nav and right content to some userinfo page, remain the header, of course using ui-view
I've seen the ui-route demo, but follow the demo, I don't know how to build the route config to what I want, so could any one help me ? The ui-route config is a little complex.....
If my url define is not perfect, please help me improve the url structure, thanks
If you have seen the demo and understood it, this should make sense:
.state('index', {
url: '/',
templateUrl: //your index.html template path,
controller: // your controller if any for index page
})
.state('index.login', {
url: '/login',
templateUrl: // your login template,
controller: // controller for login page
})
.state('index.mainTab1', {
url: '/main/tab1',
templateUrl: // your tab1 template,
})
add the other states in the same manner and you should be ready to go.

How to have global footer in separate views using angular-ui-router v0.2.5 (allows modules)

Sorry if the title of this is confusing.
I'm converting a template I purchased into an angular.js app.
I want to use different modules to organize the app.
I'm also using version 0.2.5 of angular-ui-router which allows routing with separate modules.
All is well except the template I'm using looks like this:
<div>Global Nav Bar</div>
<div>Content that changes with different states right below Nav Bar</div>
<div class="wrapsContentAndPushesToBottom">
<div>Content that changes with different states at
bottom of page thanks to parent div's class</div>
<div>Global Footer also on bottom of page due
to parent div's class</div>
</div>
I'm having a hard time getting that global footer to work because of that parent wrapping div.
Can someone help me get this to work?
UPDATE:
I can't get suggested ng-include to work with my plunkr example: http://plnkr.co/edit/dgNkHX
I also can't it working using a named view for the footer: http://plnkr.co/edit/BO8NDO
I think you're looking for ng-include. http://docs.angularjs.org/api/ng.directive:ngInclude
That will enable you to extract that global footer out to a separate file and just include it in your template.
<div ng-include src="'globalFooter.tpl.html'"></div>
Try something like this:
.state('root', {
abstract: true,
views: {
'#': {
},
'sideBar#': { templateUrl: 'views/sidebar.html', controller: 'SideBarCtrl' },
'header#': { templateUrl: 'views/header.html' },
'footer#': { templateUrl: 'views/footer.html' }
}
})
.state('main', {
url: '/',
parent: 'root',
views: {
'#': { templateUrl: 'views/main_content.html', controller: 'MainCtrl' }
}
})
This is working for me.. I have a global footer.

Resources