How to map a segment of a route to routeParams? - angularjs

Lets say I have two routes defined, served by the same view and controller, such as
/customers/:cutomerId/edit
/customers/add
in a controller I need to determine in which "mode" is view in. How do I map "edit" and "add" segments of the route so that it appears in $routeParams. Is there a way?

You may user route's resolves to solve it.
For example:
myApp.config(function($routeProvider) {
$routeProvider
.when('/customers/:cutomerId/edit', {
templateUrl: 'myView.html',
controller: 'MyController',
resolve: {
mode: function() {
return 'edit';
}
}
})
.when('/customers/add', {
templateUrl: 'myView.html',
controller: 'MyController',
resolve: {
mode: function() {
return 'add';
}
}
});
myApp.controller('MyController', function($scope, mode){
// Now controller knows it's mode.
});

Related

Using resolve functions once in angular js and angular router to few controllers

Ui router looks like:
<div ui-view="test1">
<div ui-view="test2">
My routing:
.state('testsPage', {
url: "/",
// templateUrl: "public/src/settings/settings.php",
views: {
'test1': {
templateUrl: 'public/src/test2.html',
controller: 'test2Controller',
controllerAs: 'vm',
resolve: {
getData: function(testService) {
return testService.getdata();
}
}
},
'test2': {
templateUrl: 'public/src/test1.html',
controller: 'test1ontroller',
controllerAs: 'vm',
resolve: {
getData: function(testService) {
return testService.getdata();
}
}
},
I want to call getData only once and not inject it the each controller
If I do that in each controller it means that I call to getData from server two times in loading.
I tried to use controller inheritance but it ask to inject that service
// Inherit from Base Controller
angular.extend(vm, $controller('baseController', {
getData: getData,
testService: testService,
$rootScope: $rootScope
}));
How can I make it like inheritance?
Do I need to move it to run the function? If yes do I have to use rootScope to get that data in the controller?
Try putting the resolve on the parent:
.state('testsPage', {
url: '/',
views: ...,
resolve: {
getData: function(testService) {
return testService.getdata();
}
}
...
}
You would then need to add getData as a dependancy on each views controller:
// Controller
function test1ontroller(getData) {
}

Determine Angularjs Controller based on route params

I have the following configuration for my route:
$routeProvider.when('/', {
controller: 'homeController',
templateUrl: 'app/views/main/home.html'
})
.when('/:section/:tree', {
templateUrl: function($routeParams) { return 'App/Views/'+$routeParams.section+'/'+$routeParams.tree+'.html'; },
controller: function ($routeParams) { return $routeParams.tree + 'Controller'; }
})
.otherwise({
redirectTo: '/'
});
}
The view is loaded correctly but without controller and the controller function is not even called.
Is there any way to solve this issue or determine the controller based on route params.
The controller function is not a function returning the controller name. It's supposed to be the controller itself.
Let's suppose the tree route param can be Foo or Bar, you just need
.when('/:section/Foo', {
templateUrl: function($routeParams) { return 'App/Views/'+$routeParams.section+'/Foo.html'; },
controller: 'FooController'
})
.when('/:section/Bar', {
templateUrl: function($routeParams) { return 'App/Views/'+$routeParams.section+'/Bar.html'; },
controller: 'BarController'
})
This, BTW, will avoid your application to cause an exception is the user enters something other than Foo or Bar in the URL.
If you have many similar routes, just use a loop to define them:
['Foo', 'Bar', 'Baz', 'Brr', ...].forEach(function(tree) {
$routeProvider.when('/:section/' + tree, {
templateUrl: function($routeParams) { return 'App/Views/' + $routeParams.section+'/' + tree + '.html'; },
controller: tree + 'Controller'
});
});

Access parent controller from the child state

I have a controller in AngluarJS defined like so:
'use strict';
var app = angular.module('app');
app.controller('AppCtrl', ['sth',
function (sth) {
this.inverse = false;
}
]);
here is routes deffinition:
$stateProvider.
state('app', {
abstract: true,
templateUrl: 'app/views/layout.html',
controller: 'AppCtrl',
controllerAs: 'app',
resolve: {}
}).
state('app.settings', {
abstract: true,
url: '/settings',
template: '<ui-view/>',
onEnter: function () {
}
});
How to access inverse variable from AppCtrl in app.settings route?
If you want to share data between 2 controllers, a service/factory is your best bet. Below is a an example of how you would do it. I have written it free-hand, so there may be syntax errors, but you get the idea.
app.controller('AppCtrl', ['sth', 'SharedData',
function (sth, SharedData) {
SharedData.inverse = false;
}
]);
app.factory('SharedDate', function() {
var data = {
inverse: true // or whatever default value you want to set
};
return data;
})
Now, you can inject SharedData factory in any controller, where you want to use that data.

How To Autoload ui-view on nested views?

I have code like this
<a ui-sref="nested.something">something</a>
<div ui-view="nested.something"></div>
how to load ui-view without click ui-sref ?
EXTEND - related to this plunker provided by OP in the comments above
The state definition is:
.state('store', {
views: {
'store': {
templateUrl: 'store.html'
}
}
})
.state('store.detail', {
views: {
'store_detail': {
templateUrl: 'store_detail.html'
}
}
})
Then in this updated plunker we can see that this would do the job
//$urlRouterProvider.otherwise('/store');
$urlRouterProvider.otherwise(function($injector, $location){
var state = $injector.get('$state');
state.go('store.detail');
return $location.path();
});
Reason? states do not have defined url. Which is a bit weird. So, I would honestly rather suggested to do it like this (the link to such plunker):
$urlRouterProvider.otherwise('/store/detail');
//$urlRouterProvider.otherwise(function($injector, $location){
// var state = $injector.get('$state');
// state.go('store.detail');
// return $location.path();
//});
$stateProvider
.state('store', {
url: '/store',
views: {
'store': {
templateUrl: 'store.html'
}
}
})
.state('store.detail', {
url: '/detail',
views: {
'store_detail': {
templateUrl: 'store_detail.html'
}
}
})
There is a working plunker
ORIGINAL
We can use the .otherwise(rule) of $urlRouterProvider, documented here
$urlRouterProvider.otherwise('/parent/child');
As the doc says:
otherwise(rule)
Defines a path that is used when an invalid route is requested.
So, this could be used for some default - start up "redirection"
The .otherwise() could be even a function, like shown here:
How not to change url when show 404 error page with ui-router
which takes '$injector', '$location' and can do even much more magic (on invalid or startup path)
$urlRouterProvider.otherwise(function($injector, $location){
var state = $injector.get('$state');
state.go('404');
return $location.path();
});
ALSO, if we want to fill in some more details into some nested viesw, we can do it by defining multi-named views:
.state('parent.child', {
url: "/child",
views: {
'' : {
templateUrl: 'tpl.child.html',
controller: 'ChildCtrl',
},
'nested.something#parent.child' : {
templateUrl: 'tpl.something.html',
},
}
})
So, if the tpl.child.html will have this anchor/target:
<i>place for nested something:</i>
<div ui-view="nested.something"></div>
it will be filled with the tpl.something.html content
Check it in action here

Angular ui-router resolve not working

I am trying to load a get service JSON function in the main state resolve function so I can store the data to a scope variable.
The account JSON information is relevant because all sub pages are essentially dependent on the information.
--
The below code is partially working. The account resolve function is being successfully called and even the $http returns a promise (state === 0 though). The issue is when the account function resolves the state.controller is never being called.
$stateProvider
.state('app',{
url: '/',
views: {
'header': {
templateUrl: '../views/templates/partials/header.html',
},
'content': {
templateUrl: '../views/templates/partials/content.html'
},
'footer': {
templateUrl: '../views/templates/partials/footer.html',
}
},
resolve: {
account: function($timeout, accountFactory){
//Comment
return $http({method: 'GET', url: '/account.json'});
}
},
controller: ['$scope', 'account', function($scope, account){
// You can be sure that promiseObj is ready to use!
$scope.data = account;
console.log('SCOPE!!!!!');
}],
})
.state('app.accessory', {
url: 'accessory',
views: {
'content#': {
templateUrl: '../views/accessory/listing.html',
controller: 'accessoryListingCtrl',
controllerAs: 'vm'
}
}
})
}]);
Your parent state config is not correct. When using multiple named views A controller does not belong to a state but to a view, so you should move your controller statement to the specific view declaration, or all of them if you need it everywhere.
See here: https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
$stateProvider
.state('report',{
views: {
'filters': {
templateUrl: 'report-filters.html',
controller: function($scope){ ... controller stuff just for filters view ... }
},
'tabledata': {
templateUrl: 'report-table.html',
controller: function($scope){ ... controller stuff just for tabledata view ... }
},
'graph': {
templateUrl: 'report-graph.html',
controller: function($scope){ ... controller stuff just for graph view ... }
},
}
})
I don't know why the controller does not get called. But you can start by making sure that resolve always return data.
resolve: {
account: function($timeout, accountFactory){
//Comment
return $http({method: 'GET', url: '/account.json'})
.$promise.then(
function(data) { return data; },
function(error) { return error; });
}
}

Resources