AngularJS - Directive not recognizing controller - angularjs

If I have a directive and a controller in the same file:
var app = angular.module('app.navigation', []);
app.controller('NavItemCtrl', [ ....])
app.directive('navItem', [
'ribbon', '$window', function (ribbon, $window) {
return {
require: ['^navigation', '^?navGroup'],
restrict: 'AE',
controller: 'NavItemCtrl',
...
}])
Everything is fine, but if I move the controller code to a different file, because the current file is becoming too clutered, using the same module, and referencing the new controller file in my index page, the directive screams
p0=NavItemCtrl&p1=not aNaNunction got undefined
My index page is like this:
<html>
<body>
....
<script app.js ...>
<script new controller file path .... >
<script original directive file path .... >
....
</body>
</html>
What am I missing here?
[Solution] Delta is right, I figured it out:
For good housing keeping, I think it may be wise to have one JS file, listed as a dependency in the main app.js, that instantiates all the modules you will use, assuming your project is becoming large, and then reuse that instantiate w/o having any dependencies.
As example:
(1) Main App:
angular.module('MainApp', ['ngRoute', 'ngAnimate', 'app.SubApp1', 'app.SubApp2', 'app.SubApp3' ...]
(2) Then as a repository, if you will, create a new js file, say repositoryApp.js, instantiating these sub apps, making sure that this file is referenced before all other files that will use these sub app modules:
angular.module('app.SubApp1', [xxx]);
angular.module('app.SubApp2', [xxx]);
angular.module('app.SubApp3', [xxx]);
(3) Then when creating a series of directives, controllers, or whatever pertaining to a particular sub app, merely reference that sub app in the respective file as:
angular.module('app.SubApp1').controller('foo') .....
angular.module('app.SubApp1').directive('bar') .....
Without the dependency brackets as that is what threw the error for me.

in your directive are you getting you app like this
var app = angular.module('app.navigation');
if you put the brackets after it like your first example you will just be replacing what you have currently instead of getting it.
This get a new module
var app = angular.module('app.navigation', []);
This gets an existing modules.
var app = angular.module('app.navigation');
Notice the exclusion of the brackets in the second example.

Related

angular-ui: where is the page $scope inside a <script> element? For a google chart

I'm trying to add a chart to code created by others.
I understand a bit of angular, only...
I'm using angular-ui, so I don't have access to the HEAD tag where the simple Google instructions say to put the SCRIPT tags. I tried putting it later in the html, with other SCRIPT tags, but it kept saying "google" was undefined.
Finally, it seems to work if I put it inside the onload function:
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
drawCharts = function() {
var is = issue;
... create the chart using data inside $scope.issue
}
// google.charts.load( -- DOESN'T WORK HERE, google is undefined
$(window).load(function () {
// finally, in here, 'google' is defined
google.charts.load('current', {'packages': ['corechart', 'bar']});
google.charts.setOnLoadCallback(drawCharts);
}
PROBLEM: drawCharts() needs to access the $scope, but here there's no access to $scope, so my angular data isn't accessible and drawCharts() fails.
So somewhere I need to connect
google.charts.setOnLoadCallback() and $scope
How?
I found one question where the person had a:
$rootScope
.$on('$viewcontentLoaded', function(...)
But he has it in main.js, and I don't have a main.js.
I tried putting it in my controller for the page, but it doesn't define $rootScope. I tried adding $rootScope to the parameters passed to the first line of my controller:
people.controller("voterIssueCtrl", function ($rootScope, $scope, $http, $cookieStore, $window, ClIENT
And that took care of the undefined $rootScope, but the $viewContentLoaded function was never called (it just contained a console.log() message...)
Perhaps my app.js is his main.js.
But it references the controller by name, so it probably loads it, so it probably can't reference something the controller defines.
Help?
===============
I pulled a google chart directive from the web
added the tag in index.html to pull it in
and added the directive to my module definition.
(Of course I forgot the 2nd one and the code didn't complain...)
Nothing. But no complaint that Google wasn't known...
Putting in sample data helps.
In the grand style of js and angular, it doesn't complain if the data isn't exactly in the form it needs...
If only Angular2 + Typescript had been invented sooner...

Controller in separate file throws error

I am moving my controllers from one unique file containing my whole app to separate files and get that error : "Error: [ng:areq] Argument 'MainCtrl' is not a function, got undefined"
I used the setting method to define my app in app.js :
var app = angular.module('CMT', ['ui.router', 'angularCharts', 'uiSwitch']);
I then created a file MainCtrl.js with :
angular.module('CMT').controller('MainCtrl', [
'$scope', 'reviews', '$location',
function($scope, reviews, $location){
}]);
And I have included the files in index.html after including the angular source code :
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
<script src='library/d3.min.js' type='text/javascript'></script>
<script src='library/angular-charts.min.js' type='text/javascript'></script>
<script src="node_modules/angular-ui-switch/angular-ui-switch.min.js"></script>
<script src="app.js" type='text/javascript'></script>
<script src="MainCtrl.js" type='text/javascript'></script>
Any hint or solution ?
Try the following:
In your app.js, inject your MainCtrl.js, like:
var app = angular.module('CMT', ['ui.router', 'angularCharts', 'uiSwitch', 'CMT.MainCtrl']);
And in your MainCtrl.js:
angular.module('CMT.MainCtrl', [])
EDIT:
An AngularJS module is a container. In every Angularjs app, you have one "main" module, and typically many sub-modules. These sub-modules are useful for modularizing/separating your app into components, like controllers, services etc. Initially you had one main module, which also contained the code for your controller. When you decided to move your controller out of the main module, what you wanted to do was move it into a sub-module.
So there were two problems with what you did:
You named your controller module (which is your sub-module in this case) the same name 'CMT' as that of your app/main module. Your sub-modules need to have unique names, and it is good practice to use the . separator - see this Angular style guide.
You didn't "link" your controller module to your app module in an Angular way. Just adding the script to your html isn't enough. If you have a sub-module called CMT.MainCtrl, you need to inject it into your main CMT module.
Judging by your naming convention MainCtrl.js versus something like controllers.js, I'm guessing you're organising your code by feature, instead of by type? In any case, read Angular best practices for more info on Angular directory structure.
Specify all your services/controllers/filters/directives files before the app.js file
<script src="MainCtrl.js" type='text/javascript'></script>
<script src="app.js" type='text/javascript'></script>
Note: you don't need to care about these file orders if you bundle all your script files into single file

registerModule with dependencies

I'm building an app with MEAN.JS and I'm trying to use a controller from another module. I've found that I can do this with dependency injection:
angular.module(‘MyModule’, [‘Dependency’]);
But the way modules are created in MEAN.JS is:
ApplicationConfiguration.registerModule('MyModule');
And I can't just pass a second parameter to registerModule. So, how should I do this? Do I have to use both methods? Am I doing it wrong?
Example
I want to add a new model: Campaign. Campaigns are created by admins only, but can be seen by the "campaign owner" (another User). The create campaign form should list available Users, so the admin can select the one that's going to be the "owner" of that Campaign.
The problem is, the create campaign form is controlled by CampaignsController, how can I list Users? I've used another controller (UsersController) and thats the problem, it is undefined because we are in the Campaign module.
EDIT:
The problem was grunt autorestarting the app incorrectly:
I moved the controller from one module (folder) to another, but grunt was still trying to load it from the old path, and thus failing: Controller not found. I thought the problem was dependency injection, but you only have to close grunt (Ctrl+C) and run it again. Problem solved.
Anyways, thanks for the answer #gilBirman cause it is correct: there is no need to inject anything with MEANJS.
MEAN.js makes all the modules registered via registerModule available to all other modules in your app by adding it as a dependency to the main app called mean. Here's the part of the MEAN.js source code that does this:
var applicationModuleName = 'mean';
....
// Add a new vertical module
var registerModule = function(moduleName) {
// Create angular module
angular.module(moduleName, []);
// Add the module to the AngularJS configuration file
angular.module(applicationModuleName).requires.push(moduleName);
};
So you're on the right track, however it sounds like you are trying to inject a controller. However, in angular, controllers are not injectable. You can inject services, factories, values, and constants.
First create your own module for example:
angular.module('app.controllers', []) - angular module with controllers.
then add controller to that module:
angular.module('app.controllers', [])
.controller('dashboard.admin.account.controller', ['$scope', ($scope) { .... }]);
then create global module which will bind to your markup:
angular.module('app', [
'app.controllers'
'ui.router',
'ngAnimate'
]);
then bootstrap your global module to markup:
domReady(function () {
angular.bootstrap(document, ['app']);
});
Now you can use your controller.

Can I divide up my app.js file into multiple files in Angular JS?

In my app.js file I have my Angular code like this:
var app = angular
.module('app',
['...'])
.config([
'...',
function (
...) {
}])
.factory('requestInterceptor', function ($q, $rootScope) {
..
return {
..
};
})
Is it possible for me to move the code for the config and the factory out of the file and if so then how do I link this up to the app variable?
I have an app setup this way.
What you can do is declare the module in one file before and separate from everything else. Then just make sure it's the first script file referenced in your HTML.
After that you should be able to just add factories, configs and what not to the app in other files.
Yes. If you define a module, app:
angular.module('app',[]); // Including the [], or list of module dependencies
then you can refer to it later, in other files, by calling module without the second parameter:
angular.module('app').factory('requestInterceptor',...
It is confusing: module is used for both creating a new module, and to add to an existing one, depending on whether you have passed an array as its second parameter.

Retrieve AngularJS app name

How can I retrive the name of the current app in AngularJS?
I mean the ng-app="foo" value.
I have searched through the API documentation, but I could not find any reference to this.
MY SOLUTION
Actually I have found solution like this
angular.element($('[ng-app]')).attr('ng-app');
But I don't really like the idea to search through DOM just to get this information.
Do you know a better solution?
From the $rootElement docs:
The root element of Angular application. This is either
the element where ngApp was declared or the element passed into
angular.bootstrap.
If you inject it you can get the main module name without scanning the DOM:
<html ng-app="myApp">
...
app.controller('MyCtrl',
[
'$scope',
'$rootElement',
function($scope, $rootElement) {
console.log($rootElement.attr('ng-app')); // --> myApp
}
]
);

Resources