I have an abstract parent view that is meant to share a controller with its nested views, before I have a main controller that is the principal of my app
.state('main', {
abstract: true,
url: '/',
templateUrl: 'app/templates/main.html',
controller: 'mainController'
})
.state('main.edit', {
abstract: true,
url: '/edit',
templateUrl: 'app/templates/edit.html',
controller: 'editController'
})
.state('main.edit.details', {
url: '/details',
templateUrl: 'app/templates/editDetailsView.html',
controller: 'editDetailsController'
})
.state('main.edit.info', {
url: '/info',
templateUrl: 'app/templates/editInfoView.html',
controller: 'editInfoController'
})
The routing works as expected, before I set de controller, I have the parent controller of the module that would be edit controller and every controller of each view
The error:
"Error: [ng:areq] Argument 'editController' is not a function, got undefined
http://errors.angularjs.org/1.5.7/ng/areq?p0=editController&p1=not%20aNaNunction%2C%20got%20undefined
minErr/<#http://localhost:3000/js/libs.min.js:5:4923
assertArg#http://localhost:3000/js/libs.min.js:5:19120
assertArgFn#http://localhost:3000/js/libs.min.js:5:19322
$ControllerProvider/this.$get</<#http://localhost:3000/js/libs.min.js:7:31336
z/<.compile/<#http://localhost:3000/js/libs.min.js:15:2556
bind/<#http://localhost:3000/js/libs.min.js:5:12865
invokeLinkFn#http://localhost:3000/js/libs.min.js:7:22121
nodeLinkFn#http://localhost:3000/js/libs.min.js:7:4193
compositeLinkFn#http://localhost:3000/js/libs.min.js:6:26125
compile/<#http://localhost:3000/js/libs.min.js:6:24834
compilationGenerator/<#http://localhost:3000/js/libs.min.js:6:31172
l#http://localhost:3000/js/libs.min.js:15:1755
y/l.compile/<#http://localhost:3000/js/libs.min.js:15:2183
bind/<#http://localhost:3000/js/libs.min.js:5:12865
invokeLinkFn#http://localhost:3000/js/libs.min.js:7:22121
nodeLinkFn#http://localhost:3000/js/libs.min.js:7:4193
compositeLinkFn#http://localhost:3000/js/libs.min.js:6:26125
compile/<#http://localhost:3000/js/libs.min.js:6:24834
z/<.compile/<#http://localhost:3000/js/libs.min.js:15:2764
bind/<#http://localhost:3000/js/libs.min.js:5:12865
invokeLinkFn#http://localhost:3000/js/libs.min.js:7:22121
nodeLinkFn#http://localhost:3000/js/libs.min.js:7:4193
compositeLinkFn#http://localhost:3000/js/libs.min.js:6:26125
compile/<#http://localhost:3000/js/libs.min.js:6:24834
compilationGenerator/<#http://localhost:3000/js/libs.min.js:6:31172
l#http://localhost:3000/js/libs.min.js:15:1755
y/l.compile/</<#http://localhost:3000/js/libs.min.js:15:2175
$RootScopeProvider/this.$get</Scope.prototype.$broadcast#http://localhost:3000/js/libs.min.js:9:24515
v/y.transitionTo/y.transition<#http://localhost:3000/js/libs.min.js:14:29498
processQueue#http://localhost:3000/js/libs.min.js:9:8733
scheduleProcessQueue/<#http://localhost:3000/js/libs.min.js:9:9000
$RootScopeProvider/this.$get</Scope.prototype.$eval#http://localhost:3000/js/libs.min.js:9:22223
$RootScopeProvider/this.$get</Scope.prototype.$digest#http://localhost:3000/js/libs.min.js:9:19908
$RootScopeProvider/this.$get</Scope.prototype.$apply#http://localhost:3000/js/libs.min.js:9:22650
done#http://localhost:3000/js/libs.min.js:8:7950
completeRequest#http://localhost:3000/js/libs.min.js:8:11757
createHttpBackend/</xhr.onload#http://localhost:3000/js/libs.min.js:8:12689
"
If I erase the editController, it works well, but what can I do if I need the shared controller of my views, other way it works if i set a the parent controller like this
.state('main.edit', {
abstract: true,
url: '/edit',
templateUrl: 'app/templates/edit.html',
controller: function($scope){
console.log('edit parent controller');
}
not the idea.
I spent last 24 hours trying to find this. I was about to post a question/add to yours but I finally found my issue.
In my case, after refactoring to the recommended format (separate file for module definition, controller definition, service definition etc) I left [] in some controller definition files like this in a few files:
(function () {
'use strict';
angular
.module('app.landing', [])
.controller('LandingController', LandingController);
That was overwriting app.landing module that has already been created. After reviewing and cleaning up all module definitions and component definitions that use those module references, it all works now. Phew.
(function () {
'use strict';
angular
.module('app.landing')
.controller('LandingController', LandingController);
Interestingly enough I read S/O answers with this very issue, i.e. Error: [ng:areq] from angular controller but I couldn't spot those crazy brackets in 2 files. It makes me question best practices endorsed by angular team a bit as if i had it all in one file, this would not be an issue. When I have 50 files to look over and I've been staring at the screen for hours, this is pretty challenging. I wish there was a check for multiple module definitions.
Related
Just to give some context, I have an Angular application with several separate modules. I am working with ui-router to provide routing to these modules, and I want to use the names of the modules in the URLs. In my Angular app config block I have defined a state for both module1 and module2 with a parameter on each like so:
.state('module1', {
url: '/:module_name',
templateUrl: '/app/modules/module1/views/index.html',
controller: 'someCtrl'
})
.state('module2', {
url: '/:module_name',
templateUrl: '/app/modules/module2/views/index.html',
controller: 'someOtherCtrl'
})
I also have a few links that should take me to the home page of each module.
Naturally, the problem is that the first state will catch all of the rest of my module2 routes, since their URLs all have the same form:
http://localhost:3000/#/module1
http://localhost:3000/#/module2/users
http://localhost:3000/#/module2/books
and so on. I can see how the order that we define the stats is important, but I can't seem to come up with a way to be able to have the module name as a state parameter (this is important since I need it in the corresponding controllers to distinguish from which module an operation is coming from) and avoid this hierarchy problem altogether.
Any ideas?
In your case ui-router will not know which route your are pointing to as they are exactly the same. You would either have to hardcode the module name(assuming there are only a few):
.state('module1', {
url: '/module1',
templateUrl: '/app/modules/module1/views/index.html',
controller: 'someCtrl'
})
.state('module2', {
url: '/module2',
templateUrl: '/app/modules/module2/views/index.html',
controller: 'someOtherCtrl'
})
.state('module2', {
url: '/module2/users',
templateUrl: '/app/modules/module2/views/users.html',
controller: 'someOtherCtrl'
})
.state('module2', {
url: '/module2/books',
templateUrl: '/app/modules/module2/views/books.html',
controller: 'someOtherCtrl'
})
or dynamically inject the html based on the module number
.state('module', {
url: '/module/:moduleId',
templateUrl:
function (stateParams){
return '/app/modules/module' + stateParams.moduleId + '/views/index.html';
}
controller: 'someOtherCtrl'
})
so now to hit module one the path looks like this
http://localhost:3000/#/module/1
I am in trouble with a specific requirement here for our Application.
We a are setting-up an angular application inside a pre-existent Rails Application.
As a full refactor of our code-base is currently out-of-the-question we are dealing with some hard customization and hackings on both sides to allow a incremental introduction of Angular.
What we need for now is a way to tell the ui-router to bind only to the links we have the ng-sref attribute and do not bother with all the regular href links within our app.
Is there a way to achieve this behavior ?
Below is my current code:
angular.module('app').config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider.state('test', {
url: "/1/test",
template: 'test'
});
$locationProvider.html5Mode({
enabled: true,
requireBase: false,
rewriteLinks: false
})
}
)
With this approach, all links, even those ones without any route setup for it, and without a ui-sref attribute, are being watched by angular routing service and prevented to work like it`s previous behaviour. I do not want to add every route of our huge app to the angular routing setup (this is a terrible idea) because most of theses links are to non-angular pages. I just want angular routing service to ignore this links, or these locations that are not defined. Maybe a setting for the $location service to let those guys fallow along with its previous behaviour (ajax requests, regular requests, or Turbolinks requests). I am pretty sure this is something really trivial that I might be missing the point.
What happens when I click on theses links is that the window location changes, but nothing happen. The browser request is not triggered.
Thank you very much in advance.
###################################################################################
# My suggestion is use the ui-router to route to specific pages as shown
# in the example below.
# <a ui-sref="/login">
# <a ui-sref="/logout">
# <a ui-sref="/signup">
# <a ui-sref="/profile">
# 'ui-sref' will take you to the specific pages.
# You can also use '$state.go' to take you to specific pages as shown below.
# $state.go('authentication.login');
# $state.go('authentication.logout');
# $state.go('authentication.signup');
# $state.go('authentication.profile');
###################################################################################
(function() {
'use strict';
angular
.module('app.foo.authentication')
.config(moduleConfig);
/* #ngInject */
function moduleConfig($translatePartialLoaderProvider, $stateProvider) {
$translatePartialLoaderProvider.addPart('app/foo/authentication');
$stateProvider
.state('authentication.login', {
url: '/login',
templateUrl: 'app/foo/authentication/login/login.tmpl.html',
controller: 'LoginController',
controllerAs: 'vm'
})
.state('authentication.logout', {
url: '/logout',
templateUrl: 'app/foo/authentication/logout/logout.tmpl.html',
controller: 'LogoutController',
controllerAs: 'vm'
})
.state('authentication.signup', {
url: '/signup',
templateUrl: 'app/foo/authentication/signup/signup.tmpl.html',
controller: 'SignupController',
controllerAs: 'vm'
})
.state('authentication.profile', {
url: '/profile',
templateUrl: 'app/foo/authentication/profile/profile.tmpl.html',
controller: 'ProfileController',
controllerAs: 'vm'
});
}
})();
I have the following state setup for a page using an abstract state and the controller as syntax:
# Details page route
.state 'title',
url: '/title',
abstract: true,
template: '<ui-view/>',
.state 'title.show',
url: '/:titleId',
templateUrl: 'title/show.html'
controller: 'Title as t'
For the purpose of this demo lets say I assign a variable to the 't' instance of the 'Title' controller and I do this inside of the Title controller function.
angular.module('title').controller 'Title',
['$state', ($state) ->
this.name = 'Test'
and inside my view 'title/show.html' I attempt to print out that variable I just created to the page:
{{t.name}}
I don't see anything. But if I remove the controller our of the ui-router and onto the element that wraps the 'title/show.html' page like this:
<div ng-controller="Title as t">
Then everything works great. Has anyone come across this problem before. I have it working fine in another app so I'm still trying to figure out what might be different in this app, maybe a difference in js library versions.
In your state configuration :
Instead of controller: 'Title as t', try :
controller: 'Title',
controllerAs: 't'
Edit : Just implemented a minimal app with ui-router and the syntax controller: Title as t also works, in versions 0.2.0 of ui-router to the most recent one as of today. I can see the t instance when I inspect angular scopes.
Your controller needs to return the value of this in order for the controllerAs feature to work properly. Since CoffeeScript implicitly returns the last line, you need to write:
return this
or if you are using the vm syntax and have written:
vm = this
you can write at the very end of the controller:
return vm
If this helps anyone my problem came about from using templated views but specifying the controllerAs outside the views element. This took forever to figure out. Credit to this thread https://github.com/driftyco/ionic/issues/3058
** WRONG **
views: {'content#': { templateUrl: 'views/listing.html' }},
controller: 'ListingCtrl',
controllerAs: 'ctrl'
** RIGHT **
views: {
'content#': { templateUrl: 'views/listing.html' },
controller: 'ListingCtrl',
controllerAs: 'ctrl'
}
Seems like these answers might be working for a lot. I came here with a different problem :
In my UI Router Javascript file, my controllers are defined like this :
state('groupHome', {
url: '/groupHome',
templateUrl: 'app/modules/group-home/groupHome.html',
controller: 'GroupHomeController',
controllerAs: 'groupHomeController'
And in my template file if I try to access the controller with the name groupHomeController it is not able to access.
But on the other hand when I changed my code to this :
state('groupHome', {
url: '/groupHome',
templateUrl: 'app/modules/group-home/groupHome.html',
controller: 'GroupHomeController as groupHomeController'
It works perfectly fine.
You will have to return this; at the end of your controller function for the controllerAs syntax to work.
angular.module('title').controller 'Title',
['$state', ($state) ->
this.name = 'Test'
return this
If you are working with $scope, you'll have to return $scope instead.
angular.module('title').controller 'Title',
['$state','$scope', ($state, $scope) ->
$scope.name = 'Test'
return $scope
Good Luck.
I am using StateProvider library to create nested views in my AngularJS app.
I had an abstract view defined at the root and now need to define another abstract view as 2nd level child to the previously created abstract view.
Facing issues with this, Not sure if I can have nested abstract views or not. Any idea.
greatly appreciate your help.
Thanks
There could be more abstract-nested states in hierarchy. This example shows it in action, definition of these states could be like this:
$stateProvider
.state('main', {
url: "",
abstract: true,
templateUrl: 'tpl.main.html',
})
.state('main.middle', {
url: "",
abstract: true,
templateUrl: 'tpl.middle.html',
})
.state('main.middle.alpha', {
url: "/alpha",
templateUrl: 'tpl.leaf.html',
controller: function ($scope, $state){
$scope.state = $state.current;
},
})
Check the plunker. As we can see, the root (main) and its child (middle) do not use url at all... but they could..
Based on these set-ups (Angular UI-Router testing scope inheritance, Angular ui-router - how to access parameters in nested, named view, passed from the parent template?), I did the following (the third holds the relevant issue):
.state("patients", {
url: "/dashboard/patients",
templateUrl: 'patients/index.html',
controller: "patientCtrl"
})
.state("sharedPatients", {
url: "/dashboard/patients/shared",
templateUrl: 'patients/shared_patients.html',
controller: "patientCtrl"
})
.state('showPatient', {
url: "/dashboard/patients/:id",
templateUrl: 'patients/show.html',
controller: ("patientCtrl", ['$scope', '$stateParams', function($scope, $stateParams) {
$scope.patient_id = $stateParams.id;
}])
})
Patients and sharedPatients work without a problem. I can also go to showPatient and access the variable patient_id. However, I cannot access any of the functions or variables established in patientCtrl. Thoughts?
The controller scope inheritance has nothing to do with the state inheritance.
Your controllers only inherit from each other if their views are nested in the DOM.
Also, the syntax you're using there is misleading. controller: ("patientCtrl", [...]) will just ignore that first part. It'll only use the controller inside the array.