Angular: Controller is undefined when adding a directive - javascript

I get the following error when adding a directive to my site:
Error: [ng:areq] Argument 'MainController' is not a function, got undefined
The error only occurs when I include the welcome-directive (welcome.js) in my site. If the import is removed the controller works.
Body of my index.html
<body ng-app="my-app">
<div ng-controller="MainController">
<welcome></welcome>
</div>
<!-- Angular -->
<script src="bower_components/angular/angular.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers/mainController.js"></script>
<!-- Without this line the controller works -->
<script src="js/directives/welcome.js"></script>
</body>
app.js
(function() {
var app = angular.module('my-app', []);
})();
mainController.js
angular.module('my-app', [])
.controller('MainController', ['$scope', function($scope) {
console.log('Controller working');
}]);
welcome.js
angular.module('my-app', [])
.directive("welcome", function() {
return {
restrict: "E",
template: "<div>Test test.</div>"
};
});

You are redefining the module. Define module only once.
when used as angular.module('my-app', []) it defined the module this should be used only once. When you want retrieve it. then use angular.module('my-app')
Use
angular.module('my-app') //Notice remove []
.directive("welcome", function() {
});

passing a 2nd argument like this angular.module('my-app', []) creates a new module, use it only once.
To retrive a module use var module = angular.module('my-app') and use module.controller(... or module.directive(.... etc.,

Related

Separate service from controller in Angularjs

I would like to separate the service from the controller in my angularjs application, I did it in a following way:
the app.js there is:
var myApp = angular.module('myApp',['restangular','ui.router','myApp.controllers','myApp.services']);
the controllers.js:
angular.module('myApp.controllers',[]);
the services.js:
angular.module('myApp.services',[]);
I have a controllers related to the controllers.js:
angular.module('myApp.controllers',[]).controller('ContactController', ContactController);
ContactController.$inject = [ '$scope', 'ContactService' ];
function ContactController($scope, ContactService) {
console.log("here call ctrl contact");
$scope.contacts = ContactService.getAll();
}
This ContactController call the service ContactService defined in a separate file:
ContactService .js
angular.module('myApp.services',[])
.factory('ContactService', function(Restangular){
var Contacts = Restangular.all('contacts');
return {
getAll : function(){
return Contacts.getList().$object;
}
};
});
the problem is when I have tried to invoke this controller I got the following error:
Error: [$injector:unpr] Unknown provider: ContactServiceProvider <-
ContactService
http://errors.angularjs.org/1.2.19/$injector/unpr?p0=ContactServiceProvider%20%3C-%20ContactService
how can I fix that?
UPDATE:
this is the structure of my app:
I have in app.js:
.state('contacts', {
url: '/contacts',
templateUrl: 'templates/contacts.html',
controller: 'ContactController'
})
.state('todos', {
url: '/todos',
templateUrl: 'templates/todos.html',
controller: 'TodoController'
})
in the index.html i imported all th js files:
Once you have initialized a module withm, angular.module('myApp.controllers', []) again you should not use second parameter dependency([])
So,
in your controller,
`angular.module('myApp.controllers',[])` should be `angular.module('myApp.controllers')`
So,
angular
.module('myApp.controllers')
.controller('ContactController', ContactController);
ContactController.$inject = ['$scope', 'ContactService'];
function ContactController($scope, ContactService) {
console.log('here call ctrl contact');
$scope.contacts = ContactService.getAll();
}
The same applies to your service/factory,
angular.module('myApp.services')
.factory('ContactService', function(Restangular){
var Contacts = Restangular.all('contacts');
return {
getAll : function(){
return Contacts.getList().$object;
}
};
});
PS: After seeing the order of your js file injection in index.html I found the major issue.
The order of your file scripts is wrong. In ContactController you are using contactService which is not defined before it.
So change the scripts order in index.html as below.
<script src="js/app.js"></script>
<script src="js/services.js"></script>
<script src="js/services/ContactService.js"></script>
<script src="js/services/TodoService.js"></script>
<script src="js/controllers/HomeController.js"></script>
<script src="js/controllers/ContactController.js"></script>
<script src="js/controllers/TodoController.js"></script>
try to include
angular.module('myApp.controllers',['myApp.services'])
instead of
angular.module('myApp.controllers',[])
cheers
Seems the issue fixed by reorder the import of my js files as follows:
the app.js then the file services and then the controllers.

How to use one module for multiple controllers

How to use one module for multiple controllers, when these controllers are in different js files.
I have 3 js file
1. app.js
2. Login. js
3. Register.js
app.js
var app = angular.module("myApp", ['ngRoute']);
app.config(function ($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'Login/login.html',
controller: 'myCtrl'
})
.when('/register', {
templateUrl: 'Register/register.html',
controller: 'registerCntrl'
})
})
Login.js
var app = angular.module("myApp");
app.controller("myCtrl", function ($scope) {
$scope.login = function (data) {
console.log(data);
if (data.name == 'pinku' && data.pswd == '1234') {
console.log("Login Successfull");
} else {
console.log("Not successful");
}
};
$scope.moreInfo = function () {
alert("M in more info");
}
});
Register.js
var app = angular.module("myApp");
app.controller("registerCntrl", function ($scope) {
});
I have defined mymodule in my app.js file now i want to register my controller to that module and controllers are in different class. I have injected ng-Route in app.js. In login m using already defined module but m getting error
'Failed to instantiate module ngRoute due to:'
Thanks in advance
You can rather do:
angular.module("myApp")
.controller(...)
for both the controllers, rather than writing the variable here
Note: app.js should be loaded before any of the controllers for this to work.
This is one of the ways it can be done:
<html ng-app="myApp">
<head>
<title></title>
</head>
<body>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript" src="controller1.js"></script>
<script type="text/javascript" src="controller2.js"></script>
</body>
</html>
Apart from this you can also use some task runners like gulp OR grunt to do that automatically.
If you load your app.js first, in other files you can inject your modules like
app = angular.module("myApp");
Note that I omit [] from the function call. It means that you are trying to get already defined module.

cannot pass parameters via angular service between 2 html file

I have 2 html file and I want to pass parameters via angular service between them.
these are the files I have:
index.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body>
<script type="text/javascript" src="services.js"></script>
<div ng-app="myApp" ng-controller="myCtrl2">
</div>
enter here
<script>
var app=angular.module("myApp");
app.controller("myCtrl2", ['$scope','$location', 'myService',
function($scope, $location, myService) {
myService.set("world");
}]);
</script>
</body>
</html>
enter2.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body>
<script type="text/javascript" src="services.js"></script>
<div ng-app="myApp" ng-controller="myCtrl3">
hello {{x}}
</div><script type="text/javascript">
var app=angular.module("myApp");
app.controller("myCtrl3", ['$scope','$location', 'myService',
function($scope, $location, myService) {
$scope.x=myService.get();
}]);
</script>
</body>
</html>
services.js
var app=angular.module("myApp", []);
app.factory('myService', function() {
var savedData = {}
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
});
why can't I get "hello world" in enter2.html, but instead get "hello" (x is not found by service)...?
When you go from index.html to enter2.html the whole page loads from scratch. For the data that you are expecting to stay in the browser, you might need to use advanced angular concepts such as loading just a part of the page using ng-view.
If that's something you have already overruled, saving the data in the service somewhere (may be the browser session) before unloading (window.onunload event) the page and then loading it back from there when the service loads (window.onload event) could also work.
Here is a working example based on your code.
I kept your index.html and added ui-view to have a single page application. The app uses 'ui.router'.
In the myCtrl2 I saved the data in the service, and call it back from myCtrl3:
.controller('myCtrl2', ['$scope', 'myService', function($scope, myService) {
console.log('myCtrl2');
myService.set('world');
}])
.controller('myCtrl3', ['myService', function(myService) {
console.log('myCtrl3');
var vm = this;
vm.x = myService.get();
}])
To keep things simple, I have one Javascript file:
angular.module('myApp', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'index.html',
controller: 'myCtrl2',
controllerAs: 'vm'
})
.state('enter2', {
url: '/enter2',
templateUrl: 'enter2.html',
controller: 'myCtrl3',
controllerAs: 'vm'
});
})
.factory('myService', function() {
var savedData = {}
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
})
.controller('myCtrl2', ['$scope', 'myService', function($scope, myService) {
console.log('myCtrl2');
myService.set('world');
}])
.controller('myCtrl3', ['myService', function(myService) {
console.log('myCtrl3');
var vm = this;
vm.x = myService.get();
}])
I also uses the var vm=this and ControllerAs as often recommended to avoid $scope issues.
index.html looks like below... pleaes note the ui-sref instead of href:
<div ui-view="">
<a ui-sref="enter2">Enter here</a>
</div>
enter2.html is now just the div part and your content:
<div>
Hello {{ vm.x }}
</div>
Let us know if that helps.
Additional info:
AngularJS Routing Using UI-Router
AngularJS's Controller As and the vm Variable
Sounds like you need to use a controller for your view page
https://docs.angularjs.org/guide/controller

Angular Module injection error while injecting controllers

I am new to AngularJS and facing a problem injecting controller to an angular app. I am trying to build a single page application where the user can navigate through the pages of a particular application form. While the code for the controllers was in the same JS file, it was working fine. But moving the controllers to a separate file(as in this case, 'js/controllers/pagecontroller.js') is throwing the error below.
Error:
Uncaught Error: [$injector:nomod] http://errors.angularjs.org/1.5.5/$injector/nomod?p0=uwApp.controllers
Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.5.5/$injector/modulerr?p0=uwApp&p1=Error%3A%2…oogleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.5.5%2Fangular.min.js%3A21%3A19)
index.html:
<!DOCTYPE html>
<html ng-app="uwApp">
<head>
<!-- SCROLLS -->
<!-- load bootstrap and fontawesome via CDN -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.css" />
<!-- SPELLS -->
<!-- load angular and angular route via CDN -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-route.js"></script>
<!-- Donut chart api -->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script src="js/app.js"></script>
<script src="js/controllers/maincontroller.js"></script>
<script src="js/controllers/pagecontroller.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body ng-controller="mainController">
<div ng-view></div>
</body>
</html>
app.js
'use strict';
var uwApp = angular.module('uwApp', ['uwApp.controllers','ngRoute'])
.config(function($routeProvider) {
$routeProvider
// route for the home page
.when('/', {
templateUrl : 'pages/home.html',
controller : 'mainController'
})
// route for the page
.when('/acknandagreement', {
templateUrl : 'pages/loan/acknandagreement.html',
controller : 'pageCtrl9'
})
// route for the page
.when('/assetsandliabilities', {
templateUrl : 'pages/loan/assetsandliabilities.html',
controller : 'pageCtrl6'
})
// route for the page
.when('/borrowerinfo', {
templateUrl : 'pages/loan/borrowerinfo.html',
controller : 'pageCtrl3'
})
// route for the page
.when('/employmentinfo', {
templateUrl : 'pages/loan/employmentinfo.html',
controller : 'pageCtrl4'
})
// route for the page
.when('/infoandgovpurpose', {
templateUrl : 'pages/loan/infoandgovpurpose.html',
controller : 'pageCtrl10'
})
// route for the page
.when('/monthlyincomeandche', {
templateUrl : 'pages/loan/monthlyincomeandche.html',
controller : 'pageCtrl5'
})
// route for the page
.when('/morttypeandterm', {
templateUrl : 'pages/loan/morttypeandterm.html',
controller : 'pageCtrl1'
})
// route for the page
.when('/propertyinfoandpurpose', {
templateUrl : 'pages/loan/propertyinfoandpurpose.html',
controller : 'pageCtrl2'
})
// route for the page
.when('/residualapplication', {
templateUrl : 'pages/loan/residualapplication.html',
controller : 'pageCtrl11'
})
// route for the page
.when('/txndetails', {
templateUrl : 'pages/loan/txndetails.html',
controller : 'pageCtrl7'
})
// route for the page
.when('/declarations', {
templateUrl : 'pages/loan/declarations.html',
controller : 'pageCtrl8'
})
;
});
pagecontroller.js:
'use strict';
angular.module('uwApp.controllers')
.controller('pageCtrl1', function($scope) {
$scope.page = 'morttypeandterm';
})
.controller('pageCtrl2', function($scope) {
$scope.page = 'propertyinfoandpurpose';
})
.controller('pageCtrl3', function($scope) {
$scope.page = 'borrowerinfo';
})
.controller('pageCtrl4', function($scope) {
$scope.page = 'employmentinfo';
})
.controller('pageCtrl5', function($scope) {
$scope.page = 'monthlyincomeandche';
})
.controller('pageCtrl6', function($scope) {
$scope.page = 'assetsandliabilities';
})
.controller('pageCtrl7', function($scope) {
$scope.page = 'txndetails';
})
.controller('pageCtrl8', function($scope) {
$scope.page = 'declarations';
})
.controller('pageCtrl9', function($scope) {
$scope.page = 'acknandagreement';
})
.controller('pageCtrl10', function($scope) {
$scope.page = 'infoandgovpurpose';
})
.controller('pageCtrl11', function($scope) {
$scope.page = 'residualapplication';
});
maincontroller.js
'use strict';
angular.module('uwApp.controllers', [])
.controller('mainController', function($scope) {
});
I have no clue why its not working. Please suggest.
In pageController.js write like this
angular.module('uwApp.controllers', [])
.controller('mainController', function($scope) {
$scope.page = 'main controller';
})
some Explanation:
Beware that using angular.module('myModule', []) will create the module myModule and overwrite any existing module named myModule. Use angular.module('myModule') to retrieve an existing module.
Find more angular docs module
There is an interesting style guidelines for angular by jonpapa johnpapa/angular-styleguide
Update
I made a working example on plnkr from supplied code. There are a couple things I changed:
1) Since your base route will be running mainController you should not put it on the ng-controller as well.
2) When you are referencing a module, as in the angular.module('uwApp.controllers'), the module must first have been defined. The way to define a module is to have brackets for it's dependencies, like angular.module('uwApp.controllers', []).
With those things fixed you do not need to do what I said below.
There is no need to inject the controllers through a separate module.
You can change pagecontroller.js:
angular.module('uwApp.controllers')
to...
angular.module('uwApp')
Then app.js:
var uwApp = angular.module('uwApp', ['uwApp.controllers','ngRoute'])
to...
var uwApp = angular.module('uwApp', ['ngRoute'])

using directives breaks ng-view in angular, how to?

i have a index.html:
<body ng-app="app">
<topmenu></topmenu>
<div ng-view=""></div>
then inside a views folder i have main.html and topmenu.html
there is a route:
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
and a directive
var App = angular.module('app', []);
App.directive('topmenu', function () {
return {
replace: true,
restrict: 'E',
templateUrl: 'views/topmenu.html'
};
});
the problem is when i include the directive.js file and place the <topmenu></topmenu> tag the main.html doesn't load no more
any ideas?
In your directive file you don't need to initialize a variable with your module and dependencies a second time. So this:
var App = angular.module('app', []);
should be removed from that file.
in directive.js
remove this, it will create a new angular module with name 'app'
var App = angular.module('app', []);
if you want get module from angular you can do
var App2 = angular.module('app');
console.log(App === App2) // true
and make sure you already created your 'app' module before you load directive.js,
for example, if you have 2 JS file
<script src="index.js"/>
<script src="directive.js"/>
in index.js do
var App = angular.module('app', []);

Categories