AngularJS - UI Router: Get template url from within the template - angularjs

I'm creating states via ui-router, and attaching them to the same controller. (although obviously different instances of that controllers are initialized)
Inside of that controller, I'd like to know the name of the template it was initialized for.
My idea was to somehow pass to that controller properties in the stateProvider (ui-sref doesn't solve opening the browser with a deep link), but from my searches so far it appears it can't be done.
I can't simply check the name of the current state, since I'm working with multiple views.
I'm working with the same controller for multiple states and views, the controller can act accordingly as soon as he can know the name of the template he's attached to.
Here's how I create my states and views:
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
var controller = 'textFile';
var base = 'templates';
var views = ['home', 'about'];
for (var i = 0; i < views.length; i++)
{
var view = views[i];
$stateProvider.state(view, {
url: '/' + view,
views: {
'header': {
templateUrl: base + '/header.html',
controller: controller
},
'page': {
templateUrl: base + '/' + view + '.html',
controller: controller
},
'footer': {
templateUrl: base + '/footer.html',
controller: controller
}
}
});
}
}]);
I need to be able to know in textFile for instance if it's attached to header.html, footer.html, etc...

Why don't you use a resolve, so that you can access the unique data for each controller instance. For example:
$stateProvider.state(view, {
url: '/' + view,
views: {
'header': {
templateUrl: base + '/header.html',
controller: 'textFile',
resolve: {
viewName: function() { return 'header'; }
}
},
'page': {
templateUrl: base + '/' + view + '.html',
controller: 'textFile',
resolve: {
viewName: function() { return 'page'; }
}
},
'footer': {
templateUrl: base + '/footer.html',
controller: 'textFile',
resolve: {
viewName: function() { return 'footer'; }
}
}
}
});
Then you can access the value in your controller:
.controller('textFile', function($scope, viewName){
console.log(viewName);
});

Related

Getting nested views to work with multiple modules in AngularJS and ui-router

I'm working with a large AngularJS application, which has 1 large module, which I'm trying to break down into more easily managed modules.
We have several ui-views on the main page for menu, footer, content, sidebar etc.
At the moment each $stateProvider.state is populating each of these ui-views on every state change. I want to change it to only be more hierarchical and only have the root state change these. This I can do.
However, I'm having issues when I split the application into modules. I've created a Plunker to demonstrate.
(function() {
angular
.module("acme", ["ui.bootstrap", "ui.router", "acme.admin", "acme.stock"]);
angular
.module("acme")
.config(MainModuleConfig);
MainModuleConfig.$inject = ["$stateProvider", "$urlRouterProvider", "$locationProvider"];
function MainModuleConfig($stateProvider, $urlRouterProvider, $locationProvider) {
//$locationProvider.html5Mode(true);
var root = {
name: "root",
url: "/",
views: {
"menuView": {
templateUrl: "app/menu/menuTemplate.html",
},
"mainView": {
templateUrl: "app/mainTemplate.html",
controller: "MainController",
controllerAs: "vm",
}
}
};
$stateProvider
.state("root", root);
$urlRouterProvider
.otherwise("/");
}
})();
(function() {
angular
.module("acme.admin", ["ui.router"]);
angular
.module("acme.admin")
.config(AdminConfig);
AdminConfig.$inject = ["$stateProvider", "$locationProvider"];
function AdminConfig($stateProvider, $locationProvider) {
var admin = {
name: "admin",
url: "/Admin",
views: {
"menuView": {
templateUrl: "app/menu/menuTemplate.html",
},
"mainView": {
templateUrl: "app/admin/adminTemplate.html",
}
}
};
var countries = {
name: "admin.Countries",
url: "/Admin/Countries",
views: {
"adminView": {
templateUrl: "app/admin/adminCountriesTemplate.html",
controller: "AdminCountriesController",
controllerAs: "vm"
}
}
}
var people = {
name: "admin.People",
url: "/Admin/People",
views: {
"adminView": {
templateUrl: "app/admin/adminPeopleTemplate.html",
controller: "AdminPeopleController",
controllerAs: "vm"
}
}
}
$stateProvider
.state("admin", admin)
.state("admin.Countries", countries)
.state("admin.People", people);
}
})();
In the admin module and others, I don't want to have to set the "menuView" again, but I can't see how to reference the parent
I managed to fix the issue:
First I set up the root state in the main module:
var root = {
name: "root",
url:"/",
views: {
"menuView": {
templateUrl: "app/menu/menuTemplate.html",
},
"mainView": {
templateUrl: "app/mainTemplate.html",
controller: "MainController",
controllerAs: "vm",
}
}
};
Then in the child modules, I changed the main node to be a child of root and also suffixed the ui-view name with an #:
var admin = {
name: "root.admin",
url: "/Admin",
views: {
"mainView#": {
templateUrl: "app/admin/adminTemplate.html",
}
}
};
The plunker has been updated with the working example.

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'
});
});

Unable to call controller function from child view in angularjs using ui router

Config of the module is
home.config(['$stateProvider','$urlRouterProvider',function($stateProvider, $urlRouterProvider){
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'templates/home.html'
})
** Here i have done loading of two child views(startPracticeCase.html,steps.html) in main view(partial-startPracticeCase.html) **
.state('startPracticeCase', {
url: '/startPracticeCase',
views: {
'': { templateUrl: 'templates/partial-startPracticeCase.html'},
'startPracticeContent#startPracticeCase': { templateUrl: 'templates/startPracticeContent.html' },
'steps#startPracticeCase': {
templateUrl: 'templates/steps.html'
}
}
})
** here i am changing first child view with another one whenever user click on different steps available on steps.html **
.state('startPracticeCase.casePatientHistory', {
url: '/casePatientHistory',
views: {
'': { templateUrl: 'templates/partial-startPracticeCase.html',controller: 'subjectiveQuestions' },
'startPracticeContent#startPracticeCase':
{
templateUrl: 'templates/casePatientHistory.html' ,
controller: 'serverData'
},
}
});
$urlRouterProvider.otherwise('/home');
}]);
Controller:
home.controller('serverData',function ($state,$scope,$location,DataLoadingService){
$scope.subjectiveQuestions = function (ref) {
console.log(this.id);
$scope.dataLoading = true;
DataLoadingService.SubjectiveQuestions(function(response) {
if(response) {
$scope.questions=response;
console.log("$scope.questions :: "+response);
//$state.go('startPracticeCase.casePatientHistory');
}else {
//$scope.error = response.message;
$scope.error = 'error';
$scope.dataLoading = false;
}
});
};
});
** I am trying to call subjectiveQuestions function on click of steps available on steps.html**
I wrote following things in anchor tag but the controller method/fun is not called .
< ui-sref="startPracticeCase.casePatientHistory" ng-click="subjectiveQuestions ()" > Subjective Interview</>
One more thing the index.hml page of my app have one ui-view in which i am loading partial-startPracticeCase.html this page also have two ui-view
Call the controller function first then use $state.go(your_state) like
In html
<a href ng-click="subjectiveQuestions()">Subjective Interview</a>
In controller
$scope.subjectiveQuestions = function () {
//other code
$state.go('state_name'); //set your state where you want to go
};

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; });
}
}

angular-ui-router unable to create a dynamic named, named view

I am using angular-ui-router multiple views.
I have a constant module:
angular.module('app.constants', [])
.constant('constants', {
parent1: "parent1",
parent2: "parent2"
});
my state looks like this:
.config(['$stateProvider', 'constants', function ($stateProvider, constants) {
$stateProvider.state(constants.parent1, {
abstract: true,
url: '/' + constants.parent1
});
$stateProvider.state(constants.parent1 + ".state1", {
url: '/state1',
views: {
'cool-view#' + constants.parent1 + 'state1': {
templateUrl: root + 'views/splashScreen/splash.html',
controller: 'splashScreenCtrl'
}
}
});
$stateProvider.state(constants.parent2, {
abstract: true,
url: '/' + constants.parent2
});
$stateProvider.state(constants.parent2 + ".state1", {
url: '/state1',
views: {
'cool-view#' + constants.parent2 + 'state1': {
templateUrl: root + 'views/splashScreen/splash.html',
controller: 'splashScreenCtrl'
}
}
});
}]);
I have many parent abstract states.
In a child state i have a named view which i want to trigger.
The problem is that i can't dynamically create the line:
'cool-view#' + constants.parent1 + 'state1'
It will work with :
'cool-view#parent1.state1'
Gives me an error. How will i be able to create a dynamically field name inside the views object.
The reason i want to be able to create it dynamically is because i have a constant module which i might change in the future and i do not want to hardcode it in the views.
jsfiddle to solve this problem without much thinking about why you are doing this:
http://jsfiddle.net/qq1rbbb7/
var constants = { parent2: "someThing" };
var root = "root";
var views = {};
views['cool-view#' + constants.parent2 + 'state1'] = {
templateUrl: root + 'views/splashScreen/splash.html',
controller: 'splashScreenCtrl'
};
var state = {
'url': '/state1',
'views': views
};
console.debug(state);

Resources