Can not get grandchild state to work with UI Router - javascript

I am using Angular 1.6.2 and UI Router. I am still trying to learn the concepts correctly, but have come to a road block.
I have a parent state called app using MainController, and a bunch of child states. However I now want to go one level deeper by making grandchild states.
The following codes leaves me with a blank page when loading www.example.com/manage-users/edit/1 thus not loading the grandparent state.
However it does work if I make app a parent of edit-users (the one I want to make a third level deep), but thats not really the correct way of going about it. Because after this I need to use the parent states for other reasons.
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<base href="/">
// loading JS/CSS etc
</head>
<body ng-app="sampleApp">
<div class="container">
<div ui-view></div>
</div>
</body>
</html>
parent.html
<div ng-controller="MainController as data">
// more html
<div ui-view></div>
</div>
manage-users.html
<div class="col-sm-12" ng-controller="UserController as data">
// more html
<div ui-view></div>
</div>
manage-users-edit.html (only works when I make the parent state 'app' instead of 'manage-users'
<div>Hello World! This is the Edit HTML Page</div>
app.js setting up states
$stateProvider
.state('app', {
templateUrl: 'views/parent.html',
controller: 'MainController as data'
})
.state('manage-users', {
parent: 'app',
url: '/manage-users',
templateUrl: 'views/manage-users.html',
controller: 'MainController as main'
})
.state('edit-users', {
parent: 'manage-users',
url: '/manage-users/edit/:id',
templateUrl: 'views/manage-users-edit.html',
controller: 'MainController as main'
});

Try this:
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<base href="/">
// loading JS/CSS etc
</head>
<body ng-app="sampleApp">
<div class="container" ui-view="container"></div>
</body>
</html>
parent.html
<div ng-controller="MainController as data">
// more html
<div ui-view="parent"></div>
</div>
manage-users.html
<div class="col-sm-12" ng-controller="UserController as data">
// more html
<div ui-view="manageusers"></div>
</div>
app.js
$stateProvider
.state('app', {
views:{
'container': {
templateUrl: 'views/parent.html',
controller: 'MainController as data'
}
}
})
.state('app.manage-users', {
url: '/manage-users',
views:{
'parent':{
templateUrl: 'views/manage-users.html',
controller: 'MainController as main'
}
}
})
.state('app.manage-users.edit-users', {
url: '/edit/:id',
views:{
'manageusers':{
templateUrl: 'views/manage-users-edit.html',
controller: 'MainController as main'
}
}
});
You should always navigate to the child of your hierarchy. In this case, $state.go('app.manage-users.edit-users')
EDIT:
Your URL property in state config is wrong. To hit what you expect, you should enter http://exapmle.com/#/manage-users/edit/1.
I have updated the config, so extra manage-users from the URL is removed. Give it a shot.

Related

Loading multiple templates/controllers on one route

I'm working on a small project and it's been a while since I've worked with Angular. I'm trying to separate all my templates/controllers so I don't have one gigantic file, but I want to be able to access them all on the one page. I'm using Angular UI router, and trying to have them all load on the same route. It doesn't seem to work. Does anyone have any idea how I can load everything on one route but still keep everything separate? Currently it's only loading the first controller/template listed in my routing file (createCompanyController) and not the others.
Here is my routes.js file:
(function() {
angular.module('myApp', ['ui.router'])
.config(['$stateProvider', function($stateProvider) {
var applicationStates = [{
name: 'homepage',
url: '/app',
templateUrl: 'partials/CreateCompany/createCompany.html',
controller: 'createCompanyController',
controllerAs: 'createCompanyCtrl'
},
{
name: 'guestbook',
url: '/app',
templateUrl: 'partials/CreatePerson/createPerson.html',
controller: 'createPersonController',
controllerAs: 'createPersonCtrl'
},
{
name: 'states',
url: '/app',
templateUrl: 'partials/ListCompanies/listCompanies.html',
controller: 'listCompaniesController',
controllerAs: 'listCompaniesCtrl'
}];
applicationStates.forEach(function(state) {
$stateProvider.state(state);
});
}])
})();
And the index.html file I'm using:
<html ng-app='myApp'>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/>
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.css'/>
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<link href='app.less' type='text/css' rel='stylesheet/less'>
</head>
<body class="container" ng-cloak>
<div class='row'>
<div class='span12'>
<div ui-view></div>
</div>
</div>
</body>
</html>
(All my script tags are there, I just removed them from this post to make space). If anyone can help me out I'd be very grateful.
You can use Multiple Named Views
$stateProvider.state('app', {
url: '/app',
views: {
'': {
templateUrl: 'home/home.html'
},
'homepage#app': {
name: 'homepage',
templateUrl: 'partials/CreateCompany/createCompany.html',
controller: 'createCompanyController',
controllerAs: 'createCompanyCtrl'
},
'guestbook#app': {
name: 'guestbook',
templateUrl:'partials/CreatePerson/createPerson.html',
controller: 'createPersonController',
controllerAs: 'createPersonCtrl'
},
'states#app': {
name: 'states',
templateUrl:'partials/ListCompanies/listCompanies.html',
controller: 'listCompaniesController',
controllerAs: 'listCompaniesCtrl'
}
}
And the index.html
<html ng-app='myApp'>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/>
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.css'/>
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<link href='app.less' type='text/css' rel='stylesheet/less'>
</head>
<body class="container" ng-cloak>
<div class='row'>
<div class='span12'>
<div ui-view="homepage"></div>
<div ui-view="guestbook"></div>
<div ui-view="guestbook"></div>
</div>
</div>
</body>
</html>
The answer to your question is "Angular Components" (available from angular 1.5 version onward).
Component => Template + Controller
Angular Route which would contain all templates => combination of components (in your case CreateCompany, CreatePerson and ListCompanies components all in one route's template)
All you need to do is:
Create components (controller + template for CreateCompany, CreatePerson and ListCompanies) instead of routes.
Create a single route "/app" and define the template for this route as below
HomePage.html
<div class='row'>
<div class='span12'>
<create-company></create-company>
<create-person></create-person>
<list-companies></list-companies>
</div>
</div>
Fiddle: https://jsfiddle.net/vuas3wbq/2/
Reference link for Angular components:
https://docs.angularjs.org/guide/component

How does Node JS know how to handle routes

I am just trying to get a partial page to load.
HTML:
<!DOCTYPE html>
<html ng-pp='app' lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Friends</title>
<script src='angular/angular.js'></script>
<script src='angular-route/angular-route.js'></script>
<script src='app.js'></script>
</head>
<body>
<p>
<a href='#!/list'>All Your Frinds</a> | <a href='#!/new'>Add a Friend</a>
</p>
<div ng-view=''>
</div>
</body>
</html>
Routing:
var app = angular.module('app', ['ngRoute']).config(function ($routeProvider)
{
$routeProvider
.when('/list',
{
templateUrl: 'partials/list.html'
})
.when('/new',
{
templateUrl: 'partials/create.html'
})
.when('/show/:id',
{
templateUrl: 'partials/show.html'
})
.when('/edit/:id',
{
templateUrl: 'partials/edit.html'
})
.otherwise(
{
redirectTo: '/'
})
});
Although, I have a controller, there is nothing in it. I just want to be all to see the a partial page is loading and it is not. I need the ng-controller directive in my partial page for it to load?
It doesn't do anything in this example
Most likely your nodejs is serving your static angularjs content from a folder, if you are using expressjs it will be because of
app.use(express.static('public'))
However, the angularjs router is handling your partials
Make sure you set
$locationProvider.html5Mode(false);
It can also help by looking into the developer console to see what url your router is pointing too.
Also
is fine by itself without the ""
I tried your code after removing exclamation mark from href and it's working as expected. Also add base href in HTML. Try below code
<!DOCTYPE html>
<html ng-pp='app' lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<base href="/"></base>
<meta charset="utf-8" />
<title>Friends</title>
<script src='angular/angular.js'></script>
<script src='angular-route/angular-route.js'></script>
<script src='app.js'></script>
</head>
<body>
<p>
<a href='#/list'>All Your Frinds</a> | <a href='#/new'>Add a Friend</a>
</p>
<div ng-view=''>
</div>
</body>
</html>
JS
var app = angular.module('app', ['ngRoute']).config(function ($routeProvider,$locationProvider)
{
$locationProvider.html5Mode(false);
$routeProvider
.when('/list',
{
templateUrl: 'partials/list.html'
})
.when('/new',
{
templateUrl: 'partials/create.html'
})
.when('/show/:id',
{
templateUrl: 'partials/show.html'
})
.when('/edit/:id',
{
templateUrl: 'partials/edit.html'
})
.otherwise(
{
redirectTo: '/'
})
});
The directive was misspelled... Should be:
ng-app

Angular-UI-Router not working properly

So, today I added angular-ui-router to my webapp. However, it's showing some really weird behaviour. It used to display the current page in the ui-view. So a page in a page.
Now, it's working correct, but it doesn't show subpages and I can't seem to figure out why.
Main page
<!doctype html>
<html lang="en" ng-app="ExampleApp">
<head>
<meta charset="UTF-8">
<title>Example App</title>
</head>
<body>
<div>
<div ui-view></div>
</div>
<!-- Angular -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.4/angular.js"></script>
<!-- UI-Router -->
<script src="//angular-ui.github.io/ui-router/release/angular-ui-router.js"></script>
<!-- Main app file -->
<script src="/js/main.js"></script>
</body>
</html>
main.js
var ExampleApp = angular.module('ExampleApp', ['ui.router']);
ExampleApp.config(function($stateProvider, $urlRouterProvider) {
//
// For any unmatched url, redirect to /home
$urlRouterProvider.otherwise("/home");
//
// Now set up the states
$stateProvider
.state('home', {
url: "/home",
templateUrl: "views/home.html",
controller: "MainController"
})
.state('settings', {
url: "/settings",
templateUrl: "views/settings.html",
controller: "SettingsController"
})
.state('settings.account', {
url: "/account",
templateUrl: "views/settings.account.html",
controller: "AccountSettingsController"
});
});
ExampleApp.config(["$locationProvider", function($locationProvider) {
$locationProvider.html5Mode(true);
}]);
Try this
url:"settings/account",

multiple ui-view html files in ui-router

Is it possible to make something using 2 or more html files using ui-view? I need it to be something like this :
I've tryed to do something working on plinker, but looks like I clearly don't uderstand concepts. I've read a nested ui-vew tutorial but they simple make a single index.html and place multiple ui-view there, but I need multiple .html files.
test.html is just a file with some text that should be displayed under master header
index.html looks like this
<html ng-app="MyApp">
<head>
<link href="stylesheets/style.css" rel="stylesheet">
</head>
<body>
<h4>
This should be Master header
</h4>
<div ui-view></div>
<script data-require="angular.js#*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<script data-require="ui-router#*" data-semver="0.2.10" src="https://rawgit.com/angular-ui/ui-router/0.2.10/release/angular-ui-router.js"></script>
<script src="app.js"></script>
<script src="controllers/main.js"></script>
</body>
</html>
this is app.html
<head>
<link href="stylesheets/style.css" rel="stylesheet">
</head>
<body>
<h4>
This should be Sub master header
</h4>
<div ui-view></div>
</body>
and app.js is written on pseudo code showing how I want it to work, because I clearly have no idea how to make it work
angular.module('MyApp', [
'ui.router'
])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('index', {
templateUrl: 'index.html',
controller: 'IndexCtrl'
})
.state('index.test', {
url: '/',
templateUrl: 'test.html',
controller: 'TestCtrl'
})
.state('app', {
templateUrl: 'app.html',
controller: 'AppController'
})
.state('app.test2', {
url: '/test2',
templateUrl: 'test2.html',
controller: 'Test2Controller'
})
})
test2.html is just a text.
I am not sure if I do understand your goal 100%, but there is updated plunker, showing how we can work with nested views.
Firstly, there is a $state defintion showing the nesting:
$stateProvider
.state('index', {
url: '/',
views: {
'#' : {
templateUrl: 'layout.html',
controller: 'IndexCtrl'
},
'top#index' : { templateUrl: 'tpl.top.html',},
'left#index' : { templateUrl: 'tpl.left.html',},
'main#index' : { templateUrl: 'tpl.main.html',},
},
})
.state('index.list', {
url: '/list',
templateUrl: 'list.html',
controller: 'ListCtrl'
})
.state('index.list.detail', {
url: '/:id',
views: {
'detail#index' : {
templateUrl: 'detail.html',
controller: 'DetailCtrl'
},
},
})
And here is the index core template layout.html:
<div>
<section class="top">
<div ui-view="top"></div>
</section>
<section class="middle">
<section class="left">
<div ui-view="left"></div>
</section>
<section class="main">
<div ui-view="main"></div>
</section>
</section>
</div>
And how it works?
I. List View
we can see the content of the tpl.top.html
<div>
This is a tpl.top.html<br />
<a ui-sref="index">index</a>
<a ui-sref="index.list">index.list</a><br />
</div>
which does have some navigation to the index or list view. The list view, will be injected into the tpl.left.html, which looks like this:
<div>
This is a tpl.left.html
<h4>place for list</h4>
<div ui-view=""></div>
</div>
Becuase the view target is unnamed <div ui-view=""></div>, we can defin list $state like this:
.state('index.list', {
url: '/list',
templateUrl: 'list.html',
controller: 'ListCtrl'
})
we can see, that we target the index (root) state view anchor, which is unnamed. But for a detail we do use different technique:
II. Detail View
This is the content of the tpl.main.html:
<div>
This is a tpl.main.html
<h4>place for detail</h4>
<div ui-view="detail"></div>
</div>
In this case, the anchor for a view is named: ui-view="detail", that is why we have to define that detail state like this:
.state('index.list.detail', {
url: '/:id',
views: {
'detail#index' : {
templateUrl: 'detail.html',
controller: 'DetailCtrl'
},
},
})
We can see, that because the parent view is not the target of our state (the grand parent index is the target) we have to use aboslute naming: 'detail#index'
III. View Names - Relative vs. Absolute Names
small cite from doc:
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.
SUMMARY:
So, this example is about it - about almost all essential features of the ui-router. We showed here how to use nesting, view naming (absolute/relative) and also how to use multiple views for one state (index state definition)
Please, observe that all in action here (click the inex.html in the top section, then try to select some details)

ui-router nested views and passing variable

i have a lot of question about the angular ui-router module.
I'm tryin to understand it well before implement my applications with that one, but i have problems even with simple things.
HTML
<!doctype>
<html ng-app='myapp'>
<head>
<title>main</title>
<meta charset="utf-8">
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"></script>
<!--controller-->
<script src="app.js"></script>
<script src="controller.js"></script>
<!-- endbuild -->
</head>
<body>
hi
<div ui-view="view1"></div>
<div ui-view="view2"></div>
</body>
</html>
EDIT
var app=angular.module('myapp',['ui.router'
]);
app.config(function($stateProvider/*,$urlRouteProvider*/){
//$urlRouteProvider.otherwise("view1");
$stateProvider.
state('father',{
abstract:true,
template:'<div ui-view></div>',
controller:function($scope){
$scope.view='hi';
}
}).
state('son',{
parent:'father',
url:'/',
views:{'view1':{
templateUrl:'view1.html'
},
'view2':{
templateUrl:'view2.html'
}
}
})
})
and this is my js plunker http://plnkr.co/edit/hsEFKhpaGkIkzarQiuQQ?p=preview.
Now the questions:
1) As you can see in the index.html nothing appears, and my first intention is to see both the views in the main window
2)i have build an abstract state to pass a $scope.view to all the child state, but it seems it didn't work too
3)If what i want to do is done in the wrong way, what's the better approach to do it?
After spending more time than I should have playing around with it, I think I figured out what you were looking for.
I made a few changes and I will try to go over them all.
In the HTML, I added ui-router, moved your js script tags to just before </body>, that allowed me to get rid of all the console errors:
<!doctype>
<html ng-app='myapp'>
<head>
<title>main</title>
<meta charset="utf-8">
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ui-view ></div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"></script>
<script src="ui-router.js"></script>
<script src="app.js"></script>
</body>
</html>
Than in your app.js file I made a few changes:
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.when('', '/');
$stateProvider
.state('father', {
abstract: true,
// I couldn't get this to work without a templateUrl for some reason,
// I'm sure with a little time you could figure this part out.
templateUrl: 'father.html',
controller: function($scope) {
$scope.view = 'Hello Dad';
console.log($scope.view);
}
})
.state('father.son', {
parent: 'father',
url: '/',
views: {
// Added the absolute target declaration `#father`, see link 1 below
'view1#father': {
templateUrl: 'view1.html',
controller: function($scope) {
console.log($scope.view);
}
},
'view2#father': {
templateUrl: 'view2.html',
controller: function($scope) {
console.log($scope.view);
}
}
}
})
});
Here is the father.html template:
<!-- Big file, I know -->
<div ui-view="view1"></div>
<div ui-view="view2"></div>
Link 1: View Names - Relative vs. Absolute Names
Link 2: Plunker

Categories

Resources