[angularjs] Error: Argument is not a function, got undefined

Using AngularJS with Scala Play, I'm getting this error.

Error: Argument 'MainCtrl' is not a function, got undefined

I'm trying to create a table consisting of the days of the week.

Please take a look at my code. I had checked the name of the Controller, but that seems correct. Note: Code used from this SO answer

index.scala.html

@(message: String)

@main("inTime") {

<!doctype html>
<html lang="en" ng-app>
    <head>
        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
    </head>
<div ng-controller="MainCtrl">
    <table border="1">
    <tbody ng-repeat='(what,items) in data'>
      <tr ng-repeat='item in items'>
        <td ngm-if="$first" rowspan="{{items.length}}">{{what}}</td>
        <td>{{item}}</td>
      </tr>
    </tbody>
  </table>
</div>
</html> 
}

MainCtrl.js

(function() {
    angular.module('[myApp]', []).controller('MainCtrl', function($scope) {
        $scope.data = {
            Colors: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
        }
    });
}());

This question is related to angularjs playframework

The answer is


There appear to be many working solutions suggesting the error has many actual causes.

In my case I hadn't declared the controller in app/index.html:

<scipt src="src/controllers/controller-name.controller.js"></script>

Error gone.


Because this pops-up in Google when trying to find an answer to: "Error: Argument '' is not a function, got undefined".

It's possible that you are trying to create the same module twice.

The angular.module is a global place for creating, registering and retrieving AngularJS modules.

Passing one argument retrieves an existing angular.Module, whereas passing more than one argument creates a new angular.Module

Source: https://docs.angularjs.org/api/ng/function/angular.module#overview

Example:

angular.module('myApp', []) Is used to create a module without injecting any dependencies.

angular.module('myApp') (Without argument) is used to get an existing module.


I had the same error message (in my case : "Argument 'languageSelectorCtrl' is not a function, got undefined").

After some tedious comparison with Angular seed's code, I found out that I had previously removed a reference to the controllers module in app.js. (spot it at https://github.com/angular/angular-seed/blob/master/app/js/app.js)

So I had this:

angular.module('MyApp', ['MyApp.filters', 'MyApp.services', 'MyApp.directives'])

This failed.

And when I added the missing reference:

angular.module('MyApp', ['MyApp.filters', 'MyApp.services', 'MyApp.controllers', 'MyApp.directives'])

The error message disappeared and Angular could instanciate the controllers again.


In my case it was a simple typo in index.html:

<script src="assets/javascript/controllers/questionssIndexController.js"></script>

that should have been

<script src="assets/javascript/controllers/questionsIndexController.js"></script>

without the extra s in the controller's name.


FIRST. check if you have correct controller in the route definitions, same as the controller names that you are defining

communityMod.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/members', {
        templateUrl: 'modules/community/views/members.html',
        controller: 'CommunityMembersCtrl'
      }).
      otherwise({
        redirectTo: '/members'
      });
  }]);

communityMod.controller('CommunityMembersCtrl', ['$scope',
    function ($scope) {
        $scope.name = 'Hello community';
    }]);

different controller names in this example will lead to errors, but this example is correct

SECOND check if you have imported your javascript file:

<script src="modules/community/controllers/CommunityMembersCtrl.js"></script>


Turns out it's the Cache of the browser, using Chrome here. Simply check the "Disable cache" under Inspect (Element) solved my problem.


Could it be as simple as enclosing your asset in " " and whatever needs quotes on the inside with ' '?

<link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">

becomes

<link rel="stylesheet" media="screen" href="@routes.Assets.at('stylesheets/main.css')">

That could be causing some problems with parsing


This seriously took me 4 HOURS (including endless searches on SO) but finally I found it: by mistake (unintentionally) I added a space somewhere.

Can you spot it?

angular.module('bwshopper.signup').controller('SignupCtrl ', SignupCtrl);

So ... 4 hours later I saw that it should be:

angular.module('bwshopper.signup').controller('SignupCtrl', SignupCtrl);

Almost impossible to see with just the naked eye.

This stresses the vital importance of revision control (git or whatever) and unit/regression testing.


I had the same error with a big mistake:

appFormid.controller('TreeEditStepControlsCtrl', [$scope, function($scope){

}]);

You see ? i forgot the '' around the first $scope, the right syntax is of course:

appFormid.controller('TreeEditStepControlsCtrl', ['$scope', function($scope){

}]);

A first error i didn't see immediatly was: "$scope is not defined", followed by "Error: [ng:areq] Argument 'TreeEditStepControlsCtrl' is not a function, got undefined"


To fix this problem, I had to discover that I misspelled the name of the controller in the declaration of Angular routes:

.when('/todo',{
            templateUrl: 'partials/todo.html',
            controller: 'TodoCtrl'
        })

I got sane error with LoginController, which I used in main index.html. I found two ways to resolve:

  1. setting $controllerProvider.allowGlobals(), I found that comment in Angular change-list "this option might be handy for migrating old apps, but please don't use it in new ones!" original comment on Angular

    app.config(['$controllerProvider', function($controllerProvider) { $controllerProvider.allowGlobals(); }]);

  2. wrong contructor of registering controller

before

LoginController.$inject = ['$rootScope', '$scope', '$location'];

now

app.controller('LoginController', ['$rootScope', '$scope', '$location', LoginController]);

'app' come from app.js

var MyApp = {};
var app = angular.module('MyApp ', ['app.services']);
var services = angular.module('app.services', ['ngResource', 'ngCookies', 'ngAnimate', 'ngRoute']);

?med's second point was my pitfall but just for the record, maybe it's helping someone somewhere:

I had the same problem and just before I went nuts I discovered that I had forgotten to include my controller script.

As my app is based on ASP.Net MVC I decided to keep myself sane by inserting the following snippet in my App_Start/BundleConfig.cs

bundles.Add(new ScriptBundle("~/app").Include(
                "~/app/app.js",
                "~/app/controllers/*.js",
                "~/app/services/*.js" ));

and in Layout.cshtml

<head>
...
   @Scripts.Render("~/app")
...
</head>

Now I won't have to think about including the files manually ever again. In hindsight I really should have done this when setting up the project...


If you are in a submodule, don't forget to declare the module in main app. ie :

<scrip>
angular.module('mainApp', ['subModule1', 'subModule2']);

angular.module('subModule1')
   .controller('MyController', ['$scope', function($scope) {
      $scope.moduleName = 'subModule1';
   }]);
</script>
...
<div ng-app="mainApp">
   <div ng-controller="MyController">
   <span ng-bind="moduleName"></span>
</div>

If you don't declare subModule1 in mainApp, you will got a "[ng:areq] Argument "MyController" is not a function, got undefined.


Some times this error is a result of two ng-app directives specified in the html. In my case by mistake I had specified ng-app in my html tag and ng-app="myApp" in the body tag like this:

<html ng-app>
  <body ng-app="myApp"></body>
</html>

In my case (having an overview page and an "add" page) I got this with my routing setup like below. It was giving the message for the AddCtrl that could not be injected...

$routeProvider.
  when('/', {
    redirectTo: '/overview'
  }).      
  when('/overview', {
    templateUrl: 'partials/overview.html',
    controller: 'OverviewCtrl'
  }).
  when('/add', {
    templateUrl: 'partials/add.html',
    controller: 'AddCtrl'
  }).
  otherwise({
    redirectTo: '/overview'
  });

Because of the when('/' route all my routes went to the overview and the controller could not be matched on the /add route page rendering. This was confusing because I DID see the add.html template but its controller was nowhere to be found.

Removing the '/'-route when case fixed this issue for me.


I have encountered the same problem and in my case it was happening as a result of this problem:

I had the controllers defined in a separate module (called 'myApp.controllers') and injected to the main app module (called 'myApp') like this:

angular.module('myApp', ['myApp.controllers'])

A colleague pushed another controller module in a separate file but with the exact same name as mine (i.e. 'myApp.controllers' ) which caused this error. I think because Angular got confused between those controller modules. However the error message was not very helpful in discovering what is going wrong.