dynamic configuration of states using ui-router - angularjs

I am using ui-router to generate multiple states, views and subviews. it looks like below :
$stateProvider.state('dashboard', {
url : "/dashboard",
controller : function($scope, $filter) {
console.log($scope, '$scope');*/
views : {
"header":{
templateUrl : getTemplate("dashboardHeader"),
controller : function($scope, $filter) {
console.log($scope.location, '$scope');
}
},
"body" : {
templateUrl : getTemplate("dashboardChart"),
controller : function($scope, $filter) {
console.log($scope, '$scope');
}
}
}
}).state('dashboard.insight', {
url : "/:insight",
templateUrl : getTemplate("insight"),
controller : function($scope, $filter) {
console.log($scope, 'Sameer Test');
}
}).state('products', {
url : "/products",
views: {
"header":{
templateUrl: getTemplate("productHeader"),
controller: function($scope, Restangular, $filter, PlatformService){
.......
}
},
"body":{
templateUrl:getTemplate("products"),
controller : function($scope, Restangular, $filter, $route, $routeParams, $location, ngDialog,PlatformService) {
.......
} );
}
}
}
})
here dashboard and products are main views. insight is dynamically binded using ui-sref. i want to move all these a JSON structure so that i can configure which client needs which all states views and controllers. like some may need dashboard some may not.
So i decided to use app.run() to load these configurations. But i am not getting subviews of dashboard and states which are "dashboard.insight" (/:insight). As JSON will have dashboard not dashboard.insight.
How to achieve this.

Related

How to define a abstract in routeprovider?

I want to define a abstract in route provider as we can define it in a state provider to for parent.
.when('/home', {
title: 'home',
templateUrl : 'templates/home.html',
controller : 'HomeController'
})
.when('/about', {
title: 'about',
templateUrl : 'templates/about.html',
controller : 'AboutController'
})
i want to define a (/home) as abstract or is the any way to use a HomeController as a global for entire application.
My controller is :
.controller('HomeCtrl', function($scope, $http, oliveService, $location, $routeParams) {
console.log('home ctrl');
$scope.about_info = function(){
console.log('this is about info');
}
})
.controller('AboutCtrl', function($scope, $http, oliveService, $location, $routeParams) {
console.log('about ctrl');
$scope.about_info = function();
})
is the any way to use a HomeController as a global for entire application?
Yes,you can.
consider the index template :
HTML :
<body ng-view>
<div ng-controller="globalCtrl">
</div>
</body>
and define your controller as usual.
For the ngRoute router there are no abstract states like for uiRouter. Just attach a Controller to the Body Tag for example.

Controller for views in a state

I'm trying to define a controller within an abstract state so that I can have a single controller for all my views but the functions inside controller are not getting called if the controller is defined outside.
.state('update', {
url : '/update',
abstract: true,
template: '<ui-view/>',
controller : function($scope) { //works
$scope.hello = function() {
alert("hello");
}
}
controller : 'updateController' // Doesn't work
})
.state('update.detail', {
url : '/view/:id',
views : {
"" : {
templateUrl : 'update-detail.html'
},
"header#update.detail" : {
templateUrl : 'header.html'
},
"genericnavigation#update.detail" : {
templateUrl : 'generic-navigation.html'
},
"mnavigation#update.detail" : {
templateUrl : 'mobile-navigation.html'
},
"updatecontent#update.detail" : {
templateUrl : 'update-content.html'
}
}
})
HTML
header.html
<div ng-click="hello();"></div> //Click event doesn't get fired for ( controller : 'updateController' )
app.controller('updateController', ['$scope', '$state', function($state, $scope) {
console.log("inside update")
$scope.hello = function() {
alert("hello");
}
}]);
Look how you defined your controller:
['$scope', '$state', function($state, $scope)
The arguments are not in the right order. So the $state variable is in fact the scope, and the $scope variable is in fact the state.

child state controller not being reached in angular-ui-router

I have the following setup in my code
.config(function config($stateProvider)
$stateProvider
.state('home', {
url : '/home',
views : {
'main' : {
controller : 'HomeCtrl',
templateUrl : 'home/home.tpl.html'
}
}
})
.state('home.details', {
url : '/details',
views : {
" " : {
template : "<h1>hello</h1>",
controller : function ($scope, $http, $state) {
//do some stuff here
//does not seem to reach code in here
}
}
}
});
})
.controller('HomeCtrl', function ($scope, $http, $state) {
//on a button click do $state.go('.details');
});
When I do this , the button click on my HomeCtrl seems to take me to /home/details but it does not seems to go inside the controller in that particular route at that point. (I checked by putting a break point inside the controller for the details.) Is there something wrong with my setup? I'm trying to do something similar to this sample app shown in the ui-router webpage.
The solution here would in a named-view (not) matching. Here is the working plunker.
We have to place the named ui-view inside of the parent view (or use more precise naming, see for example here)
So, the parent, home template should contain the named ui-view, e.g. nameOtherThanSpace
<div ui-view="nameOtherThanSpace" ></div>
And the child defintion must target that view, the complete snippet is:
$stateProvider
.state('home', {
url: '/home',
views: {
'main': {
controller: 'HomeCtrl',
template: '<div>' +
'<h1>hello from parent</h1>' +
'<hr />' +
'<div ui-view="nameOtherThanSpace" ></div>' +
'<div>',
}
}
})
.state('home.details', {
url: '/details',
views: {
"nameOtherThanSpace": {
template: "<h2>hello from a child</h3>",
controller: function($scope, $http, $state) {},
}
}
});
How to use more specific view names:
View Names - Relative vs. Absolute Names
UI-Router isnt rendering childs correctly with templateurl in Asp.net Mvc
The working plunker using the name nameOtherThanSpace, instead of " " (space)
Try registering your controller on the app instead of on your $stateProvider. e.g.
var app = angular.module('myApp', []);
app.controller('HomeCtrl', function ($scope, $http, $state) {
//on a button click do $state.go('.details');
});
Update 1:
You should only need to specify a view if you have multiple views in which case the view probably needs to have a name. But you only have one view for that state so I would just do this.
.state('home.details', {
url : '/details'
template : "<h1>hello</h1>",
controller : function ($scope, $http, $state) {
//do some stuff here
//does not seem to reach code in here
}
}

AngularJS - Consuming REST API with Restangular in a factory

I understand how to use Restangular in a controller, however my thoughts are that Restangular is essentially an ORM on steroids.
The ORM shouldn't have any knowledge of the state of the application. That is the job of the controller.
I also want to re-use queries to the ORM, and as such, I believe that Restangular should be used inside a service.
My problem is that I am a js / angularjs and restangular noob, having only about 2-3 months exp with anything front-end.
My Controllers:
app.controller('AdminSupplierIndexController',
['$scope', '$stateParams', '$state', 'Supplier',
function ($scope, $stateParams, $state, Supplier) {
$state.reload();
Supplier.getAll.then(function (suppliers) {
$scope.suppliers = suppliers;
});
}]);
app.controller('AdminSupplierDetailController',
['$scope', '$stateParams', 'Supplier',
function ($scope, $stateParams, Supplier) {
Supplier.getOne({ supplierId : $stateParams.supplierID}).then(function(supplier) {
$scope.supplier = supplier;
});
}]);
My Factory
app.factory('Supplier', ['Restangular', function (Restangular) {
return {
getAll: Restangular.all('supplier').getList(),
getOne: Restangular.one('supplier', supplierId).get()
};
}]);
My Supplier.getAll method works fine - I can list all the suppliers from the Supplier factory.
My problem is with my Supplier.getOne method.
Question 1: How do I inject the supplierId into the factory? I am getting ReferenceError: supplierId is not defined
Question 2: Am I trying to over-engineer things considering that I would have to create individual methods for C-R-U-D for every single factory when these methods are already provided by Restangular?
I know this is old, but an alternate way would just be to wrap it within a function. This way, you can keep any other logic within the service/method.
app.factory('Supplier', ['Restangular', function (Restangular) {
return {
getAll: Restangular.all('supplier').getList(),
getOne: function(supplierId) {
return Restangular.one('supplier', supplierId).get()
}
};
}]);
Found the solution in https://github.com/mgonto/restangular#decoupled-restangular-service
Essentially, the way I have solved this problem is as follows:
app.js
$stateProvider
...
.state('admin.supplier', {
url : "/supplier",
templateUrl : 'templates/admin/supplier/index.html',
controller: "AdminSupplierIndexController",
resolve: {
suppliers: ['Supplier', function(Supplier) {
return Supplier.getList();
}]
}
})
.state('admin.supplier.detail', {
url : "/:supplierId",
templateUrl : "templates/admin/supplier/detail.html",
controller: "AdminSupplierDetailController",
resolve: {
supplier : ['Supplier', '$stateParams', function(Supplier, $stateParams) {
return Supplier.one($stateParams.supplierId).get();
}]
}
})
...
Supplier.js
app.factory('Supplier', ['Restangular', function(Restangular) {
return Restangular.service('supplier');
}]);
SupplierControllers.js
app.controller('AdminSupplierIndexController', ['$scope', '$stateParams', '$state', 'suppliers',
function ($scope, $stateParams, $state, suppliers) {
$state.reload();
$scope.suppliers = suppliers;
}]);
app.controller('AdminSupplierDetailController', ['$scope', 'supplier',
function ($scope, supplier) {
$scope.supplier = supplier;
}]);

AngularJS Pre-served $params variables for a controller defined inside of a route

Is it possible to pass your own variables in a defined route in AngularJS?
The reason why I'm doing this is because I have to data representations of the same page (one is a filtered view in terms of the JSON data) and all I need to do is give a boolean flag to the $params array to let the controller function know that this page is either filtered or non-filtered.
Something like this:
var Ctrl = function($scope, $params) {
if($params.filtered) {
//make sure that the ID is there and use a different URL for the JSON data
}
else {
//use the URL for JSON data that fetches all the data
}
};
Ctrl.$inject = ['$scope', '$routeParams'];
angular.modlule('App', []).config(['$routeProvider', function($routes) {
$routes.when('/full/page',{
templateURL : 'page.html',
controller : Ctrl
});
$routes.when('/full/page/with/:id',{
templateURL : 'page.html',
controller : Ctrl,
params : {
filtered : true
}
});
}]);
According to $routeProvider documentation, the route parameter of $routeProvider.when() has property resolve:
An optional map of dependencies which should be injected into the controller.
Something like this should work:
function Ctrl($scope, isFiltered) {
if(isFiltered) {
//make sure that the ID is there and use a different URL for the JSON data
}
else {
//use the URL for JSON data that fetches all the data
}
}
Ctrl.$inject = ['$scope', 'isFiltered'];
angular.modlule('App', []).config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/full/page',{
templateURL: 'page.html',
controller: Ctrl
});
$routeProvider.when('/full/page/with/:id',{
templateURL: 'page.html',
controller: Ctrl,
resolve: {
isFiltered: function() { return true; }
}
});
}]);
AFAIK it is not currently possible to specify additional parameters for a route. Having said this your use case could be easily covered by testing if :id is defined as part of $routeParams.
The thing is that AngularJS will match your routes either on '/full/page' or '/full/page/with/:id' so just by testing $routeParams for id presence in your controller:
if ($routeParams.id)
you would know in which case your are.
The alternative is to use different controllers for different routes.
mething like this must be work for filter:
function caseFilterCtrl($scope, $routeParams, $http) {
$http.get('./data/myDatas.json').success( function(data){
var arr = new Array();
for(var i=0; i < data.length; i++){
if(data[i].filter == $routeParams.id){
arr.push(data[i]); }
}
$scope.filtered= arr;
});
}
caseFilterCtrl.$inject = ['$scope', '$routeParams', '$http']; //for minified bug issue
and the routage :
angular.module('myFilterApp', []).
config(['$routeProvider', function($routeProvider){
$routeProvider.when('/filter/:id', {templateUrl: './view/partial/filter.html', controller: caseFilterCtrl});
$routeProvider.otherwise({redirectTo: '/filter/01'});
}
]);
You can get sneak params directly through $route.current.$$route.
function Ctrl($scope, $route) {
var filtered = $route.current.$$route.params.filtered;
}
angular.modlule('App', []).config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/full/page/with/:id',{
templateURL: 'page.html',
controller: Ctrl,
params : {
filtered : true
}
});
}]);
Although it work, I'd still prefer a resolve solution. params (or any name of your choice) could be overwritten by angularjs in future releases.

Resources