Why controllers is being created 2 times in my AngularJS + RequireJS application? - javascript

I am creating small application called puzometr. It is for educational needs only. I want to create this application using AngularJS. Also, I want to use RequireJS as module system.
I have strange problem. I created my test controller and I got problem: controller initialization fires two times.
Firstly, full code available here on GitHub (wait, don't click me, I will explain everything below).
So, problem is in myCtrl.js file. Here is code of this file:
define(['angular'], function (angular) {
var module = angular.module('main.myModule', []);
module.controller('main.myCtrl', function ($scope) {
console.log($scope.$id);
$scope.bob = function () {
}
})
});
It is included in main/controllers/controllers.js by this:
define(['app', 'main/controllers/myCtrl'], function (app) {
var module = angular.module('main.controllers', ['main.myModule']);
});
This file included in main.js by this code:
angular.module('main', ['ngRoute', 'main.services', 'main.controllers', 'main.directives']);
And main.js is included into app.js:
var app = angular.module('myApp', ['ngRoute', 'main', 'common']);
So, I incidentally noticed, that function definition in myCtrl controller fired two times. I put console.log there and saw this:
Can you please explain me why is this happens? Why controller is being initialised two times?
Also, I have this in ng-inspector:
So one scope is created as child for another scope. Notice, that scope with id 3 has correct controller name.

If you use ng-route to register controllers and bind them with views, then don't add them again using attributes in your html files.

Related

How to define controllers in separate files

Suppose that I have an SPA written via AngularJS 1.x.
It has a single app module defined like this:
var app = angular.module('app', ['ngAlertify', 'ngRoute', 'ui.bootstrap'])
I also have several controllers which are defined in separate *Ctrl.js-files. What is the appropriate way to define them?
I see two options here. The first one is
app.controller('LoginCtrl', function($scope) { /* ... */ });
and the second one is
angular.module('app').controller('LoginCtrl', function($scope) { /* ... */ });
Which one is better and most common-used practice? Is there any downsides of using either of them?
If I understand your question correctly then you wan to know different between
app.controller('LoginCtrl', function($scope) { /* ... */ });
vs
angular.module('app').controller('LoginCtrl', function($scope) { /* ... */ });
In above two in first method app is a global object which you declared somewhere i.e. in app.js like
var app = angular.module('app',[]);
In this case app is a global variable which will be accessible throughout your entire application. which I believe is not a good thing to use global variable
in our application.
In second method we are using global angular object to create a controller so that in this we will not be using global variable. In this case app.js will look like
(function(){
'use strict';
var app = angular.module('app', []);
....
....
....
....
})
In this case app variable will not be available anywhere apart from this file.
So I belive second method is better than first one.
My personal preference is to use app.controller('LoginCtrl', function($scope) { /* ... */ }); as this makes it easier to reuse the controller in another project with little to no changes, without those annoying module not found errors because you forgot to rename the module when reusing the file
I think that depends a bit on the personal style of writing. One thing is that while working with AngularJS 1.x.x you can have different styles of writing code, method stacking etc.
Personally, I prefer app.controller('LoginCtrl', function($scope) { /* ... */ }); mainly because you can easily preview your controller and distinguish it from thge module. Another bonus I see of having a clearly defined separate module is that you can easily check what includes you have ('ngAlertify', 'ngRoute', 'ui.bootstrap').
Most commonly used as far I have seen, even here on SO, is the method that I previously mentioned. Yet again this is something that is more reflective of personal style rather than strong pre-requirements of writing code. I hope that helps to some extend.
None of the above. The purpose of modules is to keep the application modular and not pollute global scope.
You can have var app = ... but this should be done inside IIFE once per file.
Another issue with modules is the precedence. If the application uses angular.module('app') module getter, the files should be loaded in specific order, in order for the module to be defined when it is retrieved in other files. This creates problems if they aren't, for example when they are concatenated in alphabetic order.
The solution is to use one module per file. This makes the application truly modular, independent of file loading order, also benefits testability. See also this answer for how this pattern supposed to work.
You can use module setter and getter methods for implementation of controllers in different file.
Suppose myApp.module.js
angular.module('myApp', []); //Setter method, registring module
In myApp.homeCtrl.js
var myApp = angular.module('myApp'); // getter method, getting the module already registered.
myApp.controller('homeCtrl', [function()]{ })
For more info check this https://toddmotto.com/angular-modules-setters-getters/
The second approach your are taking about is better because it uses the already created module and doesn't create the new module but with the first approach you are using global variable that is not recommended

Angularjs: inject Controller on module inside anonymous function

I am a bit newbiew with javascript and i am starting to use angular.js
So my question is if there is a way to inject a controller inside a module that is declared in an anonymous function
my code looks like this
app.js
(function(angular) {
var app = angular.module('Organizer', ['ngMaterial', 'ngAnimate', 'ngAria']);
})(angular);
siteController.js
(function(angular, app) {
app.controller('site', function($scope, $mdDialog)
{
var alert = $mdDialog.alert({
title: 'Test',
content: 'Testing',
ok: 'Exit'
});
$mdDialog.show(alert);
});
})(angular);
i have tried to look for ways if it is possible, but still i would like to see if anyone here could explain how this can be made if it could.
Note: I have already used angular.js before and i wanted to try a different way to declare controllers so the client wont have any way to modify it
If you create a module in Angular, then you can not obfuscate it in this way. In the console, a user can just run angular.module('Organizer') to get access to your app, and then call any method they want on it.
The reason your code won't work as written, is because you are not passing the app variable to your anonymous function. So if you want to add a controller to the Organizer module, then you would do something like this:
(function(angular)
{
angular.
module('Organizer').
controller('site', function($scope, $mdDialog)
{
...
});
})(angular);
Theres no need to wrap any of this code in self executing functions as if you are trying to keep variables out of the global scope. The only one that's global is the "angular" object.
Your app.js should only have
'use strict';
angular.module('Organizer', ['ngMaterial', 'ngAnimate', 'ngAria']);
You controller file should only have
'use strict';
angular.module('Organizer').controller('siteController', function($scope, $mdDialog) {
var alert = $mdDialog.alert({
title: 'Test',
content: 'Testing',
ok: 'Exit'
});
$mdDialog.show(alert);
});
The first call to module in app.js passes the second parameter which angular uses to instantiate your module. Subsequent calls that omit the second parameter "get" the module.

adding another module dependency in angularjs, the application stops working

I ran into a weird problem that I could not figure out, I could not get a good explanation even after searching on the internet.
I have a application (webpage) which consists of ui-bootstrap's accrodion element which gets the data from a json file by $http request. This part is working perfectly fine. Now I wanted to add a multiselect dropdown and I wanted to use the element provided in ui-select. But when I add the dependencies 'ngSanitize' and 'ui-select' in the module, the application doesn't work. I haven't added any dropdown elements, just the dependencies. I don't understand where the problem is.
The original application controller
var app = angular.module('callApp', ['ui.bootstrap']);
app.controller('firstController', function($scope, $http, $modal, $log) {
//some functions are defined here
});
angular.module('callApp').service('popupService', function () {
//service is defined
});
Then i added the dependencies ngSanitize and ui.select
var app = angular.module('callApp', ['ui.bootstrap', 'ngSanitize', 'ui.select']);
app.controller('firstController', function($scope, $http, $modal, $log) {
//some functions are defined here
});
angular.module('callApp').service('popupService', function () {
//service is defined
});
Now the application doesn't work. I haven't modified any other function or added any elements in the html. Why does such a problem arrive? Is there anything wrong with the declaration?
Have you added the reference to the js files to your html page too?
What errors do you see in the console (press F12)?
If the reference to the js files exist in your html then just check the paths are correctly pointing to the actual path.
Regards,

Initialize Angular Service (factory) when application start

In my Angular application I adding tracing functionality, which should work as separate plugin, so if script included into HTML Angular should create service and initialize (run) it. Plugin is service because it has mandatory dependency on $rootScope.
For implementation I select to use Angular factory, like (code is in myservice.js):
angular.module('app').factory('mysevice', ['$rootScope', '$interval', serviceFunc]);
function serviceFunc($rootScope, $interval) {
return {
run: function () { ... }
}
}
And now I have problem how to immediately initialize it. My solution is to enhance Angular app run function (code is in myservice.js):
window.app.run(['mysevice', function (srvc) {
srvc.run();
}]);
Where app defined in separate main app.js file like:
var app = window.app = angular.module('app', [...]);
app.run(['$state', 'breeze', ...,
function ($state, breeze, ...) { ..real initialization.. }
The code is working fine. Both main run and run for myservice calls are fine. The application together with the service are working well, but the code looks ugly, especially storing the app in the global window object and multicasting the run function.
Is there a better way to do Angular service and initialize it immediately after app starts with some other Angular services dependencies.
You can call angular.module('app').run(function(){...}). So you will not need a global variable anymore.
Example:
angular.module('app').run(['mysevice', srvc.run.bind(srvc)]);

Yeoman Angularjs How to Implement Directive

I'm trying to get my feet off the ground with Yeoman + Angular and going through the tutorials, I can't get even the most basic directives to fire, even when I try them exactly the same as in the tutorials.
Could someone please lend some insight as to what I'm missing, I've been struggling with this for the past 2 days
HTML template - ng-resize is the intended directive
<body ng-app="mvmdApp">
....
<div ng-mousemove="onMouse($event)" ng-resize="" class="youtube-cover ng-scope">
<div class="youtube-unit"></div>
</div>
// controllers/youtube.js
'use strict';
angular.module('mvmdApp').controller('YoutubeCtrl', function($scope) {
console.log('hi');// fires
return $scope.onMouse = function(e) {}// fires
// directives/resize.js
'use strict';
angular.module('mvmdApp', []).directive('ngResize', function($window) {
return function(scope) {
return console.log('directive');// does not fire
};
});
The strange thing is that whenever I even call angular.module('mvmdApp', []) like so from the directive script, it blocks the view from rendering.
edit: Also I noticed that when I load the directive before all the other scripts, it doesn't block the html from rendering, but it still doesn't trigger the directive. I don't know if/how the load order of angular scripts matters as I don't know where to find that.
You are declaring the module multiple times. You can simplify this by doing the following:
In app.js:
'use strict';
var myApp = angular.module("mvmdApp", []);
myApp.config(function($routeProvider, $locationProvider) {
...
});
In youtube.js:
'use strict';
myApp.controller('YoutubeCtrl', function($scope) {
...
});
An in resize.js:
'use strict';
myApp.directive('resize', function($window) {
...
});
Updated plunker at http://plnkr.co/edit/Im4SpcyH4cIem6TDWZaG?p=preview. Also, I would refrain from calling the directive "ng-resize" as the ng prefix is usually used by the angular team. In this case, the directive is simply "resize".
This may not solve your issue but one mistake i see is
angular.module('mvmdApp', []) been declared at multiple places, resize.js and app.js. This format declaration creates a new module everytime with this name.
This should be called once only from app.js. In resize.js it should be angular.module('mvmdApp')

Categories