I am converting a large server rendered app to use Angular. Because of the size, we are doing it a bit at a time. During this conversion period, part of the app will use Angular and part will not. This means that routing sometimes will route within the Angular app and sometimes it will need to transition from old world to new world (easy) or new world to old world (harder).
Ideally, I would like to specifically route some page transitions within the Angular app (new world) to the proper controllers but then any other page transitions should just fetch new HTML pages (old world).
I can't seem to figure out how to do this. I think I need to use the routeProvider and when / otherwise, but there isn't a lot of documentation that I found which is helpful.
You can't use routeProvider for the old world, since angular routes only direct you within the actual same page.
You could make a placeholder angular route for each legacy route, then in the controller, inject $window and do something like:
$window.location.href = destinationUrl;
Something like: (go to the old world on logout)
app.controller('LogoutCtrl', function ($scope, $window) {
var destinationUrl = 'https://mywebsite.com/';
$window.location.href = destinationUrl;
});
Vice versa, to go back to the angular world, just use a normal link to your angular route:
Link
If you want a catch-all route to redirect to the outside, you can do the following:
otherwise({
controller: 'NotFoundCtrl'
});
...
app.controller('NotFoundCtrl', function($scope, $location, $window) {
var path = $location.path();
$window.location.href="http://test.com" + path;
})
As triggerNZ said, you can always have a controller redirect unhandled routes to the outside. Here is the HTML and Javascript showing how to do it.
HTML
<div ng-app="myApp">
<script type="text/ng-template" id="this.html">
This Page.
</script>
<script type="text/ng-template" id="that.html">
That Page.
</script>
<div>
<ul>
<li>This</li>
<li>That</li>
<li>Other</li>
</ul>
<ng-view></ng-view>
</div>
</div>
Javascript
var app = angular.module("myApp", ['ngRoute']);
app.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/this', {
templateUrl: 'this.html'
}).when('/that', {
templateUrl: 'that.html'
}).otherwise({
template: "<div></div>",
controller: function ($window, $location, $rootScope) {
if (!$rootScope.isInitialLoad) {
$window.location.href = $location.absUrl();
}
}
});
$locationProvider.html5Mode(true);
});
app.run(function ($rootScope) {
$rootScope.$on('$routeChangeSuccess', function() {
$rootScope.isInitialLoad = (typeof $rootScope.isInitialLoad === "undefined");
});
});
Related
I am trying to create a Chrome extension for my school's Online Learning Platform. This website uses HashLocationStrategy, with multiple 'pages'.
I want to add custom ngRoutes to the page, so whenever it goes to the following URL: ".../magister/#/plus" it load my custom template into the ng-view component. I have tried the following script:
angular.module("MagisterPlusRouting", ["ngRoute"])
.controller("RootController", ($scope, $route, $routeParams, $location) => {
$scope.$route = $route;
$scope.$location = $location;
$scope.$routeParams = $routeParams;
})
.controller("PageController", ($scope, $routeParams) => {
})
.config(($routeProvider, $locationProvider) => {
$routeProvider.when("/plus", {
templateUrl: "index.html",
controller: "PageController",
});
$locationProvider.html5Mode(true);
});
But that does not seem to work, I get the following message in my console routechange undefined 0, this originates from the website's official script.
Is it even possible to do this? How do I add these new routes? If you need further information, tell me. Although I do not have access to the development source code of the website.
I was looking at some how-tos on doing angular-routing and to pass parameters into a controller. This is what i did:
.controller("myController", ["$scope", "$routeParams", function($scope, $routeParams, Units, Tests){
//Units and Tests are both factories i created to reference within this function.
var id = $routeParams.id;
console.log(id);
}]);
When I did this, it failed to inject "$routeParams" into my application.
I looked at the angular.js file, and it looks like i am running: #license AngularJS v1.5.3
Is this way of doing it no longer the correct way? I tried to update it to:
.controller("myController", ["$scope", "ngRoute", function($scope, ngRoute, Units, Tests){
// ...
}]);
but that seemed to also not inject correctly.
Is there something I am missing?
Currently I am developing with the Ionic Framework, which is leveraging the AngularJS tools.
When dealing with ionic, as stated within the question, you connect to the $stateProvider so when you are creating a state such as:
$stateProvider
.state("unit", {
url: "/unit/:id",
templateUrl: "templates/unit.html",
controller: "UnitController"
})
you would then in your controller do:
.controller("myController", ["$scope",
"$stateParams",
function($scope, $stateParams, Units, Tests){
var id = $stateParams.id;
console.log(id);
}]);
This is the way to do it in Ionic, since it is leveraging a $stateProvider over a $routeProvider
If you want to navigate to different pages in your application, but you also want the application to be a SPA (Single Page Application), with no page reloading, you can use the ngRoute module.
The ngRoute module routes your application to different pages without reloading the entire application.
var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "main.html"
})
.when("/red", {
templateUrl : "red.html"
})
.when("/green", {
templateUrl : "green.html"
})
.when("/blue", {
templateUrl : "blue.html"
});
});
Your application needs a container to put the content provided by the routing.
This container is the ng-view directive.
like this
<div ng-view></div>
You can also define controllers for each view
var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "main.html"
})
.when("/london", {
templateUrl : "test.html",
controller : "myController"
})
});
Can i create several modules for routing in AngularJS app like:
1. First route management file:
angular.module('app.p.routes', ['ngRoute'])
.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/forbidden',
{
templateUrl: 'app/views/pages/forbidden.html'
})
.......................
2. Second route management file:
angular.module('app.admin.routes', ['ngRoute'])
.config(function ($routeProvider) {
$routeProvider
.when('/admin-dashboard',
{
templateUrl: 'app/views/pages/admin/dashboard.html',
controller: 'dashboardController',
controllerAs: 'dashboard'
})
.............................
3. Main app file:
angular.module('mainApp',
[
'ngAnimate', //animating
'app.p.routes', //public routing
'app.admin.routes',
'ui.bootstrap',
'ngParallax', //parallax effect
'ngFileUpload'
])
When i tried to use this approach page hangs and angular throws error:
> VM188:30554 WARNING: Tried to load angular more than once.
I need an approach to split public and admin routing management.
You can have as many AngularJS modules as you like. There are no rules against that, however, you've attempted to include the Angular source twice which is why you're seeing this warning...
> VM188:30554 WARNING: Tried to load angular more than once.
The simplest solution to your issue that I can think of, is to add an event listener to the $routeChangeStart event. With this you'll be able to verify that the current user has the correct permissions to view anything before they actually to do so.
A simple Service to store some basic information on the current user could like this.
var app = angular.module('app', ['ngRoute']);
app.service('AuthenticationService', function () {
// Set the User object
this.setUser = function () {
this.$user = user;
};
// Get the User object
this.getUser = function (user) {
return this.$user
};
});
And then upon receiving the $routeChangeStart event, you can retrieve the user object and confirm that they are allowed to proceed to the chosen resource.
Here's an example, whereupon a user needs to be an Administrator to view any route that has "/admin" in it.
app.run(function ($rootScope, $location, AuthenticationService) {
// Create a listener for the "$routeChangeStart" event
$rootScope.$on('$routeChangeStart', function () {
// Is the user is an Administrator? Are they attempting to access a restricted route?
if ($location.url().indexOf('/admin') && !AuthenticationService.getUser().isAdmin) {
// Redirect the user to the login page
$location.path('/login');
}
});
});
If you want a more advanced solution however, have a look at this: https://github.com/Narzerus/angular-permission
This will enable you to achieve a more in-depth ACL implementation across your application.
I create single page app by AngularJS and I found my problem. I have function refresh data every 2 minutes by jQuery in route A. When I change to other route, that function in controller is still working. This is my code.
App.js
var newsapp = angular.module('newsAppMD', ['ngRoute']);
newsapp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/news', {
templateUrl: 'templates/news.html',
controller: 'imageNewsCtrl'
}).
when('/news/:nameCat', {
templateUrl: 'templates/news-thumbnail.html',
controller: 'newsPageCtrl'
}).
otherwise({
redirectTo: '/news'
});
}]);
newsapp.controller('imageNewsCtrl', function($scope, $http, $interval, $timeout ) {
$('#bottom-bar').find('#epg').hide();
$scope.updateTimeEPG = 120000;
$scope.fetchFeed = function() {
$http.get("http://wi.th/thaipbs_tv_backend/epg_forJS.php").success(function(response) {
$scope.items = response.Schedule;
console.log($scope.items);
$timeout(function() { $scope.fetchFeed(); }, $scope.updateTimeEPG);
}).then(function() {
$('#bottom-bar').find('.loading').hide();
$('#bottom-bar').find('#epg').show();
});
};
$scope.fetchFeed();
});
newsapp.controller('newsPageCtrl', function($scope, $http, $location) {
// blah blah blah
}]);
I choose /news imageNewsCtrl work. And when I switch to other route, function in imageNewsCtrl still work (I see function print console.log when I changed route). I want to stop function in controller when change route. Thanks for your suggestion everyone. :)
I am not too entirely sure, but try using $stateProvider instead of $routeProvider. If you do, then you need to npm install angular-ui-router (it is a powerful third party module) and replace ngroute. I only user $routeProvider for the .otherwise function. You can also do a lot more cool stuff like onEnter and onExit with $stateProvider. Another thing is I would recommend you to use only Angular instead of jQuery. I do not really see a point of you using both. Use Angular's two-way data binding! Also, if you really want to get into Angular, then I recommend John Papa's style guide. This guys knows what he is talking about for making a great Angular app. I hope this info helps!
I have a reset link, which is meant to reset my angular js app...
<a ng-click="resetApp()">reset</a>
I am handling the button press in the main controller...
$scope.resetApp = function(){
if(confirm("You will lose data...")){
$scope.user.reset();
// not sure how to do this in more angular js way
window.location = "/#";
}
}
I am not sure if setting the window.location as I have done is the right way to do things. It works for me, but does not seem like the correct way, and I have not been able to find out ow to do it online.
I have been using the so-called AngularJS way like this, at least the routing is handled by AngularJS rather than browser directly.
function Ctrl($scope, $location) {
$scope.resetApp = function(){
...
$location.url('/');
}
}
The path is what is defined in the Route Provider like this:
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'index.html',
controller: 'Ctrl'
}).
...