Nested views error - only after refreshing page - angularjs

I am a total beginner with Angluar.JS. I want to have a Single Page Application with a row of tabs, each of which can contain another row of tabs, each of which contains a view.
So, I asked this question and accepted an answer, which had a demo at http://plnkr.co/edit/BUbCR8?p=preview.
The demo was very close, but used a list instead of the second row of tabs, so I am trying to modify the code. So far, I just have a skeleton, a proof of concept of nested tabs with views. I will drop the real contents in later.
I will post my code below, but here is the problem:
when I drag & drop the index,html file into the browser, it works fine. I can click around and what I expect to happen seems to happen. There is not much to see when moving between the tabs Left, Centre & Right; so far the action is on Link & Link2 of the Left tab.
Seems perfect - until press F5 and refresh the page, then I start geeing errors in the JS Console:
Error: Could not resolve '.link2' from state 'left.link1'
at Object.t.transitionTo (http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js:7:8834)
at Object.t.go (http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js:7:8182)
at http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js:7:15639
at http://code.angularjs.org/1.2.9/angular.js:13585:28
at completeOutstandingRequest (http://code.angularjs.org/1.2.9/angular.js:4111:10)
at http://code.angularjs.org/1.2.9/angular.js:4418:7
If I drag the file back onto the browser, all is fine again. Same behavior in Chrome & FireFox.
Any idea what I am doing wrong?
Index.html
<!DOCTYPE html>
<html ng-app="plunker">
<!-- http://plnkr.co/edit/BUbCR8?p=preview -->
<head>
<meta charset="utf-8" />
<title>Nested tabs demo</title>
<link data-require="bootstrap-css#*" data-semver="3.0.3" rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" />
<link data-require="font-awesome#*" data-semver="4.0.3" rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" />
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script data-require="angular.js#1.2.x" src="http://code.angularjs.org/1.2.9/angular.js" data-semver="1.2.9"></script>
<script data-require="ui-bootstrap#*" data-semver="0.10.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.min.js"></script>
<script data-require="angular-animate#*" data-semver="1.2.9" src="http://code.angularjs.org/1.2.9/angular-animate.js"></script>
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js"></script>
<!-- Our stuff -->
<script src="app.js"></script>
<script src="controller.js"></script>
</head>
<body ng-controller="Tabs">
<div style="border-style:solid;border-width:1"> <!-- FixMe: uses CSS, not inline style -->
<h3>Nested tabs demo</h3>
</div>
<!-- ToDO: how to set initial state & view
<span>$state = <b>{{$state.current.name}}</b></span><br>
<span>$state url = <b>{{$state.$current.url.source}}</b></span>
-->
<tabset>
<tab>
<tab-heading>
<a ui-sref="left" ui-sref-active="active">Left</a>
</tab-heading>
</tab>
<tab>
<tab-heading>
<a ui-sref="centre" ui-sref-active="active">Centre</a>
</tab-heading>
</tab>
<tab>
<tab-heading>
<a ui-sref="right" ui-sref-active="active">Right</a>
</tab-heading>
</tab>
</tabset>
<div class="row">
<br>
<div ui-view="viewA">
<!--Here is the A content-->
</div>
</div>
</body>
app.js
var app = angular.module('plunker', ['ui.bootstrap', 'ui.bootstrap.tpls', 'ui.router'])
.run(['$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
// It's very handy to add references to $state and $stateParams to the $rootScope
// so that you can access them from any scope within your applications.For example,
// <li ng-class="{ active: $state.includes('contacts.list') }"> will set the <li>
// to active whenever 'contacts.list' or one of its decendents is active.
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}]);
app.config(function($stateProvider,$locationProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$locationProvider.html5Mode(false).hashPrefix('!');
$stateProvider
.state('left', {
url: "/",
views: {
"viewA": {
template: '<h1>Left Tab, index.viewA</h1><br></h1><div>' +
'<tabset>' +
' <tab>' +
' <tab-heading>' +
' <a ui-sref=".link1">Link1</a><br>' +
' </tab-heading>' +
' </tab>' +
' <tab>' +
' <tab-heading>' +
' <a ui-sref=".link2">Link2</a></div>' +
' </tab-heading>' +
' </tab>' +
'</tabset>' +
'<div class="col-xs-6">' +
'<div ui-view="viewA.link1"></div>' +
'<div ui-view="viewA.link2"></div></div>'
},
"viewC": {
template: 'Left Tab, viewC <div ui-view="viewC.link1"></div>' +
'<div ui-view="viewC.link2"></div>'
}
}
})
.state('left.link1', {
url: 'link1',
views: {
"viewA.link1": {
template: '<h2>viewA Nest Link1</h2><ul>' +
'<li ng-repeat="thing in link1things">{{thing}}</li></ul>',
controller: 'Tab1Link1Ctrl',
data: {}
},
"viewC.link1": {
template: 'Link1'
}
}
})
.state('left.link2', {
url: 'link2',
views: {
"viewA.link2": {
template: '<h2>viewA Nest Link2</h2><ul>' +
'<li ng-repeat="thing in link2things">{{thing}}</li></ul>',
controller: 'Tab1Link2Ctrl',
data: {}
},
"viewC.link2": {
template: 'Link2'
}
}
})
.state('centre', {
url: "/centre",
views: {
"viewA": {
template: '<h1>Centre Tab, viewA</h1>',
controller: '2ndTabCtrl',
data: {}
},
"viewC": {
template: 'Centre Tab, viewC <div ui-view="viewC.list"></div>'
}
}
})
.state('right', {
url: "/right",
views: {
"viewA": {
template: '<h1>Right Tab, viewA</h1>',
controller: '2ndTabCtrl',
data: {}
},
"viewC": {
template: 'Right Tab, viewC <div ui-view="viewC.list"></div>'
}
}
});
});
controller.js
app.controller('Tabs', ['$scope', '$stateParams', '$state',
function($scope, $stateParams, $state) {}
]);
app.controller('2ndTabCtrl', ['$scope', '$stateParams', '$state',
function($scope, $stateParams, $state) {}
]);
app.controller('Tab1Link1Ctrl', ['$scope', '$stateParams', '$state',
function($scope, $stateParams, $state) {
$scope.link1things = ["A", "Set", "Of", "Things", "link1", "viewA"];
}
]);
app.controller('Tab1Link2Ctrl', ['$scope', '$stateParams', '$state',
function($scope, $stateParams, $state) {
$scope.link2things = ["A", "Set", "Of", "Things", "link2", "viewA"];
}
]);

in your template youre triggering state '.link1':
<a ui-sref=".link1">Link1</a>
but you havent defined a state called '.link1' in your state config. You do have a state named 'left.link1'. Is that what you meant?
P.S. In the future just create a plunkr with your examples, its a pain scrolling through multiple files here

Related

$location not changing the path in AngularJS

I am new for AngularJS and I'm having issue with moving one page to another and I have to pass parameters from main page to details page, I followed below code but it's not working and I am getting error:
ReferenceError: $location is not defined at a.$scope.moveToOthers (showOrders.js:4)
app.js:
var sampleApp = angular.module('sampleApp', ["ngRoute"]);
sampleApp.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.
when('/AddNewOrder', {
templateUrl: 'templates/add_orders.html',
controller: 'AddOrderController'
}).
when('/ShowOrders', {
templateUrl: 'templates/show_orders.html',
controller: 'ShowOrdersController'
}).
when('/ExpandOrders', {
templateUrl: 'templates/expand_orders.html',
controller: 'ExpandOrderController'
}).
when('/OthersPage:id?', {
templateUrl: 'templates/others_page.html',
controller: 'OthersPageController'
}).
otherwise({
redirectTo: '/AddNewOrder'
});
}]);
show_orders.html
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
<script src="controllers/othersPage.js"></script>
<title>AngularJS Routing example</title>
</head>
<body>
<h1>Show orders</h1>
<button ng-click="moveToOthers()" type="button" class="btn btn-default" style="margin:10px 0px 10px 0px;">Others Page</button>
</body>
</html>
showOrders.js:
sampleApp.controller('ShowOrdersController', function ($scope, $location) {
$scope.msg = 'This is Show orders screen123';
$scope.moveToOthers = function () {
$location.path('/others_page/100')
}
});
I suggest this:
Correct your router: change '/OthersPage:id?' to '/OthersPage/:id'
On the <button> element don't use a function to change your path. Use instead an ng-href like this: <a ng-href="/OthersPage/100" type="button" class="btn btn-default" style="margin:10px 0px 10px 0px;">Others Page</a>

Make two layouts share the same $scope

I want to propose two layouts (ie, horizontal and vertical) for my contents. So switching in the selector will lead automatically to the corresponding layout. Here is the JSBin:
<html ng-app="flapperNews">
<head>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router.js"></script>
<script type="text/ng-template" id="horizontal.tpl">
<textarea ng-model="one"></textarea>, <textarea ng-model="two"></textarea>
<br><br>{{one}}+{{two}}
</script>
<script type="text/ng-template" id="vertical.tpl">
<textarea ng-model="one"></textarea><br><textarea ng-model="two"></textarea>
<br><br>{{one}}+{{two}}
</script>
<script>
var app = angular.module('flapperNews', ['ui.router']);
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('entry', {
url: '/',
params: { tpl: 'vertical' },
templateUrl: function (params) {
return params.tpl + ".tpl"
}
})
}]);
app.controller('MainCtrl', ['$scope', '$state', function ($scope, $state) {
$scope.one = "one";
$scope.two = "two";
$scope.layouts = ["horizontal", "vertical"];
$scope.$watch('layout', function () {
$state.go('entry', {tpl: $scope.layout});
})
}])
</script>
</head>
<body ng-controller="MainCtrl">
<select ng-model="layout" ng-init="layout = 'horizontal' || layouts[0].value" ng-options="x for x in layouts"></select>
<br><br>
<ui-view></ui-view>
</body>
</html>
However, with the above code, each time we change the view, $scope.one and $scope.two are reset to their initial values. I would hope the change in their textarea would remain regardless of the change of layout.
Does anyone know how to solve this?
Easy sharing same data between different views by using factories (AngularJS factory documentation). Try this example, it uses a simple factory named myFactory to share data between controllers. This also does work on the same controller as in your case.
var myApp = angular.module("myApp",[ "ui.router"]);
myApp.config(function ($stateProvider, $urlRouterProvider){
$stateProvider.state("state1", {
url: "#",
template: '<p>{{ aValue }}</p><button ng-click="bindValue(\'its me\')">Bind value</button>',
controller: "myController"
}).state("state2", {
url: "#",
template: '<p>{{ aValue }}</p><button ng-click="bindValue(\'its me\')">Bind value</button>',
controller: "myController"
});
});
myApp.controller( "myController", function($scope, myFactory) {
$scope.aValue = myFactory.myValue;
$scope.bindValue = function (value) {
$scope.aValue = value;
myFactory.myValue = value;
}
});
myApp.factory('myFactory', function () {
return {
myValue: ''
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.8/angular-ui-router.min.js"></script>
<div ng-app="myApp">
<nav>
<a ui-sref="state1">State 1</a>
<a ui-sref="state2">State 2</a>
</nav>
<div ui-view></div>
</div>
I think that you should use nested views - you can define main controller on parent route state and define two nested states corresponding to two views. This way parent controller will remain (it's not re-initialised when child states are switched) and only nested states views will be changed. Something like this:
$stateProvider
.state('myState', {
url: '/test/',
template: '<div ui-view></div>',
controller: function() {
//main controller shared by child states
...
}
})
.state('myState.view1', {
url: '/test/view1'
templateUrl: 'tpl-1.hmtl',
...
})
.state('myState.view2', {
url: '/test/view2'
templateUrl: 'tpl-2.hmtl',
...
})

AngularJs Open Route Page On Modal

In my angular-message application I have an option to choose message from template.
I need open the template list as modal.
My problem is that I have a template list as controller + view
How can I open the view without to duplicate my template list code.
$stateProvider
.state('app', {})
.state('app.email', {
}).state('app.email.compose', {
url: '/compose',
data: {
pageTitle: 'Email Compose'
},
templateUrl: 'Assets/app/templates/email_compose.html'
})
.state('app.manage', {
})
.state('app.manage.templates', {
template: '<div ui-view></div>',
url: '/templates',
abstract: true
})
.state('app.manage.templates.list', {
url: '/',
data: {
pageTitle: 'Email List'
},
templateUrl: 'Assets/app/templates/tamplate_list.html'
});
In my app route I want to open the app.manage.template.list
from app.email.compose as modal
How can I do it?
This can easily be done using UI-Bootstrap: https://angular-ui.github.io/bootstrap/ A walkthrough:
Load the Bootstrap CSS asset, note you don't need the JS and jQuery:
<link type="text/css" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
Load the UI-Bootstrap asset:
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.1.2/ui-bootstrap-tpls.min.js"></script>
Inject the ui.bootstrap module in your application:
angular.module('app', [
'ui.router',
'ui.bootstrap'
]);
Use the onEnter method of your state definition to open a new modal:
.state('myModalState', {
'url': '/myModalUrl',
'onEnter': [
'$uibModal',
function ($uibModal) {
$uibModal.open({
'controller': 'myModalController',
'templateUrl': 'myModalTemplate.html'
}).result.then(
function closed (item) {
// Executed when uibModalInstance is closed, returns value
},
function dismissed () {
// Executed when modal is dismissed/canceled
}
);
}
]
});
Create a controller for your modal and inject $uibModalInstance:
.controller('myModalController', [
'$scope', '$uibModalInstance',
function ($scope, $uibModalInstance) {
$scope.item = 'foobar';
$scope.ok = function () {
$uibModalInstance.close($scope.item);
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
}
]);
And finally a template for the modal:
<div class="modal-header">
<h4 class="modal-title">Title</h4>
</div><!-- /.modal-header -->
<div class="modal-body">
{{item}}
</div><!-- /.modal-body -->
<div class="modal-footer">
<button type="button" class="btn btn-warning" ng-click="cancel()">
Cancel
</button>
<button type="button" class="btn btn-success" ng-click="ok()">
Ok
</button>
</div><!-- /.modal-footer -->
Now everytime you visit /myModalUrl or ui-sref or state.go to myModalState the modal automaticly opens.
Stacksnippet:
angular.module('app', [
'ui.router',
'ui.bootstrap'
]);
angular.module('app').config([
'$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider.state('root', {
url: '/',
templateUrl: 'root.html',
});
$stateProvider.state('modal', {
url: '/modal',
onEnter: [
'$uibModal', '$state',
function ($uibModal, $state) {
$uibModal.open({
'controller': 'modal',
'templateUrl': 'modal.html',
}).result.then(
function closed (item) {
// Executed when uibModalInstance is closed, returns value
$state.go('root');
},
function dismissed () {
// Executed when modal is dismissed/canceled
$state.go('root');
}
);
}
]
});
}
]);
angular.module('app').controller('modal', [
'$scope', '$uibModalInstance',
function ($scope, $uibModalInstance) {
$scope.item = 'foobar';
$scope.ok = function () {
$uibModalInstance.close($scope.item);
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
}
]);
<!DOCTYPE html>
<html ng-app="app">
<head>
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.css" />
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js"></script>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.14.3/ui-bootstrap-tpls.js"></script>
<script type="text/ng-template" id="root.html">
<a ui-sref="modal">Open route in modal</a>
</script>
<script type="text/ng-template" id="modal.html">
<div class="modal-header">
<h4 class="modal-title">Title</h4>
</div>
<div class="modal-body">
{{item}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning" ng-click="cancel()">
Cancel
</button>
<button type="button" class="btn btn-success" ng-click="ok()">
Ok
</button>
</div>
</script>
</head>
<body ui-view></body>
</html>
Plunker: http://plnkr.co/edit/5qrD7hB6i8vQEqa8jZ1G?p=preview
UI-Router FAQ on opening a modal when entering a state (mind you it's outdated because of some changes to the UI bootstrap modal directive):
https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-open-a-dialogmodal-at-a-certain-state
And here's the reference for UI-Bootstrap's modal directive:
https://angular-ui.github.io/bootstrap/#/modal
I resolve it by adding route as "child" from another state, that refer to same templateUrl templateUrl: 'Assets/app/templates/tamplate_list.html'
$stateProvider
.state('app.email.compose', {
url: '/compose',
data: { pageTitle: 'Email Compose' },
templateUrl: 'Assets/app/templates/email_compose.html'
}).state('app.email.compose.template', {
url: '/template',
data: { pageTitle: 'Email Compose', modal: true },
parent: 'app.email.compose',
templateUrl: 'Assets/app/templates/tamplate_list.html'
}).state('app.manage.templates.list', {
url: '/',
data: { pageTitle: 'Email List' },
templateUrl: 'Assets/app/templates/tamplate_list.html'
});

Switching Angular view not updating variables

I'm just building out a simple app to learn AngularJS and having trouble updating variables when switching views. Here's what I have so far:
function routeConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/main/main.html',
controller: 'MainController',
controllerAs: 'main'
})
.state('team', {
url: '/team',
templateUrl: 'app/main/team.html',
controller: 'MainController',
controllerAs: 'main'
})
$urlRouterProvider.otherwise('/');
}
Here's part of my controller:
function MainController($timeout, webDevTec, toastr, $resource, $scope) {
var vm = this;
var GetTeam = $resource('https://apisite.com/api_endpoint/:teamId', {teamId: '#id'});
vm.teamName = '';
function getTeamInfo(id) {
var teamObj = GetTeam.get({teamId: id});
$timeout(function(){
vm.teamName = teamObj["name"];
},100)
};
vm.getTeamInfo = getTeamInfo;
}
Then in my main.html I call getTeamInfo with a ng-click:
<ul class="list-group">
<li class="list-group-item" ng-repeat="team in main.teams" ng-click="main.getTeamInfo(team.id)">{{ team.name }}</li>
</ul>
Clicking on that link will take you to team.html:
<div class="row">
<div class="col-sm-12">
<h3>{{ main.teamName }}</h3>
<ul class="list-group">
. . .
</ul>
</div>
</div>
For some reason "main.teamName" is not updating. I've tried the $scope.$apply(function(){vm.teamName = teamObj["name"]} approach as well with no luck. I also did 'console.log(teamObj["name"])' before vm.teamName and 'console.log(vm.teamName)' after to see if I get the expected results and I do. I just have no idea now why it's not updating the new view.
Thank you for your insight, patience, and time!
UPDATE 1
I also tried using $scope on my variables ($scope.teamName) and using $scope.$apply(function(){$scope.teamName = teamObj["name"]}) with no luck.
UPDATE 2
I also tried called $scope.$apply(); after 'vm.teamName = teamObj["name"]' with no luck
It looks like teamObj is not populated yet at the point when you assign vm.teamName
You would make your life so much easier if you just reference teamObj rather than creating a new property.
I made a plunker based on a modified version of your code to show a possible implementation. I couldn't get it to work using the controllerAs syntax and I'm not entirely sure why (possibly because of some issues related to sharing a controller; not sure). Anyway, hopefully it will be of some help to you.
DEMO
app.js
var app = angular.module('plunker', ['ui.router', 'ngResource']);
app.controller('MainController', MainController);
app.config(routeConfig);
function MainController($timeout, $scope, $resource) {
// mock data
var GetTeam = $resource('http://demo7592070.mockable.io/teams/:teamId', {teamId: '#id'});
//var GetTeam = $resource('https://apisite.com/api_endpoint/:teamId', {teamId: '#id'});
$scope.teamName = 'undefined';
$scope.getTeamInfo = getTeamInfo;
function getTeamInfo(id) {
var teamObj = GetTeam.get({teamId: id});
$scope.teamName = teamObj.name;
$scope.teamObj = teamObj;
};
}
function routeConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'main.html',
controller: 'MainController'
})
.state('team', {
url: '/team',
templateUrl: 'team.html',
controller: 'MainController'
});
console.log('ROUTECONFIG');
$urlRouterProvider.otherwise('/');
}
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<!-- JS (load angular, ui-router, and our custom js file) -->
<script src="http://code.angularjs.org/1.2.13/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.8/angular-ui-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular-resource.js"></script>
<script src="app.js"></script>
</head>
<body>
<a ui-sref="home">home</a>
<a ui-sref="team">team</a>
<div ui-view=""></div>
</body>
</html>
main.html
<h1>Home</h1>
<pre>$scope.teamName => {{teamName}}</pre>
<pre>$scope.teamObj => {{teamObj}}</pre>
<pre>$scope.teamObj.name => {{teamObj.name}}</pre>
<button ng-click="getTeamInfo(1)">Get Team 1</button>
team.html
<h1>Team</h1>
<pre>$scope.teamName => {{teamName}}</pre>
<pre>$scope.teamObj => {{teamObj}}</pre>
<pre>$scope.teamObj.name => {{teamObj.name}}</pre>
<button ng-click="getTeamInfo(2)">Get Team 2</button>

AngularJS: Changing Routes Based on Drop-Down Not Working

I am working on a project that will ultimately be responsive and the navigation will collapse down to a select control, so I found an article on Google about this. I learned that the ng-change does not fire an angular event but it was suggested that adding a ng-click to the option tags would replace that void.
As I built my POC, the first thing I realized is that my copying-and-pasting the go function into each meant the design wasn't DRY (so alarms began sounding off in my head) and probably means this is not the right way to do this.
I continue to build what I understood from the article and it doesn't change the routes.
I built a plunker.
Here's the HTML:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<title>Proof of Concept</title>
<link data-require="bootstrap-css#*" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<form>
<select name="naver" id="naver">
<option value="home" ng-click="go('/')">Home</option>
<option value="first" ng-click="go('/first')">First</option>
<option value="second" ng-click="go('/second')">Second</option>
</select>
</form>
<div ng-view=""></div>
<script data-require="angular.js#1.2.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js" data-semver="1.2.16"></script>
<script data-require="angular-route#*" data-semver="1.2.14" src="http://code.angularjs.org/1.2.14/angular-route.js"></script>
<script data-require="jquery#*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script data-require="bootstrap#*" data-semver="3.1.1" src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="app.js"></script>
</body>
</html>
and the script:
var app = angular.module("myApp", ['ngRoute']);
app.config(function($routeProvider){
$routeProvider
.when('/', {
templateUrl: "home.html",
controller: 'HomeController'
})
.when('/first', {
templateUrl: "first.html",
controller: 'FirstController'
})
.when('/second', {
templateUrl: "second.html",
controller: 'SecondController'
})
.otherwise({ redirectTo: '/' });
});
app.controller('HomeController', function($scope, $location){
$scope.go = function( path ){
$location.path(path);
}
});
app.controller('FirstController', function($scope, $location){
$scope.go = function( path ){
$location.path(path);
}
});
app.controller('SecondController', function($scope, $location){
$scope.go = function( path ){
$location.path(path);
}
});
Any help is greatly appreciated!
You indeed can be more DRY than that. I would:
Remove all go() functions from the views' controllers.
Create a new controller (e.g. NavCtrl) for the navigation "bar".
<form ng-controller="NavCtrl">
Remove the ngClick directives from the <option> elements (since they don't seem to have any effect - at least in Chrome).
Add an ngModel to the <select> element to keep track of the selected page/view.
Add an ngChange listener to the <select> element to trigger a "redirection" every time the selected page/view changes.
<select id="naver" name="naver" ng-model="currentPage" ng-change="go(currentPage)">
<option value="home">Home</option>
<option value="first">First</option>
<option value="second">Second</option>
</select>
Define the go() function inside the aforementioned NavCtrl controller.
app.controller('NavCtrl', function NavCtrl($location, $scope) {
$scope.currentPage = 'home';
$scope.go = function go(page) {
$location.path('/' + page);
};
});
See, also, this short demo.
The go() function cannot be called, since the select control is out of the scope of the page controllers.
Try this instead:
plunkr
To Complement the above answers, i have created a directive which will switch routes based on the value selected.
please find the plunk here:
plunkr
Here is the code:
`app.controller('mainController', function($rootScope, $scope) {
$scope.testArray = [{
'option': 'home'
}, {
'option': 'first'
}];
$scope.testModel = $scope.testArray[0].option;
});
app.directive('selectDirective', function() {
return {
scope: {
testModel: '=',
testArray: '=',
go: '&'
},
require: 'ngModel',
template: `<select name="testModel" ng-model="testModel" value="option.option" ng-change="Model(testModel)" ng-options="option.option for option in testArray">{{option.option}}</option>
<option value="" selected="selected">Select an Item</option>
</select>`,
replace: true,
controller: function($scope, $location) {
$scope.Model = function(page) {
$location.path('/' + page.option);
}
}
}
});`
HTML:
'<test-directive dat-options="testArray" dat-heldmodel="testModel"></test-directive>
<div>Selected: {{testModel}}</div>'

Resources