Working on single page application everything is working fine but getting stuck when want to set 404 page when :username not found or any unexpected url will load in browser please check my code below
controller.js
var myApp = angular.module('assignment', ['ngRoute']);
myApp.service('userData', ['$http', function($http){
return{
userslist : function(){
return $http({'url' : 'js/data.json', 'method' : 'GET'}).then(function(response){
return response.data;
}, function(data){
console.log('some error')
})
}
}
}]);
myApp.config(function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'user-list.html',
controller: 'users'
}).
when('/:username', {
templateUrl: 'detail.html',
controller: 'userdetail'
}).
otherwise({
redirectTo: '/404.html' /*>>>>>>Here is the problem<<<<<<*/
});
});
myApp.controller('userdetail', ['$scope', '$routeParams', 'userData', function($scope, $routeParams, userData){
var selectedUser = $routeParams.username;
selectedUser = selectedUser.replace(/-/g, ' ');
userData.userslist().then(function(data){
$scope.items = [];
angular.forEach(data.data.bst_users, function(item){
if(item.name == selectedUser) {
$scope.user = item;
};
})
})
}])
myApp.controller('userdetail', ['$scope', '$routeParams', 'userData', function($scope, $routeParams, userData){
console.log($routeParams.username);
userData.find($routeParams.username, function(found){
$scope.user = found;
})
console.log(scope.user)
}])
/*******Filters*******/
myApp.filter('removeSpace',function() {
return function(input) {
if (input) {
return input.replace(/\s+/g, '-');
}
}
});
Since you declared /:username as a route, it can match anything after the /, meaning the 404 route isn't really doing anything and the username route in a sense is acting as your catch-all route. This is kind of a weird case, since you can't really define a regular 404 route. But what you could do is have a /404 route, then if /:username doesn't resolve to a user, redirect them to /404. That is the most efficient method I can come up with, but I guarantee there's a better way to do it.
#Jordan points out a definite issue.
I would recommend updating your user detail path to something like the following:
when('/user/:username', {
templateUrl: 'detail.html',
controller: 'userdetail'
})
Just so there is no confusion between /random_username and /unmatched_path.
Related
I need to restrict the user from redirect and need to login only with authentication.
I tried but I can redirect to login page using back button and again come to same page using forward button. Even I can go to the required page using URL without login.
My code :
config.$inject = ['$routeProvider', '$locationProvider'];
function config($routeProvider, $locationProvider ) {
$routeProvider
.when('/login', {
controller: 'LoginController',
templateUrl: 'view/login.view.html',
controllerAs: 'vm'
})
.when('/profileData', {
controller: 'profileDataController',
templateUrl: 'view/profiledata.view.html',
controllerAs :'vm'
})
.when('/questionBank', {
controller: 'questionbankController',
templateUrl: 'view/questionbank.view.html',
controllerAs: 'vm'
})
.when('/dashboard', {
// controller: 'PersonalInfoController',
templateUrl: 'view/dashboard.view.html',
controllerAs:'vm'
})
.otherwise({ redirectTo: '/login' });
}
run.$inject = ['$rootScope', '$location', '$cookieStore', '$http'];
function run($rootScope, $location, $cookieStore, $http) {
// keep user logged in after page refresh
$rootScope.globals = $cookieStore.get('globals') || {};
if ($rootScope.globals.currentUser) {
$http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata; // jshint ignore:line
}
$rootScope.$on('$locationChangeStart', function (event, next, current) {
//redirect to login page if not logged in and trying to access a restricted page
var restrictedPage = $.inArray($location.path(), ['/dashboard','/questionBank', '/profileData']) === -1;
/* var a = $location.$$absUrl.split('#')[1];
var patt = new RegExp(a);
var res = patt.test(restrictedPage); */
var loggedIn = $rootScope.globals.currentUser;
if (restrictedPage && !loggedIn) {
$location.path('/login');
}
});
}
use this :based on response from server
.when('/login', {
controller: 'LoginController',
templateUrl: 'view/login.view.html',
resolve:{
logincheck: checklogedin
})
/ resolve function for user....
var checklogedin = function($q ,$http,$location)
{
var deferred =$q.defer();
$http.get('/loggedin').success(function(user){
if (user.staus==true)
{
//goo
deferred.resolve();
}
else
{
deferred.reject();
$location.url('/login');
}
});
return deferred.promise
};
Based on the code that you have provided, I can't tell 100% what is going on in your code. But... you could always try to use the resolve property on each route that you don't want to allow access without authentication. Here is what that would look like for questionBank:
.when('/questionBank', {
controller: 'questionbankController',
templateUrl: 'view/questionbank.view.html',
controllerAs: 'vm',
resolve: {
auth: function(AuthService, $q){
if(AuthService.isAuthenticated()) return $q.resolve();
return $q.reject();
}
}
})
Each property of the resolve object should return a promise, and if that resolves... the route change works. If it rejects... the route change is not allowed. If the promise never resolves, you are screwed, so make sure it resolves or it will never do the route.
This isn't the only way to try what you are saying. It is A way of trying it.
You can also add event listener on your $scope and prevent moving in case of unauthenticated user.
$scope.$on('$locationChangeStart', function (event, next, current) {
if (!is_logged_in) {
event.preventDefault();
}
});
In my code I have two main controllers LoginCtrl and AppCtrl, and all other controllers are nested within AppCtrl. Then in AppCtrl I have this code, which will check for logged user.
if (localStorageService.get('authToken') === null) {
$state.go('login', {locale: CONFIG.defaultLang});
} else if (!userService.isLoggedIn()) {
tokenStorage.setAuthToken(localStorageService.get('authToken'));
userService.setIdentity(JSON.parse(localStorageService.get('user')));
}
As you can see I store auth token from server in local storage. When page loades this code will be executed and if you are not logged in you will be redirected. And because all other application controllers are nested within AppCtrl this code will be executed every time.
For more info about nested controllers try for example this article - https://rclayton.silvrback.com/parent-child-controller-communication
I triggered the %a{"ng-click"=>"get_destinations(city)"}
However, it should redirect me to "destinations" controller, but it didn't
and there is no error in webconsole, what's going on ?
welcome.js.erb
var App = angular.module('App', ['ngRoute']);
App.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/depart_from/:id',
{
templateUrl: "<%= asset_path('promotion_destinations.html') %> ",
controller: 'destinations'
}
)
.otherwise({ redirectTo: '/depart_from/:id' });
}]);
App.controller("departure_cities", function($scope, $location, $http) {
$http.get("/promotion.json")
.success(function (response) {
$scope.departure_cities = response;
});
$scope.get_destinations = function(id) {
return $location.url("/depart_from/" + id);
};
});
App.controller("destinations", function($scope, $location, $http) {
$http.get("/another_city.json")
.success(function (response) {
$scope.destinations = response;
});
});
Your default controller is destinations in the $scope of destinations controller no any method like get_destinations .
Put your method in side destinations controller it will work if every thing is fine.
Well if you can link the html generated (the one that see the browser, not the server template) that would help.
However i still see an error for me in the HTML (or it's a naming problem)
get_destinations(city)
And in the javascript :
$scope.get_destinations = function(id)
Maybe you wanted to do this ?
get_destinations(city.id)
I am using ngRoute for reading the url parameters. The problem I have is that I can't get the ID while the code is running. However if try to call it as function I get values from url.
.controller('PageCtrl', function ($scope, $routeParams, Survey) {
$scope.survey = Survey.get({surveyId: $routeParams.id}); //doesn't work
this.add = function (pageId, pageIndex) {
console.log($routeParams.id); //works
};
$scope.Page = this;
}
Do you think there is the way of getting the url parameter while I am making the Survey.get() request ?
One way you could solve this would be to wait till the $routeChangeSuccess broadcast had been fired and then to initialise your $scope.survey.
i.e something like this
.controller('PageCtrl', function ($scope,$rootScope, $routeParams) {
$rootScope.$on('$routeChangeSuccess',function(){
$scope.survey = Survey.get({surveyId: $routeParams.id}); //doesn't work
});
this.add = function (pageId, pageIndex) {
console.log($routeParams.id); //works
};
$scope.Page = this;
}
Most likely your controller is called only once on the application startup. That's why your routeconfig isn't set yet and returns undefined. Are you sure you're specifying a controller to your view in your routeconfig?
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/home', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
}).
otherwise({
redirectTo: '/home'
});
}]);
I am trying to do an asynchronous http request to load some data before my app loads and so I am using a resolve in $routeProvider which is an http request in my MainController. For some reason, I keep getting Error: [$injector:unpr] Unknown provider: appDataProvider <- appData where appData is where I do my http request. I am using AngularJS v 1.2.5.
Here is the code and two methods that I tried that both give the same error:
Method #1
MainController.js
var MainController = ['$scope','$location','appData',
function($scope, $location, appData){
console.log(appData.data);
}
];
MainController.loadData = {
appData: function($http, $location, MainFactory){
var aid = MainFactory.extractAid($location);
return $http({method: 'GET', url: URL_CONST + aid});
}
};
app.js
var app = angular.module('HAY', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
redirectTo: '/pages/alerts'
})
.when('/pages/:pageName', {
templateUrl: function(params) {
return 'views/pages/' + params.pageName + '.html';
},
controller: MainController,
resolve: MainController.loadData
})
.otherwise({
redirectTo: '/pages/alerts'
});
});
I tried changing the name in case it was a conflicting system reserved keyword but with no luck. For some reason, appData is never recognized
Method #2
I also tried changing it around like so:
app.js
var app = angular.module('HEY', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
redirectTo: '/pages/alerts'
})
.when('/pages/:pageName', {
templateUrl: function(params) {
return 'views/pages/' + params.pageName + '.html';
},
controller: MainController,
resolve: {
appData: ['$http', '$location','MainFactory', function($http, $location, MainFactory) {
var aid = MainFactory.extractAid($location);
return $http({method: 'GET', url: URL_CONST + aid});
}]
}
})
.otherwise({
redirectTo: '/pages/alerts'
});
});
MainController.js
var MainController = ['$scope','$location','appData',
function($scope, $location, appData){
console.log(resolvedData);
}
];
However, the result was exactly the same. Does this have something to do with angular 1.2.5 ?
Here is a working version from someone else
http://mhevery.github.io/angular-phonecat/app/#/phones
And here is the code:
function PhoneListCtrl($scope, phones) {
$scope.phones = phones;
$scope.orderProp = 'age';
}
PhoneListCtrl.resolve = {
phones: function(Phone) {
return Phone.query();
},
delay: function($q, $defer) {
var delay = $q.defer();
$defer(delay.resolve, 1000);
return delay.promise;
}
}
angular.module('phonecat', ['phonecatFilters', 'phonecatServices', 'phonecatDirectives']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {templateUrl: 'partials/phone-list.html', controller: PhoneListCtrl, resolve: PhoneListCtrl.resolve}).
otherwise({redirectTo: '/phones'});
}]);
Here's an example of the code I've used in the application I'm working on, not sure it will help much because its not much different than how you have it already.
Routing
.when('/view/proposal/:id',{
controller : 'viewProposalCtrl',
templateURL : 'tmpls/get/proposal/view',
resolve : viewProposalCtrl.resolveViewProposal
})
Controller
var viewProposalCtrl = angular.module('proposal.controllers')
.controller('viewProposalCtrl',['$scope','contacts','details','rationale',
function($scope,contacts,details,rationale){
$scope.contacts = contacts;
$scope.details = details;
$scope.rationale = rationale;
// [ REST OF CONTROLLER CODE ]
});
// proposalSrv is a factory service
viewProposalCtrl.resolveViewProposal = {
contacts : ['$route','proposalSrv',function($route,proposalSrv){
return proposalSrv.get('Contacts',$route.current.params.id)
.then(function(data){
return data.data.contacts;
},function(){
return [];
});
}],
details : ['$route','proposalSrv',function($route,proposalSrv){
return proposalSrv.get('Details',$route.current.params.id)
.then(function(data){
return data.data.details;
},function(){
return {};
});
}],
rationale : ['$route','proposalSrv',function($route,proposalSrv){
return proposalSrv.get('Rationale',$route.current.params.id)
.then(function(data){
return data.data.rationale;
},function(){
return {};
]
}]
};
Now that I think about it, when I was developing my application I did have a problem and not sure why when I named my resolve function "resolve." This gave me a problem:
.when('/path',{
// stuff here
resolve : myCtrlr.resolve
})
but this did not:
.when('/path',{
//stuff here
resolve : myCtrlr.myResolveFn
})
Another Possibility
The only other thing I can think of, is that you're returning the promise from the $http call and then trying to use appData.data Try using the .then function or one of the other functions (.success,.error) to retrieve the information from the promise.
The problem was NOT due to previously using different version of AngularJS.
Here are the fixes using the code that I have above.
In app.js, you need to declare the controller as controller: 'MainController' and NOT as controller: MainController even though you have var MainController = app.controller('MainController', ....).
Second and biggest thing was that in my index.html I declared my controller already like so:
index.html
body ng-app="HEY" controller="MainController" /body
This was causing the whole Unknown provider error Apparently angular wont tell you that you have already declared the controller that you are using to do the resolve it and that that will cause a weird error that have nothing to do with the resolve.
I hope this helps someone who may have the same problem.
One thing I noticed in angular 1x docs is that YOU DO NOT SPECIFY THE RESOLVED PARAMETER AS AN ANNOTATED DEPENDENCY
So this:
.when('/somewhere', {
template: '<some-component></some-component>',
resolve: {
resolvedFromRouter: () => someService.fetch()
}
})
export default [
'$scope',
'someService',
'resolvedFromRouter'
Controller
]
function Controller($scope, someService, resolvedFromRouter) {
// <= unknown provider "resolvedFromRouter"
}
is wrong. You don't specify the resolved parameter as a dependency, in the docs:
For easier access to the resolved dependencies from the template, the resolve map will be available on the scope of the route, under $resolve (by default) or a custom name specified by the resolveAs property (see below). This can be particularly useful, when working with components as route templates.
So just do this instead:
.when('/somewhere', {
template: '<some-component></some-component>',
resolve: {
resolvedFromRouter: () => someService.fetch()
}
})
export default [
'$scope',
'someService',
Controller
]
function Controller($scope, someService) {
$scope.$resolve.resolvedFromRouter; // <= injected here
}
Is it possible to [execute a function] e.g. open a modal dialog window from the routeProvider when a certain route is requested?
myApp.config(function($routeProvider) {
$routeProvider
.when('/home',
{
controller: 'HomeCtrl',
templateUrl: 'Home/HomeView.html'
}
).when('/profile/:userId/changepwd',
function(){
$dialog.messageBox(title, msg, btns)
.open()
.then(function(result){
alert('dialog closed with result: ' + result);
});
}
).otherwise({ redirectTo: '/home' });
});
PS: I want to cancel a route and instead open a dialog box. Opening the dialog box is not the only issue. Cancelling the route is the major issue.
You can pass your function as dependency in resolve and it will wait until dependency is resolved and when your dialog ends then change the route and modify history as you wish using $location
var app = angular.module('myApp', [])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
template: ' ',
controller: //empty function,
resolve: {
data1 : function($dialog, $location) {
var promise = $dialog.messageBox(title, msg, btns)
.open()
.then(function(result){
alert('dialog closed with result: ' + result);
//Use [$location][1] to change the browser history
});
return promise;
}
}
});
}]);
Building on Rishabh's answer, and using sergey's location.skipReload from this Angular Issue you can use the following to create a dialog on route-change, defer the url-change indefinitely (in effect 'cancelling' the route change), and rewrite the URL bar back to '/' without causing another reload:
//Override normal $location with this version that allows location.skipReload().path(...)
// Be aware that url bar can now get out of sync with what's being displayed, so take care when using skipReload to avoid this.
// From https://github.com/angular/angular.js/issues/1699#issuecomment-22511464
app.factory('location', [
'$location',
'$route',
'$rootScope',
function ($location, $route, $rootScope) {
$location.skipReload = function () {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
return $location;
};
return $location;
}
]);
app
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/home', {
controller: 'HomeCtrl',
templateUrl: 'Home/HomeView.html'
})
.when('/profile/:userId/changepwd', {
template: ' ',
controller: '',
resolve: {
data1: function($dialog, location, $q){
$dialog.messageBox(title, msg, btns)
.open()
.then(function(result){
//fires on modal close: rewrite url bar back to '/home'
location.skipReload().path('/home');
//Could also rewrite browser history here using location?
});
return $q.defer().promise; //Never resolves, so template ' ' and empty controller never actually get used.
}
}
})
.otherwise({
redirectTo: '/'
});
This feels like it leaks unresolved promises, and there may be a neater solution, but this worked for my purposes.
You can redirect the route to the same partial. You can do this by watching for a change in route using the following code. You can also show a dialog from here.
$rootScope.$on( '$routeChangeStart', function(event, next, current) {
if ( next.templateUrl == "xyz.html" ) {
//other validation logic, if it fails redirect user to the same page
$location.path( "/home" );
}
});