ui-router automatically routes to parent controller - angularjs

I have an angular app with ui router with a nested view (in the config method):
$stateProvider
.state('home', {
url: '/home',
views: {
'mainView' : {
templateUrl: 'templates/home.html',
controller: 'HomeController'
}
},
authenticate: true
})
.state('home.cargaDePadrones', {
url: '/cargaDePadrones',
views: {
'contentView' : {
templateUrl: 'templates/cargaDePadrones.html',
controller: 'CargaDePadronesController'
}
},
authenticate: true
})
In the home view I have this:
<md-content layout="row" layout-fill>
<md-content ng-show="showTreeMenu" class="TextoInstitucional menuCell" flex="20">
<treecontrol class="tree-classic" tree-model="treeData" options="treeOptions"
on-selection="showSelected(node)" expanded-nodes="expandedNodes">
{{node.name}}
</treecontrol>
</md-content>
<div style="background-color: #CECECE; width: 9px;" layout="column" layout-align="center center">
<a flex href="#" ng-show="showTreeMenu" ng-click="toggleMenu()">
<img style="border: 0 none;" src="images/middle_toggle_left.gif" />
</a>
<a flex href="#" ng-show="!showTreeMenu" ng-click="$parent.toggleMenu()">
<img style="border: 0 none;" src="images/middle_toggle_right.gif" />
</a>
</div>
<md-content class="TextoGrande contentCell" style="padding-left: 10px;" ui-view="contentView" ng-cloak flex>
</md-content>
</md-content>
and in the home controller I've got this:
$scope.showTreeMenu = true;
$scope.toggleMenu = function() {
$scope.showTreeMenu = !$scope.showTreeMenu;
};
The idea is that whenever the user hits the anchor, a part of the page hides (the menu) to give it more space to work and when it hits the other anchor it bring the menu back.
The problem is that whenever I hit the anchor that is visible in the home view (executing the toggleMenu scope method) the content in the nested view (named 'contentView') dissapears. Looking at the browser path, it automatically routes from /home/cargaDeParones to /home (routing from the child state to the parent state). I'm assuming that this is happening because the toggleMenu method is defined in the Home controller, but I don't know how to prevent this behaviour.
How can I expose a parent's scope method without routing back to it??
Thanks :)

Anchor tags href value is '#'
, that is the reason it is taking to the home page. Please change the anchor tags href tag to :
<a flex href="JavaScript:void(0)" ng-show="showTreeMenu" ng-click="toggleMenu()">
<img style="border: 0 none;" src="images/middle_toggle_left.gif" />
</a>

Related

How to use ui-view on RenderBody() in angularjs

I have this mark-up html with the #RenderBody():
<div layout="column" class="relative" layout-fill role="main">
<md-toolbar class="md-hue-2">
<div class="md-toolbar-tools">
<md-button class="md-icon-button" aria-label="Settings" ng-disabled="true">
<md-icon md-svg-icon="navigation:menu"></md-icon>
</md-button>
<md-button ui-sref="dashboard">Dashboard</md-button>
<md-button ui-sref="home">Home</md-button>
</div>
</md-toolbar>
<md-content layout-fill md-padding>
<div id="main-content" ui-view="">
#RenderBody()
</div>
</md-content>
</div>
and the js here:
app.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/Home/Index');
$stateProvider
.state('home', {
url: '/Home/Index',
templateUrl: '/Home/Index' // corresponds to an MVC partial route
})
.state('dashboard', {
url: 'Home/Dashboard',
templateUrl: '/Home/Dashboard' // corresponds to an MVC partial route
})
});
The result is its own view inside a view. I cant figure it out.
Here is the output:
I see this problem in few of my apps.
Your layout is loading twice.
All you need to do is "make your layout null" while rendering from uiroute as below.
Add this on top of your Index.cshtml page
#{
Layout = null;
}
Or load ui-view out side the content div
<md-content layout-fill md-padding>
<div id="main-content">
#RenderBody()
</div>
</md-content>
<ui-view></ui-view>
Or you could use viewContentLoaded that is triggered after DOM is loaded when using uirouter in angular as below:
//trigger events after DOM content load
$scope.$watch("$viewContentLoaded",
function() {
if (document.getElementsByTagName("header").length === 2) {
document.getElementsByTagName("header")[1].remove();
}
if (document.getElementsByTagName("footer").length === 2) {
document.getElementsByTagName("footer")[1].remove();
}
});

reload controller when child state is changed - Angular UI Router

I'm new to Angular UI Router and am trying to create an application with nested views.
I've an index.html which hosts the 'header' state and the 'content' state. Within the content state, I have two nav bars representing a Global view and a Sub view. The Global View should open by default when the user opens the application.
However, at present, whenever I run the application, both Global and Sub view controllers are getting executed together(both views are getting loaded together).
What I wish instead is that only Global controller should get executed at first and then when the user clicks on Sub view, its controller should get executed. Following this, whenever the user switches between both the views, the controllers should reload.
I have been reading through Google and here but wasn't able to find the required solution. Please let me know if this is possible using ui-router. Thanks.
index.html
<html>
<body>
<div class="fluid-container">
<div ui-view="header"></div>
<div ui-view="content"></div>
</div>
</body>
</html>
content.html
<div class="row" style="background-color: #F9F9F8">
<div class="col-md-3"></div>
<div class="col-md-6">
<ul class="nav nav-pills nav-justified">
<li class="active"><a data-toggle="pill" href="#globalView">Global</a></li>
<li><a data-toggle="pill" href="#subView">Sub View</a></li>
</ul>
</div>
<div class="col-md-3"></div>
</div>
<div class="row">
<br>
<hr></hr>
<div class="tab-content">
<div id="globalView" class="tab-pane fade in active" ui-view="globalView"></div>
<div id="subAccountView" class="tab-pane fade" ui-view="subView"></div>
</div>
</div>
app.js
$urlRouterProvider.otherwise("/firstPage");
$urlRouterProvider.when('', '/firstPage');
$stateProvider
.state('home', {
url: '',
views: {
/** Find the views named in index.html and inject the named views**/
'header': {
templateUrl: 'views/header.html',
controller: 'headerController',
controllerAs: 'headerCtrl'
},
'content': {
templateUrl: 'views/content.html',
controller: 'contentController',
controllerAs: 'contentCtrl',
}
}
})
.state('home.summary', {
url: '/firstPage',
views: {
'globalView': {
templateUrl: "views/globalViewPage.html",
controller: "globalViewController",
controllerAs: "globalViewCtrl"
},
'subView': {
templateUrl: "views/subView.html",
controller: "subViewController",
controllerAs: "subViewCtrl"
}
}
});
I found the solution to my query by going through the tutorial provided by Weedoze in the comments. Below are the updated files.
index.html remains the same as above.
content.html
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-6">
<ul class="nav nav-pills nav-justified">
<li class="active"><a ui-sref=".globalView">Global</a></li>
<li><a ui-sref=".subView">Sub View</a></li>
</ul>
</div>
<div class="col-md-3"></div>
</div>
<div class="row">
<br>
<hr></hr>
<div class="tab-content">
<div class="tab-pane fade in active" ui-view></div>
</div>
</div>
A point to add here is that I was earlier having data-toggle="pill" in my anchor tag which was causing issues in navigating between the two child views. After digging further, I found that if this toggle is removed, the navigation works smoothly.
app.js
$urlRouterProvider.otherwise("/globalView");
$urlRouterProvider.when('', '/globalView');
$stateProvider
.state('home', {
url: '',
views: {
/** Find the views named in index.html and inject the named views**/
'header': {
templateUrl: 'views/header.html',
controller: 'headerController',
controllerAs: 'headerCtrl'
},
'content': {
templateUrl: 'views/content.html',
controller: 'contentController',
controllerAs: 'contentCtrl',
}
}
})
.state('home.globalView', {
templateUrl: "views/globalViewPage.html",
controller: "globalViewController",
controllerAs: "globalViewCtrl",
url: '/globalView'
})
.state('home.subView', {
templateUrl: "views/subView.html",
controller: "subViewController",
controllerAs: "subViewCtrl",
url: '/subView'
});
This code lets me switch between the two child views and whenever I toggle between the views, the controllers get reloaded.

Angular Pages with QueryString

I want to create an event page and event detail page in angular. I created my states like this in my app.js
.state('app.event', {
url: "/event",
views: {
'menuContent': {
templateUrl: "views/event.html",
controller: "eventController"
}
}
})
.state('app.eventDetail', {
url: "/eventDetail/:eventId",
views: {
'menuContent': {
templateUrl: "views/eventDetail.html",
controller: "eventDetailController"
}
}
})
I m getting my events in my views/event.html page like this
<div class="list" ng-controller="EventController">
<div class="item item-avatar item-left" ng-repeat="EventName in Events track by $index">
<p>{{ EventName }}</p>
<p>{{ EventId }}</p>
</div>
</div>
My question is how can i redirect my Event page to EventDetail page with event Id ?
And my other question is how can i get that id in my EventDetail page ?
You could use ui-sref like this:
<div class="list" ng-controller="EventController">
<div class="item item-avatar item-left" ng-repeat="EventName in Events track by $index">
<a ui-sref="app.eventDetail({eventId: EventId})">{{ EventName }}</a>
</div>
</div>
Clicking the link for an event should redirect to the details page and then to get the parameter from the url you would use the $stateParams service:
app.controller('eventDetailController', function($scope, $stateParams) {
$stateParams.eventId;
});
I suspect that there may be a few errors in your code. So if you experience any issues with the above, please update your question with the code for both controllers and I'll try to update my answer to account for them.

How to use ng-class on a top level container when using nested views

I am trying to import a toggleable sidebar and trying to use nested views so that I can dynamically change content of each section individually.
My app has 3 main components
1) a sidebar
2) a header
3) a content area
The problem I have is that in the original project everything is inside a single controller and there is an ng-class that toggles the sidebar which is can be toggled on clicking, but I am unable to reproduce it in the my application.
Here is what my index.html code looks like at the moment
<div id="page-wrapper" ng-class="{'open': toggle}" ng-cloak>
<div id="sidebar-wrapper" ui-view="sidebar">
</div>
<div id="content-wrapper">
<div class="page-content">
<!-- Header Bar -->
<div class="row header" ui-view="header">
</div>
<!-- Header Bar -->
<div ui-view="content" ></div>
</div>
</div>
</div>
And my route config.
.state('home', {
url: '/',
views: {
'content': {
templateUrl: 'home.html',
controller: 'HomeCtrl as home'
},
'sidebar': {
controller: 'SidebarCtrl as sidebar',
templateUrl: 'sidebar.html'
},
'header': {
controller: 'HeaderCtrl as header',
templateUrl: 'header.html'
}
}
});
I am confused on how I can toggle the sidebar using ng-class as I cannot place it inside any other template for it to work.
My previous comments as an answer:
in your html:
<div id="page-wrapper" ng-controller="myctrl" ng-class="{'open': toggle}" ng-cloak>
...
</div>
in your script file:
.controller('myctrl',[ '$scope', function($scope){
$scope.toggle = true; // open initially
}]);

Nested ui-view in angularjs

I am trying to do something here but it does not work, I have the following view:
<header ui-view="header">
</header>
and here is my app.js file:
.state('root', {
url: '',
views: {
'header': {
templateUrl: '/js/app/partials/layout/header.html',
controller: 'HeaderController'
},
'slider': {
templateUrl: '/js/app/partials/slider.html'
},
'container#': {
templateUrl: '/js/app/partials/home.html',
controller: 'HomeController'
},
'sidebar': {
templateUrl: '/js/app/partials/layout/sidebar.html',
controller: 'SideBarController'
},
'footer':{
templateUrl: '/js/app/partials/layout/footer.html'
}
}
})
Now this particular view:
'slider': {
templateUrl: '/js/app/partials/slider.html'
},
is not in my index.html file but rather within my /partial/layout/header.html file. Now the header template is being loaded into the header view, but the slider view does not show.
This is my header.html partial with my slider view inside:
<div class="container-fluid">
<div class="col-md-12">
<a href="#" class="pull-left">
<img src="images/logo.png" alt="Your Happy Family" class="img-responsive">
</a>
<!-- Begin Top Navigation -->
<div class="menu_block">
<nav class="horizontal-nav full-width horizontalNav-notprocessed">
<ul class="sf-menu">
<li class="home"><a ui-sref="root.home">home</a></li>
<li class="tickets">
tickets
<ul>
<li class="bus">Bus</li>
<li class="airline">Local Airline</li>
<li class="events">Events</li>
</ul>
<div class="clear"></div>
</li>
<li class="partners"><a ui-sref="root.partners">partners</a></li>
<li class="contact"><a ui-sref="root.contact">contact us</a></li>
</ul>
</nav>
<div class="clear"></div>
</div>
<!-- End Top Navigation -->
<div class="clear"></div>
<!-- Slider View -->
<div ui-view="slider">
</div>
<div class="clear"></div>
</div>
</div>
I am doing this for a reason, I need my slider view to appear within the header section.
What you usually need is relative pathing for multiple nested views. If you scroll down to the bottom of the docs (https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views) they explain what the syntax of relative pathing does.
This might be what you're looking for but I always get a little tripped up without actually testing the pathing and without a plunker...
'slider#root': {
templateUrl: '/js/app/partials/slider.html'
},

Resources