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?
Related
Im using Angular 1.5.6 and am using AngularUI Router (https://github.com/angular-ui/ui-router). I have different routes e.g. customer and users. In each of these there are different 'sub-roots' e.g. one for list and one for edt. Im setting up the customer route here:
import customerListModule from './list/customer.list';
import customerServiceModule from './services/customer.service';
...
...
function customerModule($stateProvider, $urlRouterProvider) {
'ngInject';
$urlRouterProvider
.when('/customer', ['$state', function($state) {
$state.go('customer.list.tracked');
}]);
$stateProvider
.state('customer', {
parent: 'root',
url: '/customer',
abstract: true,
views: {
'root#app': {
template: '<div class="customer" ui-view=""></div>'
}
},
onEnter: () => {
// in here I want to change my customer servce
},
})
.state('customer.list', {
url: '',
views: {
'#customer': {
template: '<customer></customer>'
}
},
breadcrumbs: {
name: 'customer.breadcrumbs.list'
},
params: {
saving: false
}
})
.state('customer.edit', {
parent: 'customer.list',
url: '/:id/edit',
views: {
'#customer': {
template: editTemplate(),
controller: manageCustomerCtrl,
controllerAs: 'manageCustomerVM'
}
},
breadcrumbs: {
name: 'customer.breadcrumbs.edit'
},
resolve: {
isAuthorized: 'readWriteAccess'
},
bodyClass: 'product-form'
});
}
export default angular.module('customerAdminUI.customer', [
'ui.bootstrap',
'ui.router',
customerListModule.name,
customerServiceModule.name,
...
...
])
.config(customerModule);
I have a customer service which I want to access in the onEnter callback of the customer state. I tried to inject it into the customerModule method so that I can use it in the onEnter() callback:
function customerModule($stateProvider, $urlRouterProvider, CustomerService) {
...
...
$stateProvider
.state('customer', {
parent: 'root',
url: '/customer',
abstract: true,
views: {
'root#app': {
template: '<div class="customer" ui-view=""></div>'
}
},
onEnter: () => {
CustomerService.clearSearch();
},
})
However I get the error:
Unknown provider: CustomerService
How can I use a service in the onEnter callback?
We can ask for a service as a param
// not ready for minification
onEnter: function(CustomerService) {
CustomerService.dowhatneeded...
},
// preferred way
onEnter: ['CustomerService', function(service) {
service.dowhatneeded...
}],
In my Angular project I have some components which loads in parent component and Angular UI Router state. I send the "fields' variable in Page Component.
index.js
...
angular.
module('generalApp').
config(['$stateProvider',
function config($stateProvider) {
$stateProvider
.state('settings', {
url: '/settings',
component: 'page',
resolve: {
type: function() {
return "form";
},
fields: function() {
return require("./data/settingsFields.json");
}
}
})
}
]);
...
page.component.js
...
angular.
module('page').
component('page', {
bindings: {
type: '#',
fields: '<'
},
template: '...<form-page ng-if="$ctrl.type"></form-page>...',
controller: [function PageController() {
...
}
]
});
...
and formPage.component.js
...
angular.
module('formPage').
component('formPage', {
bindings: {
fields: '<'
},
template: require('./formPage.template.html'),
controller: [function formPageController() {
...
}]
});
...
I can to get "fields" variable in Page Component and I want to get it in nested FormPage Component. What I should do for this?
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;
}
I'm using angularjs with ui-router (with the helper stateHelperProvider) to collect views and controllers into the page.
But got a problem with my views not updating.
My code (the one that is related)
config.js
app.config(function($httpProvider, $urlRouterProvider, RestangularProvider, stateHelperProvider) {
$urlRouterProvider.otherwise("/");
stateHelperProvider
.state({
name: 'division',
url: '/division/:division',
views: {
'main': {
templateUrl: '/templates/division.main?uri=' + segment(2),
controller: 'DivisionController'
}
},
children: [
{
name: 'appcontent',
url: '/content',
views: {
'content': {
templateUrl: "templates/division.appcontent?uri=" + segment(2) + '&root=' + segment(4),
controller: 'AppContentController'
}
},
children: [
{
name: 'root',
url: '/:root',
views: {
'roots': {
templateUrl: "templates/division.appcontent.roots?uri=" + segment(2) + '&root=' + segment(4)
}
}
}
]
}
]
});
});
the code I use for linking
// linking to another division
<a ui-sref="division.appcontent({division: 'test2')">test2</a>
// linking to another root
<a ui-sref="division.appcontent.root({division: 'test2', root: 'test')">test2</a>
Explaining
But got a problem with my views not updating.
My views are the one with the actual data, so I need them to reload on change.
Like when :division in url is test1, then the template template/division.main have one set of data. But when :division in url is test2, then the template template/division.main have another set of data.
So whenever :division in url changes, I need to reload the template template/division.main and as well all the child templates.
But when :root changes in the url, I only need to reload the template template/division.appcontent.roots and not the template/division.main template.
Is this possible somehow or should I change to use only an API in order to get data.
I really hope this makes sense.
Note
segment is a function I have made to get some data from the angular route.
Thanks to the comment from #ChrisT I managed to get it to work using templateUrl as a fucnction.
My new config.js:
app.config(function($httpProvider, $urlRouterProvider, RestangularProvider, stateHelperProvider) {
$urlRouterProvider.otherwise("/");
stateHelperProvider
.state({
name: 'division',
url: '/division/:division',
views: {
'main': {
templateUrl: function(params) {
return '/templates/division.main?uri=' + params.division;
},
controller: 'DivisionController'
}
},
children: [
{
name: 'appcontent',
url: '/content',
views: {
'content': {
templateUrl: function(params) {
return 'templates/division.appcontent?uri=' + params.division + '&root=';
},
controller: 'AppContentController'
}
},
children: [
{
name: 'root',
url: '/:root',
views: {
'roots': {
templateUrl: function(params) {
return 'templates/division.appcontent.roots?uri=" + params.division + '&root=' + params.root;
}
}
}
}
]
}
]
});
});
I have now tried whole day and i cant figure out how i shall solve this issue.
My goal is to display a sidebar thats get filled with data based on what state it is.
Lets say i am on the home page i may like this items:
Home item 1
Home item 2
And if i am on the about page i want this items:
About me
About my dog
I would like the data to get fetched from a service that returns data to the view based on what state it is.
I have tried to use ui.router's resolve function but i can't get the correct structure in my head to make it work.
Created a plunkr that shows how i mean but without the solution, what are the best practices and preferred ways when creating a dynamic sidebar with Angular and ui.router?
myapp.config(function($stateProvider) {
$stateProvider
.state('home', {
url: "",
views: {
"content": {
template: "This is the home.content"
},
"sidebar": {
templateUrl: 'sidebar.html',
controller: 'sidebarCtrl'
}
}
})
.state('about', {
url: "/about",
views: {
"content": {
template: "This is the about.content"
},
"sidebar": {
templateUrl: 'sidebar.html',
controller: 'sidebarCtrl'
}
}
})
})
Plunkr here
Edit
Can't figure out what i am doing wrong, no view is shown with this code:
app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
// For any unmatched url, redirect to root
$urlRouterProvider.otherwise("/");
$stateProvider
.state('root', {
url: '',
'abstract': true,
views: {
'sidebar#': {
templateUrl: '/App/Main/views/shared/sidebars/sidebar.cshtml',
controller: 'app.controllers.views.shared.sidebars.sidebar',
resolve: {
sidebarData: function (sidebarService) {
return sidebarService.getActions();
}
}
}
},
})
.state('root.home', {
url: "/",
views: {
'': {
templateUrl: '/App/Main/views/home/home.cshtml',
controller: 'app.controllers.views.home'
},
'content#root.home': {
templateUrl: '/App/Main/views/home/home-content.cshtml',
controller: 'app.controllers.views.home'
}
}
})
.state('root.about', {
url: "/customers",
views: {
'': {
templateUrl: '/App/Main/views/customers/customers.cshtml',
controller: 'app.controllers.views.customers'
},
'content#root.about': {
templateUrl: '/App/Main/views/customers/customers-content.cshtml',
controller: 'app.controllers.views.customers'
}
}
});
}]);
and here is how my home and customer views look like:
<div data-ui-view="sidebar">
Loading sidebar view.
</div>
<div data-ui-view="content">
Loading content view.
</div>
you could try to implement named and also an abstract view for your sidebar to reuse it among your other routes, also you can use the resolve parameter an return whatever dynamic data you need (from a service, resource, whatever), it could be something like this:
var myapp = angular.module('myapp', ["ui.router"])
myapp.config(function($stateProvider) {
$stateProvider
.state('root',{
url: '',
abstract: true,
views: {
'sidebar#': {
templateUrl: 'sidebar.html',
controller: 'sidebarCtrl',
resolve:{
sidebarData:function(){
return [{
state: '/stateHere',
text: 'Need'
}, {
state: '/stateHere',
text: 'to'
}, {
state: '/stateHere',
text: 'fill'
}, {
state: '/stateHere',
text: 'this'
}, {
state: '/stateHere',
text: 'with'
}, {
state: '/stateHere',
text: 'dynamic'
}, {
state: '/stateHere',
text: 'data'
}];
}
}
}
})
.state('root.home', {
url: "/",
views: {
'content#': {
template: "This is the home.content"
}
}
})
.state('root.about', {
url: "/about",
views: {
'content#': {
template: "This is the about.content"
}
}
})
});
myapp.controller('sidebarCtrl', ['$scope','sidebarData'
function($scope,sidebarData) {
$scope.sidebarData= sidebarData,
}
]);
EDIT:
check this working example:
http://plnkr.co/edit/Nqwlkq1vGh5VTBid4sMv?p=preview