Is it possible to have multiple views that each contain nested states in Angular UI-Router?
For example, in the following could view1#main contain nested states? Lets say Main contains two page sections and view1#main contains a list that dynamically populates data in a view which I want to nest.
HTML:
<div class="main-container">
<div ui-view="view1">
<!--this is inside the template for view1-->
<div class="myList">
<!--ng-repeat each with a click setting the nested view-->
</div>
<div ui-view>
<!--this would be another template that -->
<!--changes based on the click from the ng-repeat -->
</div>
</div>
<div ui-view="view2"></div>
</div>
JS:
.state('main', {
url: '/main',
controller: 'MainCtrl',
views: {
'': {
templateUrl: 'views/main.html'
},
'view1#main': {
templateUrl: 'views/view1.html',
controller: 'MainCtrl'
//nested states in here
},
'view2#main': {
templateUrl: 'views/view2.html',
controller: 'SecondCtrl'
}
}
}
Related
There is a following code snippet:
<my-header></my-header>
<div ng-switch="$ctrl.page">
<div ng-switch-when="1"><component1></component1></div>
<div ng-switch-when="2"><component2></component2></div>
<div ng-switch-when="3"><component3></component3></div>
</div>
I want that component myHeader would be constructed before ngSwitch directive takes an action. Now component1 is constructed before myHeader.
Routing represents following code:
$stateProvider
.state({
name: 'myApp',
url: '/',
component: 'loader',
})
.state({
name: 'myApp.pages',
url: 'pages/{id:int}',
component: 'loader'
});
$urlRouterProvider.otherwise('/pages/1');
You can achieve this by exposing your controller in the link function inside the myHeader directive.
With that, you can easily add variables to the controller and control the visibility of the ng-switch div with ng-if. Check the code snippet down here.
Ah, don't forget to add ng-cloak to the div containing the ng-switch directive.
angular
.module('app', [])
.controller('TestController', function($scope) {
this.page = 1;
})
.directive('myHeader', function () {
return {
link: function (scope, element, attrs) {
// With element.controller() we can reach the controller that is wrapping our directive. Then, we can simply set the headerIsLoaded variable to true.
element.controller().headerIsLoaded = true;
},
scope: true,
templateUrl: 'my-header.html'
}
});
<div ng-controller="TestController as ctrl">
<my-header></my-header>
<!-- Add a visual feedback so user knows the components are being loaded -->
<div ng-if="!ctrl.headerIsLoaded">
Loading...
</div>
<!-- If ctrl.headerIsLoaded is set to true, the ng-switch will appear -->
<div ng-if="ctrl.headerIsLoaded"
ng-cloak>
<div ng-switch="ctrl.page">
<div ng-switch-when="1">
Page 1
</div>
<div ng-switch-when="2">
Page 2
</div>
<div ng-switch-when="3">
Page 3
</div>
</div>
</div>
</div>
In my application, I want the nested view list-patents.htm to load when the index page loads.
My main nav is on my index.htm, with two nav items transactions and patents.
If you were to click on patents, a further two sub-menu items would load: list patents and add patents. Here you can then navigate to list-patents.htm which I want to act as the landing view.
I have tried two methods:
$urlRouterProvider.otherwise(""); which I couldn't get to work.
This method (which is in my script) loaded the nested view, but failed to load its parent nest view, the nav menu.
.state("index",
{
url: "",
templateUrl: "templates/list-patents.htm",
})
I want to keep the navigation in its own view, as I don't see the point of creating duplicate code.
Any ideas how on page load, it loads the patent-nav.htm and it's nested view list-patents.htm? Any help would be greatly appreciated
app.js
var app = angular.module('myApp', ['ngRoute', 'angularMoment', 'ui.router']);
app.config(['$stateProvider', '$locationProvider', '$urlRouterProvider', function($stateProvider, $locationProvider, $urlRouterProvider ) {
$stateProvider
.state("index",
{
url: "",
templateUrl: "templates/list-patents.htm",
})
.state("patents", {
url: "/patents",
templateUrl: "templates/patent-nav.htm",
controller: "patentCtrl"
})
.state("patents.list", {
url: "/list-patents",
templateUrl: "templates/list-patents.htm",
controller: "patentCtrl"
})
.state("patents.add", {
url: "/add-patents",
templateUrl: "templates/add-patent.htm",
controller: "patentCtrl"
})
Views
index
<main class="container">
<nav>
<ul>
<a ui-sref="patents">Patents</a>
<a ui-sref="transactions">Transactions</a>
</ul>
</nav>
<section ui-view>
</section>
</main>
patent-nav
<nav>
<ul>
<li><a ui-sref="patents.list">List patents</a></li>
<li><a ui-sref="patents.add">Add patent</a></li>
</ul>
</nav>
<div ui-view></div>
list-patents
<div>
//just a load of content
</div>
Do this
$urlRouterProvider
.when('', '/parents/list-patents')
.when('/', '/parents/list-patents')
.otherwise('/parents/list-patents');
Here is my current code:
let views = { '': 'app/content.html' };
.state('auto', {
url: '/automated',
redirectToChild: {
state: 'auto.index'
},
views: view
})
.state('auto.index', {
url :'',
templateUrl: '/app/automated/automated.html'
})
.state('auto.visit', {
url: '/visit',
views: {
'': {templateUrl: '/app/automated/visit.html'}
}
})
.state('auto.visit.create', {
url: '/create',
views: {
'': {templateUrl: '/app/automated/_form.html'}
}
})
Here is my html:
// index.html
<ui-view></ui-view>
// content.html
<div class="wrapper">
<div class="container">
<ui-view> </ui-view>
</div>
</div>
// visit.html
<h5>Visit Page</h5>
// form.html
<h5>Visit Form</h5>
Here is the problem: Everything works fine with this code but when I visit auto.visit.create state it show visit.html instead of '_form.html'.
How can I replace visit.html content without changing current routes?
First Tried:
I change my auto.visit.create state to auto.visit-create. This way is working perfectly but I want create is child of auto.visit
Second Tried:
I put new <ui-view></ui-view> on visit.html but when I go to create page it will show visit.html content.
I've tried to follow this http://angular-ui.github.io/ui-router/sample/#/ code. But it's not working.
How are you visiting the nested views? The notation you want works perfectly.
you should include the <ui-view></ui-view>in all parent pages.
See the plunker I created as an example; be sure to open the preview in using the separate page view so that you can see the urls that are being generated
UPDATE
I misunderstood your question, I apologize. Below is the updated code and plunker that achieves what you desire. I don't believe there is any way to accomplish this purely through angular routing so I used jquery to do it. only changes are on first layer and second layer
http://plnkr.co/edit/cxQpu6zS7fifnb0sGvGf?p=preview
Angular Code
(function() {
angular.module("myApp", ["ui.router"]);
angular.module("myApp")
.config(["$stateProvider", "$urlRouterProvider", function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state("home", {
url: "/",
templateUrl: "blank.html"
})
.state("first", {
url: "/first",
templateUrl: "firstLayerPage.html"
})
.state("first.second", {
url: "/second",
templateUrl: "secondLayerPage.html"
})
.state("first.second.third1", {
url: "/third_Page1",
templateUrl: "thirdLayerPage1.html"
})
.state("first.second.third2", {
url: "/third_Page2",
templateUrl: "thirdLayerPage2.html"
})
}]); // end of config
})(); //end of enclosure
Index
<body ng-app="myApp">
<ul>
<li><a ui-sref="home">home</a></li>
<li><a ui-sref="first">First Layer</a> </li>
</ul>
<h1>Home Page</h1>
<hr>
<ui-view></ui-view>
</body>
first layer
<p>this is the first layer of pages.</p>
<ul>
<li><a id="showSecondLayer" ui-sref="first.second">Second Layer</a> </li>
</ul>
<hr>
<ui-view></ui-view>
<script type="text/javascript">
$(document).ready(function(){
$("#showSecondLayer").click(function(){
$("#secondLayer").show();
});
});
</script>
second layer
<div id="secondLayer">
<p>This is the second layer</p>
<ul>
<li><a id="thirdP1" ui-sref="first.second.third1">Third Layer Page 1</a> </li>
<li><a id="thirdP2" ui-sref="first.second.third2">Third Layer Page 2</a></li>
</ul>
<hr>
</div>
<ui-view></ui-view>
<script type="text/javascript">
$(document).ready(function(){
$("#thirdP1").click(function(){
$("#secondLayer").hide();
});
$("#thirdP2").click(function(){
$("#secondLayer").hide();
});
});
</script>
third layer p1
<p>This is page one of the third level of children</p>
<hr>
third layer p2
<p>This is page two of the third level of children</p>
<hr>
Here is the highlevel skeleton of my Angular SPA. My application is about college degree offerings. In that engineering page has a separate left nav which is currently built on ng-switch which i want to convert as route. How do i do that just using angular's native routing angular-route.js?
**app.js**
(function(){
var app=angular.module("myCollege",['ngRoute']);
app.config(['$routeProvider','$locationProvider',
function($routeProvider,$locationProvider) {
$routeProvider
.when('/', {
templateUrl:"app/views/home.html",
controller:"homeController",
}
.when('/engg', {
templateUrl:"app/views/engineering.html",
controller:"engineeringController",
})
.when('/med', {
templateUrl:"app/views/medical.html",
controller:"medicalController",
})
}]);
I have left nav in engineering.html using ng-switch which i want to
convert as sub-route of the application.This left nav of engineering
page is not inside of ngView. How do i acheive this using angular's
native ngRoute/angular-route?
**engineering.html**
<div nav ng-switch on="pagename()">
<div ng-switch-when="Civil Engineering">
<div civil-directive> </div>
</div>
<div ng-switch-when="Computer Engineering">
<div computer-directive> </div>
</div>
<div ng-switch-when="Nano Engineering">
<div nano-directive> </div>
</div>
<div ng-switch-when="Electrical Engineering">
<div electrical-directive> </div>
</div>
</div>
EngineeringController.js
(function() {
var app =angular.module("collegeApp");
var engineeringController= functino($scope,$rootscope,$location)
{
$scope.pagename = function() {
return $location.path();
};
app.controller("engineeringController",['$scope','$rootScope','$location',engineeringController])
}());
The above logic is not working for me. Can someone tell me where i am doing the wrong?
Not a good practice but here's what you want to do if you want to use ng-switch:
In your html, as you write for example:
<!-- don't forget to reference your app and your controller -->
<button ng-click="goTo('/page1')">Go to page 1</button>
<button ng-click="goTo('/page2')">Go to page 2</button>
<div nav ng-switch on="pagename()">
<div ng-switch-when="'/page1'"></div>
<div ng-switch-when="'/page2'"></div>
</div>
<div ng-view> </div>
in js
Config your routes
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/page1', {
templateUrl: 'views/page1.html'
}).
when('/page2', {
templateUrl: 'views/page2.html'
}).
otherwise({
redirectTo: '/'
});
}])
and add the following in your controller:
$scope.pagename = function() { return $location.path(); };
$scope.goTo = function(page){
$location.path(page);
}
In the html above, ng-switch will use the $location.path() variable to know which view to display.
As I said this is not a good practice, because your controller isn't suppose to deal with routes.
Here is the entrypoint of my angularjs application. What I'm trying to create is an modal with multiple views.
(function() {
'use strict';
angular
.module('app', ['ui.router', 'ui.bootstrap'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('modal', {
url: '/modal',
onEnter: ['$stateParams', '$state', '$modal', function ($stateParams, $state, $modal) {
$modal.open({
templateUrl: 'partials/modal.html',
backdrop: 'static'
});
}]
})
.state('modal.models', {
url: '/models',
templateUrl: 'partials/modal.models.html'
});
})
.run(function ($rootScope) {
$rootScope.$on("$stateChangeError", console.log.bind(console));
});
}());
and this is the main view
<!-- Modal -->
<div id="myModal">
<div class="modal-header">
<h2>Select your own car</h2>
</div>
<div class="modal-body">
<h4>Brands</h4>
<a ui-sref="modal.models">Models</a>
<div ui-view></div>
</div>
</div>
My problem is that when I click on the link ui-sref nothing happens. Why ui-router doesn't work inside a modal? I should pass in the second view that is the following named modal.models.html
<div>
<h1>Hello</h1>
</div>
For those like me that stumble along later, here's another path:
This plunker uses a simple CSS modal (rather than the fancy ui-bootstrap one) to accomplish the same end result --with the additional perk of 'sticky states' that persist underneath the modal interaction. Note that this supports substates within the modal in a uirouter-kosher way.
$stateProvider.state('modal', {
url: '/modal',
views: {
'modal': {
templateUrl: 'modal.html'
}
}
});
$stateProvider.state('modal.substate', {
url: '/substate',
template: '<h3>I\'m a substate in a modal'
});
(Credit to #christopherthielen for the example code.)
<script type="text/ng-template" id="modal.html">
<div class="modal-overlay fade">
<div class="modal-content">
<h2>Modal</h2>
This modal has a substate. <a ui-sref=".substate">Activate it</a>
<div ui-view></div>
<a ui-sref="app">Back to the app...</a>
</div>
</div>
</script>
In my own troubleshooting, the problem with the 'injected-onEnter' pattern detailed in the ui-router FAQ --which your code follows-- is that the ui-views within the injected template seem to be no longer visible/available to ui-router. Alas! Good thing there's not much required to simply roll-your-own modal window.