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) {}
}
}
});
});
Related
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>
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>
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
I would to make something like this:
.state('tabs.order', {
url: "/order/:orderId",
views: {
'orders-tab': {
templateUrl: "templates/orderDetail.html",
controller: 'OrderDetailController'
},
'orders-all-tab': {
templateUrl: "templates/orderDetail.html",
controller: 'OrderDetailController'
}
}
})
then in my view i would to put a conditional ui-sref in which i can choose the tab to be addressed; something like this:
ui-sref="tabs.order({orderId:order.ID}, <orders-tab or orders-all-tab?>)"
would this be possible?
Thanks
Well, I don't think there is any way yet to specify the view in ui-sref, but here is a starting point which I hope it will help you..
Firstly, the routes:
app.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise("/order/all-orders");
$stateProvider
.state("order", { abtract: true, url:"/order", templateUrl:"main.html" })
.state("order.orderTab", { url: "/order-details", templateUrl: "orderDetails.html" })
.state("order.orderAllTab", { url: "/all-orders", templateUrl: "allOrders.html" });
});
Then, define your main page (Orders and Order Details) [main.html]
<div ng-controller="mainController">
<tabset>
<tab
ng-repeat="t in tabs"
heading="{{t.heading}}"
select="go(t.route)"
active="t.active">
</tab>
</tabset>
<h2>View:</h2>
<div ui-view></div>
</div>
And the page controller to specify the tab data:
app.controller("mainController", function($rootScope, $scope, $state) {
$scope.go = function(route){
$state.go(route);
};
$scope.active = function(route){
return $state.is(route);
};
$scope.tabs = [
{ heading: "Order", route:"order.orderTab", active:true },
{ heading: "All Orders", route:"order.orderAllTab", active:false },
];
$scope.$on("$stateChangeSuccess", function() {
$scope.tabs.forEach(function(tab) {
tab.active = $scope.active(tab.route);
});
});
});
All you have to do next is to include the orderID.
Here is a demo
I'm using AngularJS translate, and If I use it as says the tutorial from pascalprecht my angular app fail and it doesn't show anything (it doesn't load partial views), so I decided to use angular-translate-partial-loader
I have one app menu, and I have a MenuCtrl to display options, I want to translate this menu
Here Is my code
angular.module('myapp'['ngAnimate','ngAria','ngCookies','ngMessages','ngResource','ngRoute','ngSanitize', 'ngTouch', 'pascalprecht.translate'])
.value('language', 'bra')
.run(function ($rootScope, $translate)
{
$rootScope.$on('$translatePartialLoaderStructureChanged', function ()
{
$translate.refresh();
}
);
})
.config(function($translateProvider, $translatePartialLoaderProvider) {
$translateProvider.useLoader('$translatePartialLoader', {
urlTemplate: 'translations/{lang}/{part}.json'
});
$translateProvider.preferredLanguage("bra");
})
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'AboutCtrl'
})
.otherwise({
redirectTo: '/'
});
});
angular.module('myapp')
.controller('MenuCtrl', function ($scope, $translatePartialLoader) {
$translatePartialLoader.addPart('menu');
$scope.lItems = [
{
title: "HOME",
class:'active',
href:'/',
visible: true
},
{
title: "CLASSROOMS",
class:'',
href:'#',
visible: true
},
{
title: "EXPENSES",
class:'',
href:'#',
visible: true
},
{
title: "EARNINGS",
class:'',
href:'#',
visible: true
},
{
title: "STUDENTS",
class:'',
href:'#',
visible: true
}
];
});
In index.html
<div id="navbar" class="navbar-collapse collapse" ng-controller="MenuCtrl">
<ul class="nav navbar-nav" ng-repeat="lItem in lItems">
<li class="{{lItem.class}}">{{lItem.title | translate}}</li>
</ul>
</div>
Can you help me?
Thanks!
Finally I found the solution.
The trouble was that the menu is out of ng-view block, and when the app loads doesn't refresh the correct html part.
By adding this $translatePartialLoaderProvider.addPart('menu');
.config(function ($translateProvider, $translatePartialLoaderProvider) {
$translatePartialLoaderProvider.addPart('menu');
$translateProvider.useLoader('$translatePartialLoader', {
urlTemplate: 'translations/{lang}/{part}.json'
});
$translateProvider.preferredLanguage('bra');
....
When the application loads the menu part is also loaded.