ui router does not put the content in the named ui-view - angularjs

When I enter the route
\#\projects\100\dates\2014-01-01
in the url and press return I get the "projects" state.
I expected to trigger "projects.selected.dates" state.
Why does the routing not work? Actually it works locally on my machine without named view...
http://plnkr.co/edit/0DJ6W7QEPx2UzpdzDrVu?p=preview
'use strict';
angular
.module('projectplanner', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/projects');
$stateProvider
.state('projects', {
url: '/projects',
views: {
'menu': {
template: 'Start your projects!'
},
'content': {
templateUrl: "projects.html",
controller: 'ProjectsController'
}
}
})
.state('projects.selected', {
url: '/:projectId'
})
.state('projects.selected.dates', {
url: '/dates/:date',
views: {
'menu': {
templateUrl: 'menu.html'
},
'content': {
templateUrl: 'dateplanner.html',
controller: 'DateplannerController'
}
}
})
});
<!DOCTYPE html>
<html ng-app="projectplanner">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="https://code.angularjs.org/1.2.20/angular.js" data-semver="1.2.20"></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="ProjectsController.js"></script>
<script src="DateplannerController.js"></script>
</head>
<body>
<div class="wrapper" >
<header class="aside">Logo</header>
<div ui-view="menu" id="menu" class="aside"></div>
<div ui-view="content" class="main">
</div>
</div>
</body>
</html>

There is the updated and working plunker, and this is the essential update:
.state('projects.selected.dates', {
url: '/dates/:date',
views: {
'menu#': { // HERE is # added
templateUrl: 'menu.html'
},
'content#': { // HERE is # added
templateUrl: 'dateplanner.html',
controller: 'DateplannerController'
}
}
})
See the '#' at the end of the ui-view name
The full explanation is here:
View Names - Relative vs. Absolute Names (cite)
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.
So, what I did is use of the absolute name .. targeting the root - index.html
Some examples from documentation... greatly explaining that all:
$stateProvider
.state('contacts', {
// This will get automatically plugged into the unnamed ui-view
// of the parent state template. Since this is a top level state,
// its parent state template is index.html.
templateUrl: 'contacts.html'
})
.state('contacts.detail', {
views: {
////////////////////////////////////
// Relative Targeting //
// Targets parent state ui-view's //
////////////////////////////////////
// Relatively targets the 'detail' view in this state's parent state, 'contacts'.
// <div ui-view='detail'/> within contacts.html
"detail" : { },
// Relatively targets the unnamed view in this state's parent state, 'contacts'.
// <div ui-view/> within contacts.html
"" : { },
///////////////////////////////////////////////////////
// Absolute Targeting using '#' //
// Targets any view within this state or an ancestor //
///////////////////////////////////////////////////////
// Absolutely targets the 'info' view in this state, 'contacts.detail'.
// <div ui-view='info'/> within contacts.detail.html
"info#contacts.detail" : { }
// Absolutely targets the 'detail' view in the 'contacts' state.
// <div ui-view='detail'/> within contacts.html
"detail#contacts" : { }
// Absolutely targets the unnamed view in parent 'contacts' state.
// <div ui-view/> within contacts.html
"#contacts" : { }

Related

Angular UI Router - using ui-sref on child view to change parent view

Im fairly new to angular UI. I am trying to have a ui-view that has a child a tag that has an sref that will change its parent ui-view
Something like this:
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div ng-app="app">
<h1>Hello</h1>
<ul>
<li>
<a ui-sref="organisations">Click 1</a>
</li>
</ul>
<div ui-view="testview"></div>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.min.js"></script>
<script>
angular
.module('app', ['ui.router'])
.config(setViewStates)
;
function setViewStates($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
// Organisations
.state('organisations', {
url: '/',
views: {
'testview': {
template: '<p>view 1</p><a ui-sref="organisations.club">Click</a>',
},
}
})
.state('organisations.club', {
url: '/club',
views: {
'testview#': {
template: '<p>view 2</p>',
controller: function($scope) {
console.log('hello');
}
},
}
});
;
}
</script>
</html>
This is a small mockup of what I'm intending to do but ultimately, all I want to do is have a template with a table of items, and once you press on one of those items, the table template would be replaced with the details of that item, along with its state and url.
So the hierarchy is something like:
/club/list
/club/:clubId
.state('organisations', {
url: '/:id',
views: {
'testview': {
template: '<p>view 1</p><a ui-sref="organisations({id : id_of_this_file})">Click</a>',
},
}
})
if you have only one state with params as id, you can send id as new or any other keyword for the first time and manipulate the html with ng-if on whether you receive id as 'new' or the file id. if you receive new in id parameter show the table else if you receive proper id show the file data.

ui.router including partials inside head

I have the following template loaded with PHP:
<!DOCTYPE>
<html>
<head>
<div ui-view="head"></div>
<title>Main page</title>
</head>
<body>
<div ui-view="body"></div>
<div ui-view="scripts"></div>
</body>
</html>
I now want to define head, body, and scripts partials individually for each route. I did this, but I can't insert a view to the div inside the head element - it's not valid, and it doesn't work anyways.
How can I do this?
$stateProvider
.state('list', {
url: '/fooBar/list',
views: {
'body': {
templateUrl: 'list.html',
controller: 'ListCtrl'
},
'head': {
templateUrl: 'head.html'
}
}
});

Editing resolved object is not updating parent/child controller data

I am sharing data between parent and child controllers using resolve option available in ui-router.
PFB the code,
var app = angular.module('app',['ngRoute','ui.router']);
app.config(function($stateProvider,$urlRouterProvider){
$urlRouterProvider.otherwise('/first/second');
$stateProvider
.state('first', {
url: '/first',
template: "<div>First Page :: Name - <input type='text' ng-model='parentName'/></div> <div ui-view=''></div>",
resolve: {
name : function(){return 'Dheepan Raju';}
},
controller : function($scope,name){
$scope.parentName = name;
}
})
.state('first.second', {
url: '/second',
template: "<div>Second Page :: Name - <input type='text' ng-model='childName'/></div>",
controller : function($scope,name){
$scope.childName = name;
}
});
});
index.html
<!DOCTYPE html>
<html ng-app='app'>
<head>
<script src="https://code.angularjs.org/1.4.2/angular.js" data-semver="1.4.2" data-require="angular.js#*"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-route.js" data-semver="1.3.15" data-require="ngRoute#1.3.15"></script>
<script data-require="ui-router#*" data-semver="0.2.15" src="//rawgit.com/angular-ui/ui-router/0.2.15/release/angular-ui-router.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ui-view=""></div>
</body>
</html>
Here is the plunker. When the page is loaded both child and parent input fields are having same name. But if I edit any of those values, it is not updating the other property. Both looks individual. How can I make both the controllers to use same data and if edit that in one controller, other controller is also updated(without any $broadcast or $watch)
This can be accomplished by using a shared service with the controllers. By setting the ng-model of both to use a shared object, you can keep both controllers in sync through the service. The service handles the shared object and the controllers just reference it. No watch or broadcast required.
Updated script.js
app.config(function($stateProvider,$urlRouterProvider){
$urlRouterProvider.otherwise('/first/second');
$stateProvider
.state('first', {
url: '/first',
template: "<div>First Page :: Name - <input type='text' ng-model='parentName.name''/></div> <div ui-view=''>Hell</div>",
resolve: {
name : function(){return 'Dheepan Raju';}
},
controller : function($scope,name, SharedData){
// Init
SharedData.name = name;
$scope.parentName = SharedData;
}
})
.state('first.second', {
url: '/second',
template: "<div>Second Page :: Name - <input type='text' ng-model='childName.name'/></div>",
controller : function($scope, SharedData){
$scope.childName = SharedData;
}
});
}).service("SharedData", function() {
return { name: "" }
});
I have updated your plunker showing this: http://plnkr.co/edit/XIvHXSy6oDuuuKsmE3AF?p=preview

Can not render a child view outside the of the parent`s parent view with ui router

I have created a plunker repro here: http://plnkr.co/edit/zU3PtJamS61Ac0bAKToD?p=preview
When you go to the projects tab and click the Edit button I would expect that the Edit.Html view is rendered in the ui-view "outer".
When I debug then even the ProjectsEditController is created but the state is not really activated and the ui sticks to the projects view.
What do I wrong?
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="style.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.3/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js"></script>
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.js"></script>
<script src="app.js"></script>
<script src="AdministrationController.js"></script>
<script src="ProjectsController.js"></script>
<script src="ProjectsEditController.js"></script>
<script src="SettingsController.js"></script>
</head>
<body ng-app="routedTabs" >
<div class="wrapper">
<div ui-view="outer">
<header class="aside">thats the header </header>
<div ui-view="menu" id="menu" class="aside">this is the menu aside</div>
<div ui-view="content" class="main container">
<h1>Working on it... </h1>
</div>
</div>
</div>
</body>
</html>
Edit.html
<div ng-bind="title"></div>
<button ui-sref="main.projects.edit({id: 10})" class="btn btn-default primary">Edit</button>
app.js
var app = angular.module("routedTabs", ["ui.router", "ui.bootstrap"]);
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("");
$stateProvider
.state("main", {
abtract: true,
url: "",
views: {
'content#': {
templateUrl: 'administration.html',
controller: 'AdministrationController'
}
}
})
.state("main.projects", {
url: "/projects",
views: {
'menu#': {
template: 'test'
},
'planner#main': {
templateUrl: 'projects.html',
controller: 'ProjectsController'
}
}
}).state('main.projects.edit', {
url: '/edit/:id',
views: {
'outer#': {
templateUrl: 'edit.html',
controller: 'ProjectsEditController'
}
}
})
.state("main.tab2", {
url: "/settings",
views: {
'menu#': {
template: 'bla'
},
'planner#main': {
templateUrl: 'settings.html',
controller: 'SettingsController'
}
}
});
});
UPDATE
According to #Karthik`s statement I can not render the edit view into the "outer" ui-view.
I have prepared here a plunker without abstract main state and tabs. In this sample is just a projects view with an edit project button which should render the edit view into the ui-view called "outer" and indeeded it works!
http://plnkr.co/edit/ogQIpfHz7Cy9Jo03czKL?p=preview
So my new question is, what is the difference between those samples that it works in this plunker but not in the tabs plunker?
And how can I concretely make it work with tabs then?
Your projects is working and edit tab is displayed (if you debug your js code you will see it). In your case problem is in your AdministrationController.js.
On every update event form tabset is called go function with route /projects (current tab)
$scope.go = function(route){
$state.go(route);
};
This changes state back to main.projects so it seems like state was not changes which it actually was.
You probably want to re-write triggering within AdministrationController.js or found out why is update/go function triggered when leaving tab.
See if answer in this topic helps. You could use this approach instead of update function.
As temporary solution could be used something like:
$scope.go = function(route){
if($state.$current.name != 'main.projects.edit'){
$state.go(route);
}
}

ui-router global state param

I am using ui-router for my router. I want to implement i18n and for it I've created the following states
$stateProvider
.state('main', { url: '/:lng', abstract: true, template: '<div ui-view></div>'})
.state('main.index', { url: '/', templateUrl: '/views/index.html'})
.state('main.gallery', { url: '/gallery', templateUrl: '/views/gallery.html', controller: 'GalleryCtrl'})
And created the following links
a(ui-sref='main.index') Home
a(ui-sref='main.gallery') Gallery
However this links look like:
for index //
for gallery //gallery
I have found out that in uiSref directive he cannot inherit params from abstact main state.
Am I doing wrong with states?
Upadate:
I have one problem. I binded params to the scope object. In the ui-sref directive there is a watcher that tracks the params change, but in the handler of the watcher there is the following checking
if (newVal !== params) update(newVal);
However, when I try to debug the params is changing to the new param (I actually don't understand how, because params is assigned only once) and in the if check newVal === params
params = $scope.$eval(attr.params) //something like this
I even tried to use Object.observe on param object but it doesnot trigger before "watch" handler is triggered.
Now, I changed if check to make my code work.
There's nothing wrong with your state definitions from what I gather, but you're not passing any parameters to your ui-sref? Your state main.index & main.gallery still expect you to give it.
Working plunkr: http://plnkr.co/edit/uaII8LkMKoAHnacrLybQ?p=preview (Launch it seperate window to see url changes)
HTML:
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#*" data-semver="1.2.14" src="http://code.angularjs.org/1.2.14/angular.js"></script>
<script data-require="ui-router#*" data-semver="0.2.8" src="http://angular-ui.github.io/ui-router/release/angular-ui-router.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h1>Hello Plunker!</h1>
</body>
<a ui-sref='main.index({lng:5})'>Home</a> <br/>
<a ui-sref='main.gallery({lng:5})'>Gallery</a>
</html>
JS:
// Code goes here
angular.module("app", ["ui.router"]).config(["$stateProvider",
function($stateProvider) {
$stateProvider
.state('main', {
url: '/:lng',
abstract: true,
template: '<div ui-view></div>'
})
.state('main.index', {
url: '/',
template: '<span>Index</span>'
})
.state('main.gallery', {
url: '/gallery',
template: '<span>Gallery</span>',
})
}
]);

Resources