Loading different controllers with the same conditional URL - javascript

I'm using MEAN and I'm trying to redirect the user to different pages (different controllers as well) using a conditional URL like www.domain.com/#!/:path
I'll explain myself a little more better.
I've got three different packages (users, organizations and events), but all the packages can be accessed by the same parametrized URL (www.domain.com/#!/:path). Path is a field stored in database and each record belonging to each package has its own path. Path is unique, of course.
What i want to do is to detect if the URL the user is visiting belongs to users, organizations or events, for loading the proper page. For that, I have to query the database for checking if that :path is stored in users, organizations or events model. According to the result of that query, just redirecting to the proper controller/page.
I don't know how to accomplish that exactly in AngularJS side. Any suggestion?
Thanks in advance!
SOLUTION:
Finally, i got it working doing something like this:
// states for my app
$stateProvider
.state('home', {
url: '/',
templateUrl: 'system/views/index.html'
})
.state('entity', {
url: '/:path',
template: 'Loading...',
controller: function ($scope, Global, $http, $state, $stateParams) {
$http({
method: 'GET',
url: '/checkUrl/' + $stateParams.path
})
.then(function (result) {
$scope.global = Global;
// Doing entity information accesible globally
$scope.global.entity = result.data.info;
// Redirecting to the proper controller/template
switch ( result.data.type ) {
case 'users':
$state.go('user', {reload: true});
break;
case 'organizations':
$state.go('organization', {reload: true});
break;
default:
};
});
}
})
.state('user', {
url: '',
templateUrl: 'users/views/index.html'
})
.state('organization', {
url: '',
templateUrl: 'organizations/views/index.html'
});
Through /checkUrl/:path a request is made to server side for checking if :path belongs to users, organizations or events. The response contains the info of that entity and the kind (user, organization, event).
From there, it's just redirecting according to the entity matched.

Related

Initialize Current User Service on Application Start in AngularJS

I’m developing a Single Page Application with AngularJS.
When a user successfully logs in, a security token is stored in a cookie. Now, when he refreshes the page, the token will be sent to the backend, which returns a JSON object "currentUser" containing all the relevant information about the current user (as name, access-groups, profile picture, etc.).
The problem is, this is an asynchronous process of course, so when the controller starts another operation, say, just alerting the user’s name, this value will be undefined at that time.
Of course, I could set a timeout but is there a better solution?
I thought about a "currentUserService", which initializes first (sending the cookie and filling the user information with the backend response) and can only be processed after this initialization is completed.
But how can this be done? Or are there any other possibilities?
edit:
Hi guys,
thanks for the input!
Both of your suggestions seem to be very promising for asynchronous requests in general, but I think they might not fit perfectly for my concern:
The information about the current user only have to be requested once, so I would like to store them for the whole application (e.g. in the rootScope or a service) accessible from any controller without having to request them again in every controller (as in the callback or resolve-solution) but make sure that there won’t be any „timeout“ problems. Do you have any ideas?
You can resolve the user's data before the view loads either with ng-route or ui-router:
This example is written for ui-router:
.state('profile', {
url: '/profile',
controller: 'profileCtrl as vm',
resolve: {
user: function(AuthService) {
//Return a promise or an object to be resolved.
return AuthService.getUserFromToken(); //Say this is asynchronous and returns a promise
}
}
});
//In controller:
.controller('profileCtrl', function(... , user) {
//User data available here
this.user = user;
});
Please note if any errors arise during the resolve stage the state will not be loaded so you'll have to take care of the errors!
If a user refreshes you have to initialize everything. I assume the token is stored in localstorage or something and I assume this is angular 1.*. To do this I think you should call user-related functions from your http call-callback:
$scope.user = {};
$scope.getUser = function(){
$http({
method: 'GET',
url: '/someUrl'
}).then(function (res) {
$scope.user = res.data; //or whatever the response is
$scope.handleUserRelatedThings();
}).catch(function(err) {
//handle error
})
}
$scope.handleUserRelatedThings = function(){
//do things with $scope.user
alert($scope.user.name);
}
//on init
$scope.getUser();

Cannot GET - Error After refresh using Ionic

I'm using Ionic framework to build a hybrid mobile application and I have html5Mode set to true, Ui-Router, and gulp to provide me with livereload, sass compiling, css and javascript minifying.
The problem is whenever I navigate to a state directly from the index, everything works fine, requests are being made to my server, but when I refresh that same state, I get Cannot GET error.
I am treating my Ionic application as a separate thing from my Express.JS app.
Here's some code:
States
$stateProvider
.state('faculties', {
url: '/',
templateUrl: 'views/main/main.html',
controller: 'MainCtrl as main'
})
.state('faculty', {
url: 'faculties/:faculty',
templateUrl: 'views/faculty/faculty.html',
controller: 'FacultyCtrl as v'
})
So, if I opened the page and clicked on the button that takes me to the 'faculty' state, It's all good. But if I refresh that page, it's giving me that Cannot GET error.
Here's the code from the 'faculty' state controller:
app.controller('FacultyCtrl', function ($http, $stateParams, appConfig) {
var v = this;
var api = appConfig.api;
v.faculty = {};
$http.get( api + '/faculties/' + $stateParams.faculty)
.then( res => {
v.faculty = res.data;
}).catch( error => {
console.log(error);
});
});
The problem you are having is that you do not route all possible urls to the same index.html
When you first load the page, say, the URL being http://example.com/, your web server will serve the static file index.html from your root. When changing the route, your URL ends up as (for example) http://example.com/some_page. This works because the URL is "faked", there is no such file on the server. When refreshing (or going to that URL directly), that URL is requested from the server, which fails (since, as before, that file/folder does not exist).
What you need to do is route all requests (excluding API and whatnot) to the same static index.html, this is standard behavior of all single-page apps:
The routing is done clientside.

401 error angular routing

I have been driving myself crazy. Hoping one of you can help me out here...
Let me give you some background:
I have an ASP.NET web app that uses AngularJS.
Here is what my Controller looks like:
public ActionResult Index()
{
return View();
}
Ultimately this loads my HomePage and everything comes up great. However when I click a link for example:
<a ui-sref="core.applications">My Apps</a>
It prompts me to enter in a Username and Password. Even though this should be set for anonymous access.
Now if I open a new tab and go directly to that page for example: http://localhost/#/core/applications this loads just fine.
Looking at my routes:
app.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {
$urlRouterProvider.otherwise('/core/dashboard');
$stateProvider
.state('core', {
url: '/core',
views: {
'': { templateUrl: 'app/core/views/core.html' },
'sidebar#core': {
templateUrl: 'app/core/views/sidebar.html'
},
'content#core': {
templateUrl: ''
}
}
})
.state('core.dashboard', {
url: '/dashboard',
views: {
'content#core': {
templateUrl: 'app/core/views/dashboard.html'
}
}
})
.state('core.applications', {
url: '/applications',
views: {
'content#core': {
templateUrl: 'app/core/views/applications.html'
}
}
})
});
I do not see what could be blocking it and prompting it to load a Username and Password. Is it something to do with ASP.NET Routing? Please help!
I actually figured out the issue.
The issue was related to the Web API call that I do that I pass security credentials and if the credentials end up being repeated too quickly my system blocks them... (dumb enterprise security guys)
Long story short - check if you are calling a 3rd party service this could prevent you from accessing those pages.

AngularJS routing causing issues with server calls

I am using AngularJS in a nodewebkit application.
I have three views:
Home.html
Conversation.html
Login.html
On login, I am calling
$state.go('home.main');
which calls
$stateProvider.state('home.main', {
url: '/home',
views: {
"mainContent": {
templateUrl: 'views/home.html',
controller: 'loginController'
}
}
}
In main html, I am making a server call (through socket.io) to get all conversations.
Since data is huge, it takes some time to load it and in this time gap i.e. before user gets response from server, If user clicks on Logout, It takes user back to login page.
$scope.logout = function(){
//Logout Logic
$state.go('login');
}
i.e. it calls
$stateProvider.state('login', {
url: '/login',
templateUrl: 'views/login.html',
controller: "loginController"
});
Now When a user is trying to login, server responds to call made for getting conversations allowing user to take him to /home/conv.html.
I don't want to disable Logout button while data is being sent from server to client.
Is there any way on routing from /home to /login, we can cancel all server calls?
I copied the code from https://github.com/angular-ui/ui-router/wiki:
$stateProvider.state("contacts", {
template: '<h1>{{title}}</h1>',
resolve: { title: 'My Contacts' },
controller: function($scope, title){
$scope.title = 'My Contacts';
},
onEnter: function(title){
if(title){ ... do something ... }
},
onExit: function(title){
if(title){ ... do something ... }
}
})
The onExit event will be triggered when you move from home.main to another route. So you should register to handle the event at where you declare the home.main route. In this event, you can cancel all server calls. As you are using socket.io, I suggest you use the function socket.removeAllListeners();

Angularjs: Interceptor redirection creates double rendering

I am stuck with this strange behaviour. None of the Google hits seem to return any mention of a similar case so I am assuming that I am doing something seriously wrong.
My interceptor does react on the 401 status and redirects to the appropriate route but at the same time it renders the previous route too. So I have a very ugly flash of one template then the other. I am simply trying to test my authentication: if authenticated then render the table, otherwise render the login form. It does redirect to the login form but still flashes the table template for a fraction of a second.
angular.module('Basal', ['ngRoute', 'Basal.users'])
.config(function($routeProvider, $locationProvider, $httpProvider) {
$locationProvider.html5Mode(true);
$httpProvider.interceptors.push('authInterceptor');
$routeProvider.
when('/', {
templateUrl: '/tpl/table.html',
controller: 'MainCtrl'
}).
when('/login', {
templateUrl: '/tpl/login-form.html',
controller: 'MainCtrl'
}).
otherwise({
redirectTo: '/'
});
});
angular.module('Basal.users', [])
.controller('MainCtrl', function($scope, getJson) {
getJson.fetch(function (d){
$scope.computers = d;
});
})
.factory('getJson', function($http, $location) {
return {
fetch: function (c) {
$http.get("/json")
.success(function(data) {
console.log("getJson: Success!");
c(data);
})
.error(function() {
console.log("getJson: Failure!");
});
}
}
})
.factory('authInterceptor', function($q, $location) {
return {
'responseError': function(response) {
if (response.status === 401) {
$location.path('/login');
}
return $q.reject(response);
}
}
});
Now, when I hit '/' on the browser Angular does two requests on the background: one is to fetch the table template and insert it in to the view and the other is to get the JSON data.
On the server side I put session restriction only on the data request! The template is just a static file. To put restriction on the template I need to drag it through the server routing and this is not, I believe, how Angular does things. But if I do create server side route for the template and put session restriction on it then double rendering disappears.
I am confused about how this works. Fetching the template and fetching the data is done asynchronously in parallel. So while JSON request triggers 401 and redirects to the login template, the original table template is still going through and being rendered empty. Hence I get all the ugly double rendering. This is a race of some kind. How do I stop it? Maybe my interceptor is wrong? Isn't the Angular interceptor supposed to stop any further processing?
As a related issue, the otherwise function on the $routeProvider does not work either. If I put a non-existent URL, I get 404 from the server but Angular routing does not catch it. Is this how it is supposed to be? If a URL change happens in Angular and then I hit reload on the browser, I get an ugly 404 instead of a nice redirect. Am I supposed to handle 404 in an interceptor too? Then what is the point of otherwise?
Thanks.

Categories

Resources