Angular 1.5 Component Routing from Server Side - javascript

I am looking to upgrade angular version to 1.5 and trying to figure out how I can do routing in Angular 1.5 Component Routing. Currently, we are doing as following using old angular router:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when("/PP", {
templateUrl: function (route) {
var path;
var menuID = route.MenuID ;
$.ajax({
type: "POST",
async: false,
url: "./api/MyControllerName/MyControllerMethodName",
contentType: "application/json",
data: angular.toJson({
Action: 'NavigationManager.GetHtmlFilePath',
Data: { MenuID: menuID }
})
}).then(function (data) {
if (data.Success == true) {
var rte = $.parseJSON(data.Data);
path = rte.Route;
}
})
return path;
},
reloadOnSearch: false
})
.otherwise({ redirectTo: "/Home" });
}]);
The $.ajax call goes to server and gets the full path of the html file based on the MenuID from the url. Eventually content from this html file gets placed in ng-view.
All the examples of angular 1.5 component routing I have seen have hard coded path information as shown below:
angular.module('heroes', [])
.component('heroes', {
template: '<ng-outlet></ng-outlet>',
$routeConfig: [
{ path: '/', name: 'HeroList', component: 'heroList', useAsDefault: true },
{ path: '/:id', name: 'HeroDetail', component: 'heroDetail' }
]
})
My question is how do I replace the hard coded values with values coming from server just like I am doing with old angular router?

I had the same requirements. I had to set menus based on rights. My application is divided as a component tree. So, on login page, I set route registry as below:
class appOptions implements ng.IComponentOptions {
public controller: any;
public template: string;
public $routeConfig: any;
constructor() {
this.$routeConfig = [
{ path: '/', name: 'Login', component: 'login', useAsDefault: true },
{ path: '/workspace/...', name: 'Workspace', component: 'workspace' }
];
this.controller = appCtrl;
this.template = '<ng-outlet></ng-outlet>';
}
}
When user clicks on login button, I will get roles of users if authentication is passed. With successful authentication, server will pass JSON which will have list of permissions. Using that object to create routes. Calling below method in Login page
setRoute() {
this.myRoutes= this.routeService.getRoutes();
this.myRoutes.forEach((route) => {
this.$router.registry.config('workspace', route.route);
});
this.$router.navigate(['Workspace']);
}
routeService is the service which will actually generate routes
Now define interface based on parameter which are using for routing(eg:path, name, component, useAsDefault)
export interface IMyRoutes {
path: string;
name: string;
component: string;
useAsDefault: boolean
}
In controller of service:
public workspaceRoutes: app.IMyRoutes [] = []
getRoutes() {
this.accessProfile = this.userService.GetProfile();//This will get list of permission along with other details from server
if (this.accessProfile != null && this.accessProfile.Permissions.length > 0) {
this.accessProfile.Permissions.forEach((permission) => {
switch (permission) {
case "CanAccessMenu_1":
this.workspaceRoute = {
path: '/another_node_of_tree/...', name: 'Menu1', component: 'menu1', useAsDefault: (this.accessProfile.Role.toLowerCase() == "Role1")
}
this.workspaceRoutes.push(this.workspaceRoute);
break;
case "CanAccessMenu_2":
this.workspaceRoute = {
path: '/some_path/', name: 'Menu2', component: 'menu2', useAsDefault: (this.accessProfile.Role.toLowerCase() == "Role2")
}
this.workspaceRoutes.push(this.workspaceRoute);
break;
case "CanAccessMenu_3":
this.workspaceRoute = {
path: '/another_node_of_tree/...', name: 'Menu3', component: 'menu3', useAsDefault: (this.accessProfile.Role.toLowerCase() == "Role3")
}
this.workspaceRoutes.push(this.workspaceRoute);
break;
}
});
}
return this.workspaceRoutes;
}

Related

Angular - navigating to a url after logging in

For example I have a url and I input it on the browser https://developer.anduks.myproperties/#/myproperties/3664-S
If I’m not logged in, it should take me to the login page which is currently working on my end. But, after I login, it doesn’t take me to the link I inputed on the browser like the sample link
When I input the url in the browser and I am not logged in then redirect to login page . If I input the url on the browser and hit enter and then I logged in my account it should redirect to that url input.
Anyone has an idea how to implement the problem above? Thanks.
#auth.guard.ts code
export class AuthGuard implements CanActivate {
userProfile: any;
constructor(private authService: AuthService, private route: Router,) {}
public async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
const allowedUserRoles = this.getRoutePermissions(route);
return await this.checkPermission(allowedUserRoles);
}
private getRoutePermissions(route: ActivatedRouteSnapshot): Roles[] {
if (route.data && route.data.userRoles) {
return route.data.userRoles as Roles[];
}
return null;
}
private checkPermission(allowedUserRoles: Roles[]): Promise<boolean> {
return this.authService.getSession().then((session: boolean) => {
if (session) {
if (!allowedUserRoles) {
return true; // if no user roles has been set, all user are allowed to access the route
} else {
let userRoles = JSON.parse(localStorage.getItem("userRoles"));
if (this.authService.areUserRolesAllowed(userRoles, allowedUserRoles)) {
return true;
} else {
this.route.navigateByUrl('/transactions');
return false;
}
}
} else { return false; }
});
}
}
#app-routing.module.ts
const routes: Routes = [
{
path: '',
component: DashboardComponent,
canActivate: [AuthGuard],
children: [
{
path: 'properties',
loadChildren: () => import('./features/property/property.module').then(m => m.PropertyModule),
data: {
userRoles: [Roles.ADMIN, Roles.TRANSACTION_SUPER_USER, Roles.TRANSACTION_MANAGER]
},
},
{
path: 'settings',
loadChildren: () => import('./features/settings/settings.module').then(m => m.SettingsModule),
data: {
title: 'Settings',
userRoles: [Roles.ADMIN, Roles.TRANSACTION_SUPER_USER, Roles.TRANSACTION_MANAGER]
}
},
{
path: 'transactions',
loadChildren: () => import('./features/transactions/transactions.module').then(m => m.TransactionsModule),
data: {
title: 'Transactions',
userRoles: [Roles.BROKER, Roles.ADMIN, Roles.TRANSACTION_SUPER_USER, Roles.TRANSACTION_MANAGER]
}
},
]
},
{
path: 'login',
component: LoginComponent,
},
{
path:'**',
redirectTo: ''
}
];
#NgModule({
imports: [
RouterModule.forRoot(routes, {
useHash: true,
preloadingStrategy: PreloadAllModules,
}),
],
exports: [RouterModule]
})
I would create service BeforeAuthRedirectionService. It would have private property url and getter/setter. when you are returning false in canActivate guard ( when user is not logged in ) before user gets redirected to login page you have to save current url and set it in your service. after login happens you can acess that url again and redirect to that page.

Load component based on query param in AngularJS

I have a state in a component as follow.
.state('owner-details', {
parent: 'app',
url: '/vehical/sections/:sectionId/?custom_mode=preview',
data: {
authorities: ['owner'],
pageTitle: "Owner Details"
},
views: {
'content#': {
component: 'ownerDetails'
},
'breadcrumb#': {
component: 'breadcrumb'
}
},
resolve: {
}
});
I want to load the component if the query param custom_mode equals to preview.
Is this possible in AngularJS? If so: how can I do this?

How to add external link to Angular SPA Menu?

I'm using angular hottowel template for develop my web application. route config code file shown bellow.
(function(){
'use strict';
var app = angular.module('app');
// Collect the routes
app.constant('routes', getRoutes());
// Configure the routes and route resolvers
app.config(['$routeProvider', 'routes', routeConfigurator]);
function routeConfigurator($routeProvider, routes)
{
routes.forEach(function(r)
{
setRoute(r.url, r.config);
});
$routeProvider.otherwise({ redirectTo: '/' });
function setRoute(url, definition)
{
definition.resolve = angular.extend(definition.resolve || {}, {
prime: prime
});
$routeProvider.when(url, definition);
}
}
prime.$inject = ['datacontext'];
function prime(dc) { return dc.prime(); }
// Define the routes
function getRoutes()
{
return [
{
url: '/',
config: {
templateUrl: 'app/dashboard/dashboard.html',
title: 'dashboard',
settings: {
nav: 1,
content: '<i class="fa fa-dashboard"></i> Dashboard'
}
}
}, {
url: '/customers',
config: {
title: 'customers',
templateUrl: 'app/customer/customers.html',
settings: {
nav: 2,
content: '<i class="fa fa-calendar"></i> customers'
}
}
},
{
url: '/customer/:id',
config: {
title: 'customer',
templateUrl: 'app/customer/customerdetail.html',
settings: {}
}
}
];
}})();
I need to add external link to my menu as example www.google.com. how can i add another link to this route config like bellow.
{
url: 'www.google.com',
config: {
title: 'MyExternalLink',
settings: {}
}
}
This question looks similar to this post have a look
Using $routeProvider to redirect to routes outside of Angular

Angularjs 1.5 - CRUD pages and Components

I'm working in a small Angularjs 1.5 project and I'm quite new.
I have to create an object or edit an existing object and the template is the same, the only difference in the logic is the call to an http service for data retrieve in case of update.
I use ngRoute.
How can I do to use the same component for both operations ?
EDIT
JS COMPONENT CODE
angular.
module('editProject').
component('editProject', {
templateUrl: 'app/edit-project/edit-project.template.html',
controller:['$http','$routeParams', function EditProjectController($http,$routeParams) {
var self=this;
$http.get('rest/projects/' + $routeParams.id ).then(function(response) {
console.log(JSON.stringify(response.data));
self.project = response.data;
});
}
]
});
ROUTE CONFIG
angular.
module('myApp').
config(['$locationProvider', '$routeProvider',
function config($locationProvider, $routeProvider) {
$locationProvider.hashPrefix('!');
$routeProvider.
when('/projects', {
template: '<project-list></project-list>'
}).
when('/projects/:id', {
template: '<project-detail></project-detail>'
}).
when('/projects/edit/:id', {
template: '<edit-project></edit-project>'
}).
when('/projects/new', {
template: '<edit-project></edit-project>'
}).
otherwise('/projects');
}
]);
1. Quick fix
Simple solution would be using a conditional checking if the $routeParams.id param is defined, if so, then it need a request to feed the project informations, otherwise not.
if($routeParams.id){
$http.get('rest/projects/' + $routeParams.id ).then(function(response) {
console.log(JSON.stringify(response.data));
self.project = response.data;
});
}
2. Component Router
Even though the previous solution looks simple and functional, it might not be the best. A propper solution is to use a separate component for each route, but you can reuse the form part of it. Also, assuming that you are building a completelly component-based app you should use ngComponentRoute instead of ngRoute.
.component('app', {
template: '<ng-outlet></ng-outlet>',
$routeConfig: [
{path: '/projects', name: 'Projects', component: 'projectList', useAsDefault: true},
{path: '/projects/:id', name: 'Project Detail', component: 'projectDetail' },
{path: '/projects/edit/:id', name: 'Edit Project', component: 'editProject' },
{path: '/projects/new', name: 'New Project', component: 'newProject' }
]
});
Then you can create a project editor component and reuse it on both edit and new project page by just adding <project-editor-form project="{}" on-save="$ctrl.mySave()"></project-editor-form>. For example:
.component('projectEditorForm', {
template:
'Project Name: <input type="text" ng-model="$ctrl.project.name">' +
'<button ng-click="$ctrl.onSaveProject($ctrl.project)">Save</button>',
bindings: {
project: '<',
onSave: '&'
},
controller: function () {
var $ctrl = this;
$ctrl.onSaveProject = function (project) {
// general save logic goes here
// if you want to reuse this too
// then emit the on save for onSave binding
$ctrl.onSave($ctrl.project);
}
},
})
.component('editProject', {
template:
'<project-editor-form project="$ctrl.project" on-save="$ctrl.mySave()">' +
'</project-editor-form>',
bindings: {
project: '<',
onSave: '&'
},
controller: function ($http) {
var $ctrl = this;
// consider using a Service to do such task
// instead of request directly from the controller
$http.get('rest/projects/' + $routeParams.id).then(function(response) {
$ctrl.project = response.data;
});
$ctrl.mySave = function (project) {
// save logic here
}
},
})
3. ngRoute with resolve
Another approach that doesn't deppend on ngComponentRoute, is to use the route resolve property, it's very usefull when using component as route template. You add a resolve property to your route, that would be the project, and bind to your form component.
$routeProvider
.when('/projects/edit/:id', {
template: '<project-editor-form project="$resolve.project"></project-editor-form>',
resolve: {
project: function ($route, $q) {
var id = $route.current.params.id;
// again, consider using a service instead
return $http.get('rest/projects/' + id).then(function (response) {
return response.data;
});
}
}
})
.when('/projects/new', {
template: '<project-editor-form project="$resolve.project"></project-editor-form>',
resolve: {
project: {
id: 0,
name: ''
}
}
})

Angular 1.x - Pass component state resolve data to other component

I have a dummy component based application, which has the following components:
- App
-- Page
---- Breadcrumb
What i want is to pass the Page resolve data to the Breadcrumb.
This is how the Page config looks like:
$stateProvider.state('page', {
url: '/page',
component: 'page',
resolve: {
routes: ($stateParams) => {
"ngInject";
return [
{url: "/", name: "Home"},
{url: "/page", name: 'Page'}
];
}
}
})
The Page controller:
class PageController {
constructor($stateParams) {
"ngInject";
this.themeColor = "#ff8fd1";
// When i use static data it's works fine..
//this.routes = [
// {url: "/", name: "Main page"},
// {url: "/page", name: 'Sub page'},
//];
this.routes = $stateParams.routes;
}
}
And this is my Breadcrumb component:
let breadcrumbComponent = {
restrict: 'E',
bindings: {
themeColor: "<",
routes: "<"
},
template,
controller
};
The DOM of the Breadcrumb component:
<breadcrumb theme-color="$ctrl.themeColor" routes="$ctrl.routes"></breadcrumb>
Everytime the routes are undefined when i want to define it from the Page controller resolve method.
How do i wait the data, or bind the Breadcrumb again when the data arrives?
One simple way is to use ngIf directive to render breadcrumb component only when routes are resolved:
<breadcrumb
ng-if="$ctrl.routes"
theme-color="$ctrl.themeColor"
routes="$ctrl.routes"></breadcrumb>
I figured out.
If you're want to pass resolve data to your component, or an other you have to set the resolve data as binding in the parent component as well.
// page.component.js
let pageComponent = {
restrict: 'E',
bindings: {
routes: "<"
},
template,
controller
};

Categories