ui.router/angular - load secondary view with click without replacing main view - angularjs

I am very new to ui.router, I just picked it up this morning! But I have a situation where I need to load a first view, and then content within it can be clicked which can be loaded into a second view without replacing the content in the first... I'm having a hard time figuring out how to do this kind of behavior, though... It seems like it should be simple.
Is such behavior possible?
HTML
<div class="col-lg-12">
<div class="col-lg-3"><!-- menu --></div>
<div class="col-lg-9">
<div ui-view="main"></div>
<div ui-view="lookup"></div>
</div>
</div>
Routing
$stateProvider
.state('pages', {
url: '/pages/{page:.*}',
views: {
'main': {
templateUrl: function(stateParams) {
return String.format('home/{0}/{1}.html', './pages', stateParams.page);
}
}
}
})
.state('lookup', {
url: '/lookup/{page:.*}',
views: {
'lookup': {
templateUrl: function (stateParams) {
return String.format('home/lookup/{0}.html', stateParams.page);
}
}
}
})

You should use nested states:
$stateProvider
.state('pages', {
url: '/pages/{page:.*}',
views: {
'main': {
// Showing off how you could return a promise from templateProvider
templateUrl: function(stateParams) {
return String.format('home/{0}/{1}.html', './pages', stateParams.page);
}
}
}
})
.state('pages.lookup', {
url: 'lookup',
views: {
'lookup': {
// Showing off how you could return a promise from templateProvider
templateUrl: function (stateParams) {
return String.format('home/lookup/{0}.html', stateParams.page);
}
}
}
})
url for lookup is now pages/{page}/lookup
And your ui-view=lookup should may be located inside the views that load inside main.
It should work also with your current html set up.

I think you should use a directive for your second view. It will allow you to have two templates in the same view.
params_you_want_to_pass allows you to get some infos in your 2nd template.
I hope this is clear enough.
HTML
<div class="col-lg-12">
<div class="col-lg-3"><!-- menu --></div>
<div class="col-lg-9">
<div ui-view="main"></div>
<lookup-directive info="params_you_want_to_pass"></lookup-directive>
</div>
</div>
ROUTING
$stateProvider
.state('pages', {
url: '/pages/{page:.*}',
views: {
'main': {
templateUrl: function(stateParams) {
return String.format('home/{0}/{1}.html', './pages', stateParams.page);
}
}
}
})
DIRECTIVE
angular.module('yourModule').directive('lookupDirective', lookupDirective);
lookupDirective.$inject = [];
function lookupDirective() {
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl: 'yourtemplate.html'
};
});

Yes,you can implement multiple view at same template.
<body ng-app="main">
<script type="text/javascript">
angular.module('main', ['ui.router'])
.config(['$locationProvider', '$stateProvider', function ($locationProvider, $stateProvider) {
$stateProvider
.state('home', {
url: '/',
views: {
'header': {
templateUrl: '/app/header.html'
},
'content': {
templateUrl: '/app/content.html'
}
}
});
}]);
</script>
<a ui-sref="home">home</a>
<div ui-view="header">header</div>
<div ui-view="content">content</div>
<div ui-view="bottom">footer</div>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.js">
</body>

Related

How can I make an angular-ui-router template accept two views?

I am trying to understand how to use ui-router views. Here's what I have so far:
var rootSubjectsSubjectAdminWordsWord = {
name: 'r.s.s.a.w.w',
template: '<div ui-view ></div>',
url: '/:wordId',
};
var rootSubjectsSubjectAdminWordsWordDelete = {
name: 'r.s.s.a.w.w.delete',
templateProvider: ['$templateCache', ($templateCache) => {
return $templateCache.get('/app/admin/word/word.html');
}],
url: '/delete',
};
/app/admin/word/word.html
<div>
<ng-include src="'/app/admin/word/wordData.html'"></ng-include>
<ng-include src="'/app/admin/word/wordForms.html'"></ng-include>
</div>
What I would like to do is to remove the need for having word.html.
Is there a way that could make the template '<div ui-view ></div>' accept the two HTML
files by somehow naming the views?
Here is per UI Router Docs. Basically inside where the views object is defined is where you'll name the view and point it to that view(see #1). After that router will take care of the rest.
$stateProvider
.state('report', {
views: {
//(#1)--here is the named router matching in the html.
'filters': {
templateUrl: 'report-filters.html',
controller: function($scope) {...controller stuff just
for filters view...
}
},
'tabledata': {
templateUrl: 'report-table.html',
controller: function($scope) {...controller stuff just
for tabledata view...
}
},
'graph': {
templateUrl: 'report-graph.html',
controller: function($scope) {...controller stuff just
for graph view...
}
}
}
});
<body>
<div ui-view="filters"></div>
<div ui-view="tabledata"></div>
<div ui-view="graph"></div>
</body>

UI-Router is not compiling deep levels of templates

I'm having problem building a nested template using UI-Router. It seems it is unable to load or compile templates in the third level (or deeper).
I've created a plunker with a simplified example, this is the code:
angular.module('plunker', ["ui.router"])
.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise("/");
$locationProvider.html5Mode(false).hashPrefix('!');
$stateProvider
.state('home', {
url: "/",
controller: 'MainCtrl',
views: {
'main': {
template: 'Main content'
},
'secondary': {
templateUrl: "view2.html",
views: {
'hot': {
template: 'hot content'
},
'cold': {
template: 'cold content'
}
}
}
}
})
})
.controller('MainCtrl', function($scope) {
$scope.sayHello = 'Hello';
})
where the html is
<body class='container' ng-controller='MainCtrl'>
<h2>Nested template proof</h2>
<div ui-view>
<p>{{sayHello}}</p>
<div ui-view="main"></div>
<div ui-view="secondary"></div>
</div>
</body>
and view2.html is
<div>
<p>view2 loaded</p>
<div ui-view="hot"></div>
<div ui-view="cold"></div>
</div>
can any one tell me what I'm doing wrong? the 'hot' and 'cold' sections are not being compiled.
There is an updated and working example
The nesting of views inside one state must be done differently. We would need absolute naming - so this would be the syntax:
.state('home', {
url: "/",
controller: 'MainCtrl',
views: {
'main': {
template: 'Main content'
},
'secondary': {
templateUrl: "view2.html",
//views: {}
},
'hot#home': {
template: 'hot content'
},
'cold#home': {
template: 'cold content'
}
}
})
This is the absolute view naming, discussed e.g. here:
Angular-UI Router: Nested Views Not Working
Angular UI Router - Nested States with multiple layouts
Angularjs ui-router not reaching child controller

UI Router is not injecting resolved value into views at the same level

I have the following state configuration:
$stateProvider
.state('customer', {
url: '/customers',
templateUrl: 'app/components/customer/templates/main.tpl.html',
views: {
'list': {
templateUrl: 'app/components/customer/templates/list.tpl.html',
controller: 'ListCtrl as ctrl'
}
},
resolve: {
customerList: function ($stateParams, CustomerResource) {
console.log('trying to resolve');
var list = CustomerResource.list($stateParams);
return list;
}
}
})
Here is the main template:
<div class="container">
<div class="row">
<div ui-view="list" class="col-lg-4"/>
<div ui-view="details" class="col-lg-8"/>
</div>
</div>
I see on the console that angular is trying to resolve the dependency. But this dependency is never injected into the controller under views. What am I doing wrong here?
P.S. When I move views to some child state like customer.test the resolved dependency is injected as expected:
.state('customer.test', {
url: '/test',
views: {
'list#customer': {
templateUrl: 'app/components/customer/templates/list.tpl.html',
controller: 'ListCtrl as ctrl'
}
}
})
There is a working plunker
The problem here is not with resolve, but with the injection of the main template. This should be the state definition:
.state('customer', {
url: '/customers',
//templateUrl: 'app/components/customer/templates/main.tpl.html',
views: {
'': {
templateUrl: 'app/components/customer/templates/main.tpl.html'
},
'list#customer': {
templateUrl: 'app/components/customer/templates/list.tpl.html',
controller: 'ListCtrl as ctrl'
}
},
resolve: {
customerList: function ($stateParams, CustomerResource) {
console.log('trying to resolve');
var list = CustomerResource.list($stateParams);
return list;
}
}
})
so, with these in play:
.controller('ListCtrl', ['$scope', 'customerList', function ($scope, customerList) {
$scope.resolved = customerList
}])
.factory('CustomerResource', function(){
return {
list: function(params){return "Hello world"}
}
})
we can see that list view like this:
<div>
<h3>list view</h3>
{{resolved}}
</div>
will show Hello world
Check it here in action

Angular UI router - not calling the views

I'm trying out Angular UI router for the first time. I'm having issues where the views are not being called accordingly. Check the plunker: http://plnkr.co/edit/cBfR6u2BPJvKN16vi6hG?p=preview
Does anything stand out on the router?
deviceApp.config(function ($stateProvider) {
$stateProvider
.state('devices', {
views: {
'environment': {
template: 'Look I am a view!',
controller: 'DataCtrl'
},
'devicedetail': {
templateUrl: 'index.html',
controller: 'DeviceCtrl'
}
}
}
)}
);
perhaps the absence of a "url" definition in your view object?
'environment': {
url: '/environment',
template: 'Look I am a view!',
controller: 'DataCtrl'
},
You can do something like that :
config.js
.config(function ($urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$urlRouterProvider.when('', '/');
})
app.js
state('main', {
url: '/',
views: {
'': { templateUrl: 'app/main/main.html', controller: 'MainCtrl'},
'navbar': { templateUrl: 'components/navigation/navbar/navbar.html'},
}
index.html
<body>
<header ui-view="navbar" class="header"></header>
<section class="content">
<div ui-view></div>
</section>
</body>

Show hide menu in header template angularjs

Trying to show hide menus based on user login using a custom directive. It all works fine in the views templates but in header it does not work [header is a different template]. It works fine on page refresh though.
header.html
<div id="header" class="navbar">
<a class="navbar-brand" href="#">My APP</a>
<ul class="nav nav-pills">
<li has-logged="!in">Sign Up</li>
<li has-logged="in">Home</li>
</ul>
</div>
has-logged directive
angular.module('myApp')
.directive('hasLogged', function(CookieService) {
return {
link: function(scope, element, attrs) {
if(!_.isString(attrs.hasLogged))
throw "hasLogged value must be a string";
var value = attrs.hasLogged.trim();
var notLoggedFlag = value[0] === '!';
if(notLoggedFlag) {
value = value.slice(1).trim();
}
function toggleVisibilityBasedOnLogin() {
var logged = CookieService.getLoginStatus();
if(logged && !notLoggedFlag || !logged && notLoggedFlag)
element.show();
else
element.hide();
}
toggleVisibilityBasedOnLogin();
}
};
});
app.js config
var myApp = angular.module('myApp',['ngRoute','ngCookies']);
myApp.config(function ($routeProvider,$httpProvider) {
$routeProvider
.when('/', {
templateUrl: 'app/module/public/index.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html'
})
.when('/login', {
templateUrl: 'app/module/login/login.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html'
})
.when('/home', {
templateUrl: 'app/module/home/home.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html'
})
.when('/register', {
templateUrl: 'app/module/register/register.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html'
})
.otherwise({redirectTo: '/'});
});
Code to add header and footer on app run
// Adds Header and Footer on route change success
$rootScope.$on('$routeChangeSuccess', function (ev, current, prev) {
$rootScope.flexyLayout = function(partialName) { return current.$$route[partialName] };
});
I tried this POST solution but still the same effect.
How do i change the menus without page refresh??
You may look into ui-router. It supports multiple and nested views.
Demo Fiddle
Click on First and Second to navigate between both states.
Here is the basic setup
First you need the views:
<div ui-view="header"></div>
<div ui-view="content"></div>
<div ui-view="footer"></div>
Then some sort of navigation to switch between ui states:
<ul>
<li>First</li>
<li>Second</li>
</ul>
Here is a basic state configuration:
myApp.config(function($stateProvider, $urlRouterProvider) {
// default route
$urlRouterProvider.otherwise("/first");
// ui router states
$stateProvider
.state('first', {
url: "/first",
views: {
header: {
template: '<h1>First header</h1>',
controller: function($scope) {}
},
content: {
template: '<p>First content</>',
controller: function($scope) {}
},
footer: {
template: '<div>First footer</div>',
controller: function($scope) {}
}
}
})
.state('second', {
url: "/second",
views: {
header: {
template: '<h1>Second header</h1>',
controller: function($scope) {}
},
content: {
template: '<p>Second content</>',
controller: function($scope) {}
},
footer: {
template: '<div>Second footer</div>',
controller: function($scope) {}
}
}
});
});

Resources