How do I update UI when location changes occur? - angularjs

I am trying to implement a navigation bar that is at the top of my web app. That nav bar has tabs for which location you are at. (I.E. 'home' = '/home', 'settings' = '/settings' etc.) How can I update the UI to denote which tab they are on after the URL change has occurred?
To determine routes in the app the code is:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/home', {
templateUrl: 'partials/home.html',
controller: 'homeCtrl'
}).
when('/projects', {
templateUrl: 'partials/projects.html',
controller: 'projectsCtrl'
}).
when('/about', {
templateUrl: 'partials/about.html',
controller: 'aboutCtrl'
}).
when('/contact', {
templateUrl: 'partials/contact.html',
controller: 'contactCtrl'
}).
otherwise({
redirectTo: '/home'
});
}]);

if you just want a quick implementation i might recommend putting something like {{title}} in your html template, and configuring and using $rootScope.title to update this value from each of your controllers.
implementation would be something like this plus the update to your template.
angular.module('myApp', [])
.run(function($rootScope) {
$rootScope.title = "";
})
.controller('myCtrl', function($scope, $rootScope) {
$rootScope.title = "Navigation Bar Title"
})
but i think that a better way to do it would actually be to create a state for your navigation bar and make each of your current states a different child state of your navigation state. Because of scope inheritance you would have access to the navigation states $scope.title in any nested child state.
here is a good place to learn how that should work.
https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views#inherited-custom-data

Related

How to change templates using angular

I have just started to learn angular.
I have the following:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
controller: 'RouteCtrl',
templateUrl: 'views/partials/index.html'
}).
when('/about', {
templateUrl: 'views/partials/about.html'
}).
when('/contact', {
templateUrl: 'views/partials/contact.html'
}).
when('/login', {
templateUrl: 'themes/admin/views/admin/partials/login.html'
}).
otherwise({
templateUrl: 'views/partials/index.html',
controller: function ($scope) {
$scope.message = 'Welcome!!';
}
});
}
]);
The login should have a completly different layout as from the other views.
In yii I would just put something like $this->layout = admin-column1;
How do I switch in angular from layout as I have 2 different types of layouts, one from my website and one admin cms layout?
The problem is that the ng-view use the same <head></head> and footer includes, I want to change that dynamically.

Controllers and how they should be implemented in Angular?

Sorry if this seems like a stupid or simple question but I am a little confused, I have been looking up many different kinds of tutorials for Angular to understand the concept and how to create an application.
The issue is how to you attach a Controller to the Page, I have seen two methods:
Add the controller script to the page
Display Controller inside the app.js where the Website Routing is.
Here is what I have at the moment please let me know if there is any issues in this code:
var app = angular.module('myApp', [
'ngRoute'
]);
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/home.html',
controller: 'homeController'
}).
when('/login', {
templateUrl: 'partials/login.html',
controller: ''
}).
when('/signup', {
templateUrl: 'partials/signup.html',
controller: ''
}).
when('/dashboard', {
templateUrl: 'partials/dashboard.html',
controller: ''
}).
otherwise({
redirectTo: '/404',
templateUrl: 'partials/404.html'
});
}]);
app.controller('homeController', ['$scope', function($scope) {
$scope.message = "This is the Home Page";
}]);
Again I am really new to Angular.
Updated to single Controller file:
app.js:
var app = angular.module('myApp', [
'ngRoute'
]);
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/home.html',
controller: 'controllers/homeController.js'
}).
when('/login', {
templateUrl: 'partials/login.html',
controller: ''
}).
when('/signup', {
templateUrl: 'partials/signup.html',
controller: ''
}).
when('/dashboard', {
templateUrl: 'partials/dashboard.html',
controller: ''
}).
otherwise({
redirectTo: '/404',
templateUrl: 'partials/404.html'
});
}]);
controller file:
app.controller('homeController', ['$scope', function($scope) {
$scope.message = "This is the Home Page";
}]);
Nope, your code is fine. I generally use two different files app.js for all the routing options and a controller.js file for the different controllers. A single file seems a bit too cluttered to me.
A single file per controller works but I see for most usercases it turns out just a few lines of code per page for me, but you can if you have extensive codes in each controller
I create a Controller for every model in my database: e.g: ProjectController.js, PeopleController.js, etc. And I use app.js just for routing and general controllers like header, footer, etc.
There isn't a strict way to do it, you have to decide it based on your architecture design. But i can give you a tip: Never define your controllers in your .html file because it makes it awful and less readable.
That's a purely organizational choice. As long as the browser has the code of the controller available, it doesn't matter.
But unless you're creating a tiny demo, having all the controllers defined in a single JavaScript file will quickly become unmanageable: the file will be too large, you'll search for the controllers constantly, and everyone in the team will modify the same file, leading to conflicts, etc.
The simple rule is: one JS file per AngularJS component.
If you're concerned about two many JS files having to be loaded by the HTML page in production, then make sure to learn using gulp or grunt, and to generate a single minified JS file from all the small JS files used during development.
EDIT:
the controller attribute of the route is not supposed to be the path of a JS file. It's supposed to be the name of a controller. It should thus stay exactly as it was in the first, working example.
You need to understand how the browser works: if the HTML contains two <script> elements, it works the same way as if it had a single one with the code of the two scripts concatenated. So splitting the code in two files doesn't change the way the code is written.
Change your route specification to the following code:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/home.html',
controller: 'homeController' //change here
//controller should be the name of the controller,
//not the file containing the controller function
}).
when('/login', {
templateUrl: 'partials/login.html',
controller: ''
}).
when('/signup', {
templateUrl: 'partials/signup.html',
controller: ''
}).
when('/dashboard', {
templateUrl: 'partials/dashboard.html',
controller: ''
}).
otherwise({
redirectTo: '/404',
templateUrl: 'partials/404.html'
});
}]);

AngularJS multiple routes with same template shouldn't rerender

I have several views that use the same template, only the number of route params is different, how can I set it up so that the view doesn't get rerendered every time the route changes, tried with reloadOnSearch: false, but it didn't work for some reason.
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/feeds', {
templateUrl: 'partials/feeds.html',
controller: 'FeedsController'
})
.when('/feeds/:country', {
templateUrl: 'partials/feeds.html',
controller: 'FeedsController'
})
.when('/feeds/:country/:competition', {
templateUrl: 'partials/feeds.html',
controller: 'FeedsController'
})
.otherwise({
redirectTo: '/feeds'
});
}]);
According to the documentation, You cannot define multiple path's for one route. So in your case you should define two unique routes like:
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/feeds/:country/:competition/:event', {
templateUrl: 'partials/event.html',
controller: 'EventController'
})
.when('/feeds/:country/:competition', {
templateUrl: 'partials/feeds.html',
controller: 'FeedsController'
})
.otherwise({
redirectTo: '/feeds'
});
}]);
Difference, always call this URL with full params like:
http://yourapplication/feeds/false/false/false
http://yourapplication/feeds/1/false/false
http://yourapplication/feeds/1/2/false
http://yourapplication/feeds/1/2/3
And the one who is calling FeedsController is still unique with only two params:
http://yourapplication/feeds/1/2/

Dynamically switch ng-include between controllers

I have the following bit of code for my navigation that I want to update dynamically between pages.
<nav ng-include="menuPath"></nav>
Here is my app and routing set up
var rxApp = angular.module('ehrxApp', ['ngRoute']);
// configure our routes
rxApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'mainController',
templateUrl: '/content/views/index.html'
})
.when('/census', {
templateUrl: '/content/views/admission/census.html',
controller: 'censusController'
})
.when('/messages', {
templateUrl: '/content/views/account/messages.html',
controller: 'messagesController'
})
.when('/profile', {
templateUrl: '/content/views/account/profile.html',
controller: 'profileController'
})
});
In my main controller I set the menuPath value here:
rxApp.controller('mainController', function (userService, $scope, $http) {
evaluate_size();
$scope.menuPath = "/content/views/index.menu.html";
});
rxApp.controller('censusController', function ($scope, $http, $sce, censusService) {
$scope.menuPath = "/content/views/admission/census.menu.html";
evaluate_size();
});
When the page switches to the census view it should change the menu. What happens though is the first page loads the main menu, then no matter what other page you go to the menu never updates.
I imagine this problem has something to do with a primitive values and prototypical inheritance between child scopes, but would need to see more of your html to determine that. Without that, I propose an alternative way that may solve your problem and keep the config all in one place.
$routeProvider will accept variables and keep them on the route, even if angular doesn't use them. so we modify your routing by including the menuPath like so:
var rxApp = angular.module('ehrxApp', ['ngRoute']);
// configure our routes
rxApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'mainController',
templateUrl: '/content/views/index.html',
menuPath: '/content/views/index.menu.html'
})
.when('/census', {
templateUrl: '/content/views/admission/census.html',
controller: 'censusController',
menuPath: '/content/views/admission/census.menu.html'
})
.when('/messages', {
templateUrl: '/content/views/account/messages.html',
controller: 'messagesController'
})
.when('/profile', {
templateUrl: '/content/views/account/profile.html',
controller: 'profileController'
})
});
Remove setting $scope.menuPath from each controller, then finally add a watch on rootScope that will change the menuPath on $routeChangeSuccess
rxApp.run(['$rootScope', function ($rootScope) {
$rootScope.$on('$routeChangeSuccess', function(event, current) {
if (current && current.$$route && current.$$route.menuPath) {
$rootScope.menuPath = current.$$route.menuPath;
} else {
$rootScope.menuPath = '';
}
});
}]);

AngularJS nested routing

I'm working a fairly simple AngularJS project with some deep route nesting to select from a nested data structure:
angular.module('doccat', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/', { templateUrl: 'partials/detail.html', controller: DocDetailCtrl }).
when('/:p0', { templateUrl: 'partials/detail.html', controller: DocDetailCtrl }).
when('/:p0/:p1', { templateUrl: 'partials/detail.html', controller: DocDetailCtrl }).
when('/:p0/:p1/:p2', { templateUrl: 'partials/detail.html', controller: DocDetailCtrl }).
when('/:p0/:p1/:p2/:p3', { templateUrl: 'partials/detail.html', controller: DocDetailCtrl }).
when('/:p0/:p1/:p2/:p3/:p4', { templateUrl: 'partials/detail.html', controller: DocDetailCtrl }).
otherwise({ redirectTo: '/' });
}]);
function DocDetailCtrl($scope, $routeParams) {
var path = [];
if ($routeParams.p0) path.push($routeParams.p0);
if ($routeParams.p1) path.push($routeParams.p1);
if ($routeParams.p2) path.push($routeParams.p2);
if ($routeParams.p3) path.push($routeParams.p3);
if ($routeParams.p4) path.push($routeParams.p4);
// do stuff with path
}
This has up to 5 layers in the path, which should be plenty for my purposes, so it is good enough for now. However, the underlying data could be nested arbitrarily deep, which would require arbitrary routing.
I think the ideal for this would be a route that says 'all the rest of the path goes to any array of parameters', but it doesn't look like there is a way to do anything like that in AngularJS. Just for the sake of completeness, does anyone know of a way to do this?
Check $routeProvider in the doc
angularjs $routeProvider.
Especially, in the definition of 'when', you can read: "path can contain named groups starting with a star (*name). All characters are eagerly stored in $routeParams under the given name when the route matches." So you just need to make sure the route matches and you'll get plenty parameters stored in $routeParams.
I hope it helps.

Resources