AngularJS Directives and IIFE Closures - javascript

I am trying to build an angular app "the right way" using various style guides as my inspiration. John Papa's being the most notable. Most say I should wrap angular components in Immediately Invoked Function Expressions (IIFE) and separate them into different files. This works on everything except directives.
Am I doing something wrong or if I should not use IIFEs for directives or use them in a different way?
Here is my jfiddle of it not working:
http://jsfiddle.net/HB7LU/14140/
Here is my jfiddle with it working without IIFEs:
http://jsfiddle.net/8kfpf9aq/
The only difference is wrapping in:
(function() {
'use strict';
//code
});
I have tried it and it works similarly in several version of angular 1, 1.3, 1.4.

I think your problem might be that you're not invoking the IIFE. It should look like this
(function() {
'use strict';
//code
})();
or this
(function() {
'use strict';
//code
}).call(this);

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

Set commentDirectivesEnabled and cssClassDirectivesEnabled to false in Angular

I'm attempting to make some small tweaks to my config to hopefully improve performance slightly. I read through the Angular docs here and they mention disabling comment and CSS class directives. I tried to do so with the below code in my config, but I keep getting TypeError: $compileProvider.commentDirectivesEnabled is not a function or TypeError: $compileProvider.cssClassDirectivesEnabled is not a function errors.
Note: I'm running Angular 1.4.9
'use strict';
angular.module('app')
.config(compilationConfig)
;
compilationConfig.$inject = ['$compileProvider'];
function compilationConfig($compileProvider) {
$compileProvider.debugInfoEnabled(false);
$compileProvider.commentDirectivesEnabled(false);
$compileProvider.cssClassDirectivesEnabled(false);
}
Solved this myself. This functionality was introduced in 1.6.0 so you need to upgrade to take advantage of these methods.

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

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.

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')

AngularJS not working when paired with RequireJS. Any ideas?

I am trying to build a very simply demo to get AngularJS working with RequireJS.
Up to this point I have been closely following this tutorial.
I have defined a main.js file, which requires both app.js and hello.js, which are both called in turn.
app.js defines a new Angular module and returns it. hello.js then adds a controller named 'Hello' to the module.
In the page itself, the div should output 'Hello', which is returned by the sayHello method in the Hello controller. However, all my browser shows is {{sayHello}}.
I think your setup breaks the Angular bootstrap system. So you have to add the manual boostrap procedure in your hello.js file.
require(["app"], function(app) {
app.controller("Hello", ['$scope', function($scope) {
console.log('function entered');
$scope.sayHello = function() {
console.log('Hello');
return "Hello";
}
angular.element(document).ready(function() {
angular.bootstrap(document, ['app']);
});
}]
);
});
Well, it seems like Shay Friedman's solution worked.
I had seen Angularjs + RequireJs + Express Seed mentioned before, but I was sure there was a way to do the same thing by itself without too much effort. However, it seems like using this project is probably the easiest solution.

Categories