UI-Router displaying white page without errors - angularjs

I'm using UI-Router for an app but I cant for the life of me understand why the page is blank. None of the template urls are displaying. Here's the plunkr
layout.html
<div ui-view="form"></div>
sdagas
<div ui-view="results"></div>
form
This is the form page
results
Results
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state("index", {
url: "/",
abstract: true,
templateUrl: 'layout.html',
controller: 'MainController',
controllerAs: 'main'
})
.state('index.layout', {
abstract: true,
url: 'layout',
views: {
'form' : {
templateUrl: 'form.html'
},
'results': {}
}
})
.state('index.layout.results', {
url: '/results',
views: {
'results#layout': {
templateUrl: 'results.html'
}
}
});
$urlRouterProvider.otherwise('/');
});
app.controller('MainController', function($state) {
console.log($state);
console.log('hello');
});

Firstly, there is no ng-app declared in your plunker.. You should have ng-app="app" on your html tag.
Secondly, like #Bilal said, you can't have abstract:true on the states you want to transition to.
Moreover, your ui-sref should point to the states:
<a class="brand" ui-sref="index">home</a>
|
<a class="brand" ui-sref="index.layout">ui-router</a>
Here is your updated plunker

I updated a plunker which is working here
The way how we can call state resuts is:
ui-sref
<a class="brand" ui-sref="index.layout.results">
href
<a class="brand" href="#/layout/results">
We can never navigate to state which is abstract. So we cannot go to index or layout
To make the plunker running I also introduced the ng-app="app":
<!DOCTYPE html>
<html ng-app="app">
which does start up the app
Also, because the '/' is otherwise but abstract I used another setting to go to some non abstract state
$urlRouterProvider.when('/', '/layout/results');
$urlRouterProvider.otherwise('/');
And finally (but almost the most important), this is the updated super child state, which does target the named view not in layout but in index state
.state('index.layout.results', {
url: '/results',
views: {
// wrong
//'results#layout': {
// this target is in the super parent
'results#index': {
templateUrl: 'results.html'
}
}
});
Check it here

From ui-router wiki:
An abstract state can have child states but cannot get activated
itself. An 'abstract' state is simply a state that can't be
transitioned to. It is activated implicitly when one of its
descendants are activated.
https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views
You made root state abstract: true so it can't be transitioned.
Update:
ui-sref="/" should contain state name not the url path itself. If you really want to use url path then you should use href="/"
Plunkr
Update:
You also missed ng-app="app" in your html.
<html ng-app="app">

Related

ui-router, url changes, does hit the controller, content wont load, only on reload

I got a sub state that is suppose to load content into a ui-view called ui-solution. It does so while the user is in the flow of creating something called "solution". The strange part is that once that is saved and the user revisit a specific part of the process that calls that same sub state it does not load the content. Can anybody spot anything wrong with this code that could cause this inconsistent behaviour? Just so I can rule this out and start looking elsewhere.
the url change
the url has the same parameters
on reload of the page the right content is loaded in that `ui-view``
The setup of the page is
ui-view
- tabs
-- ui-view="ui-solution"
$stateProvider.state('analyse', {
url: '/analyse/:id',
data: {
solution: false
},
templateUrl: 'app/components/a/a.html',
controller: 'Analisys'
});
$stateProvider.state('analyse.solution', {
url: '/solution',
data: {
solution: true
},
views: {
'ui-solution': {
templateUrl: 'app/components/a/s/s.html',
controller: 'Analisys'
}
}
});
ui-view="ui-solution" is present in a.html one of the tabs there
you try to load nested view and is not in your parent view so it cant loaded - i had the same problem
i suggest to look at this and also the 2 link i sent on the comment
$stateProvider
.state('analyse', {
url: '/analyse/:id',
data: {
solution: false
},
templateUrl: 'app/components/a/a.html',
//controller: 'Analisys' better using ng-controller in the html instead of here
})
.state('analyse.solution', {
url: '/solution',
data: {
solution: true
},
views: {
'ui-solution': {
templateUrl: 'app/components/a/s/s.html'
}
}
});
and your a.html should look like
<div ng-controller="Analisys as ctrl">
<h1 ui-serf="analisys.solution">should load the nested view</h1>
<div ui-view="ui-solution"></div>//here should see the nested html
</div>
and index.html should have
<div ui-view></div>
hope it will help you
btw
you dont need the ui-view="solution" cause its automatically refer to the ui-view inside (unless you have few
so you can do so
$stateProvider
.state('analyse', {
url: '/analyse/:id',
data: {
solution: false
},
templateUrl: 'app/components/a/a.html'
//controller: 'Analisys' better using ng-controller in the html instead of here
})
.state('analyse.solution', {
url: '/solution',
data: {
solution: true
},
templateUrl: 'app/components/a/s/s.html'
});
and a.html
<div ng-controller="Analisys as ctrl">
<h1 ui-serf="analisys.solution">should load the nested view</h1>
<div ui-view></div>//here should see the nested html
</div>

Ionic back button with parent and child state

I have an ionic app with the following ui-router setup, where locations state is the parent of 2 states map and favourites. The updates state is a sort of details page that can be access from any state.
.state('locations', {
abstract: false,
cache: true,
url: '/locations',
templateUrl: 'templates/locations.html',
controller: 'LocationsCtrl'
})
.state('locations.favourites', {
cache: true,
url: '/favourites',
templateUrl: 'templates/locations.favourites.html',
controller: 'LocationsFavouritesCtrl'
})
.state('locations.map', {
cache: true,
url: '/map',
templateUrl: 'templates/locations.map.html',
controller: 'LocationsMapCtrl'
})
.state('updates', {
cache: true,
url: '/updates/:place_id',
templateUrl: 'templates/updates.html',
controller: 'UpdatesCtrl',
params: {'place_id': 'undefined'}
})
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/locations/map');
This is the HTML
<body ng-app="app" animation="slide-left-right-ios7">
<div>
<div>
<ion-nav-bar class="bar-turq">
<ion-nav-back-button class="button-icon icon ion-ios-arrow-back light"></ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view></ion-nav-view>
</div>
</div>
This works perfectly except that the back button on the "updates" state always goes back go locations.map rather than remembering the previous state, ie I might have come from locations.favourites. Is there something fundamentally wrong with my setup?
**
UPDATE:
**
Okay so inside UpdatesCtrl I added this code to check the view history, and no matter where I access the /updates view from, the back view is locations.map
$scope.$on('$ionicView.enter', function() {
console.log($ionicHistory.viewHistory());
}
Remove this params: {'place_id': 'undefined'} or make sure that you pass thru the place_id in $stateparams.place_id
I think that you are ending in an none unknown state (unresolved) and goes to your default state.
You haven't posted your default location route. But I'm assuming that it has this config: $urelRouterProvider.ohterwise('/location.map');

Angular ui-router subview issues

I've been working with Angular for a year or 2 now, but this is my first project using ui-router. I'm running into a few issues with views and sub-views. The app is a standard left-side menu bar, with the views on the right changing depending on what's clicked in the menu bar.
On index.html
<body>
<div ui-view></div>
</body>
In the config.js file, which defines the routes
.state("dashboard", {
url: "/dashboard",
templateUrl: "components/dashboard/dashboard.html",
data: {
pageTitle: "Dashboard",
requiresLogin: false
}
})
.state("dashboard.welcome", {
url: "/welcome",
templateUrl: "components/welcome/welcome.html",
data: {
pageTitle: "Welcome",
requiresLogin: false
}
})
In the dashboard.html file
<div class="dashboard">
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-md-8">
<div ui-view>
The /dashboard path loads correctly, and will load the left-side navigation bar with a blank right side. But changing the state to dashboard.welcome (/welcome) will not load the welcome.html template.
Whenever working with ui-router you need to understand that the concept of states is different from routes. When you define a sub-state, its defined relative to its parent state. In your scenario dashboard.welcome is defined as a child state of dashboard. The routes to substate is relative to the parent and is {parent url}/{child url}. Hence you should use either of the below 2 to route to that state:
Using $state.go change the state by specifying state name
$state.go('dashboard.welcome');
Using $location.path change the route by specifying url
$location.path('/dashboard/welcome');
It sounds like you want links to /welcome to be for state dashboard.welcome. Here is a plunker showing how this can be done. I show two sets of dashboard and welcome states. The first set of states (dashboard & welcome) shows that /dashboard/welcome will bring you to the dashboard.welcome state.
The second set (dashboard2 & welcome2) shows that /welcome will go to state dashboard2.welcome2. I believe this is what you were looking for.
If you hover over the links you can see where they will take you.
https://plnkr.co/edit/AVKPFa?p=info
Nested routes in ui-router get nested urls. I would however recommend using named-views for this kind of structure. You can find more info about it here:
https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
The gist of it is: you can specify a named component (ui-view) for your left menu navigation and another one for content, which gives you much more control down the line, because named components can be overwritten in child states or they can keep the default template, depending on your needs.
Example:
.state('root', {
url: '',
abstract: true,
views: {
'header': {
templateUrl: 'templates/partials/header.html',
controller: 'headerCtrl'
},
'logo': {
templateUrl: 'templates/partials/logoView.html'
},
'footer':{
templateUrl: 'templates/partials/footer.html',
controller: 'footerCtrl'
}
}
})
.state('root.login', {
url: '/login',
views: {
'header#': {
template: ''
},
'container#': {
templateUrl: 'templates/login.html',
controller: 'loginController'
}
}
})
.state('root.report', {
url: '/report',
views: {
'container#': {
templateUrl: 'templates/eu_dashboard.html',
controller: 'reportController'
}
}
})
And in your index.html:
<div ui-view="logo"></div>
<div ui-view="header"></div>
<div id="mainView" ui-view="container"></div>
<div ui-view="footer"></div>

Redirect to a new template in angular js

I am new to angularjs, so please consider my mistakes.
The scenario is, I have an index.html page and login.html page, index and login will have different layout thus different header footer and all.
All other pages expect login will share same layout as index.html
Now, how can I navigate to login.html using anuglar ui router.
myApp.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state('home', {
url: '/',
templateUrl: 'app/views/site/home.html',
controller: 'homeCtrl'
}).state('login', {
url: '/login',
templateUrl: 'app/views/site/login.html'
})
});
This does not work as it loads the content of login into index keeping header and footer same of index. I know the state is supposed to work that way.
Now, is there any way I can just call a completely new view using ui.router.
I really appreciate your help.
Thanks
You could probably set up multiple named views (https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views).
This would allow you to make the header and footer into separate views that you can swap in and out. I don't think there is a way to completely swap out an entire page, though.
<body>
<header ui-view="header"></header>
<main ui-view="content"></main>
<footer ui-view="footer"></footer>
</body>
.state('login', {
views: {
'header': { ... templates and/or controllers ... },
'content': { ... templates and/or controllers ... },
'footer': { ... templates and/or controllers ... },
}
})
I achieve this by making my entire layout into templates. Essentially, my index.html is nothing more than this:
<html ng-app="appName" ng-strict-di>
<head>
<title></title>
</head>
<body>
<div class="ng-cloak" ng-cloak ui-view></div>
</body>
</html>
Then I use abstract states to create template zones. For instance, my auth states:
$stateProvider
.state('auth', {
abstract: true,
url: '/auth',
template: '<div ui-view></div>'
})
.state('auth.login', {
url: '/login',
templateUrl: 'auth/login.html',
controller: [ loginController],
controllerAs: 'vm'
})
.state('auth.logout', {
url: '/logout',
resolve: {
logout: [ 'api', function (api) {
return api.getLogout().$promise;
}]
},
controller: [ logoutController],
controllerAs: 'vm'
});
This causes the auth/login route to render directly into the main ui-view where it can have it's own unique layout. Similarly, I may have an abstract core state that sets a common scope and template for the core parts of my app, which all share a common template structure.
If there are re-used elements that touch both the core and auth sections, then I use ng-include to bring in those individual partials.

How to correctly use nested routes to fix the following example?

So, it seems I am not getting ui-router, after all.
Here is the broken example:
http://plnkr.co/edit/WgDqTzE3TJjrCZ2pxg5T?p=preview
The actual file structure is:
app/
app.js
index.html
main/
main.html
header/
header.html
footer/
footer.html
sections/
content1/
content1.html
content2/
...
index.html has a simple <div ui-view></div>
main.html has:
<div ui-view="header"></div>
<div ui-view></div>
<div ui-view="footer"></div>
header.html, footer.html, content1.html, ... have actual content.
app.js has:
$stateProvider
.state("app", {
url: "",
abstarct: true,
templateUrl: "main.html"
})
.state("app.main", {
url: "",
abstarct: true,
views: {
"header": {
templateUrl: "header.html"
},
"footer":{
templateUrl: "footer.html"
}
}
})
.state("app.main.content1", {
url: "/",
templateUrl: "content1.html"
});
So, I thought this meant going to "/" would show me header, footer, and automatically insert content in the unnamed ui-view.
It does not. What am I doing wrong?
To make it quickly working (not as intended) I've just added an anchor into the footer and now it is working
<div>
im footer
<div ui-view=""></div>
</div>
Why? because our state def is like this:
.state("app.main.content1", {
url: "/",
templateUrl: "content1.html"
});
Which means:
do search for unnamed view in my parent
The footer view is a parent of the state "app.main.content1", so this way we can target it.
There are other options as well.
Here is what was most likely intended: , state defintion is changed:
.state("app.main.content1", {
url: "/",
views: {
"#app": {
templateUrl: "content1.html"
}
}
So, now we target the app state, its view anchor <div ui-view="">, by the absolute naming. See:
View Names - Relative vs. Absolute Names
Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname#statename, where viewname is the name used in the view directive and state name is the state's absolute name, e.g. contact.item. You can also choose to write your view names in the absolute syntax.
At the end, we can reach the same with even one abstract state and one child, check it here:
$stateProvider
.state("app", {
url: "",
abstarct: true,
views: {
"" : {
templateUrl: "main.html",
},
"header#app": {
templateUrl: "header.html"
},
"footer#app":{
templateUrl: "footer.html"
}
}
})
.state("app.content1", {
url: "/",
templateUrl: "content1.html",
});
Now, the all UI-Router magic is happening in the root state def. We firstly target root (index.html) unnmaed view, to inject the main.html. Next - othe views target this state itself (the main.html) via "header#app" - absolute naming
That would be the most suitable way... working example

Resources