AngularJS Modular Set up - javascript

Up until recently, I have been throwing all my function into one large JS file. I am now trying to break these into small modules to make my application more portable per say.
I have my core js file (main.js) with the following code:
var App = angular.module("app", ['ui.bootstrap', 'angularMoment', 'chieffancypants.loadingBar', 'ngAnimate', 'ui.sortable', 'ngSanitize'], function ($interpolateProvider, $httpProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
$httpProvider.defaults.transformRequest = function (data) {
if (data === undefined) {
return data;
}
return $.param(data);
};
$httpProvider.defaults.headers.post['Content-Type'] = ''
+ 'application/x-www-form-urlencoded; charset=UTF-8';
$httpProvider.defaults.headers.post['X-Requested-With'] = ''
+ 'XMLHttpRequest';
});
In another file (i.e. blog.module.js), I have the following:
(function(window, angular, undefined) {
'use strict';
angular.module("app", [])
.controller('Blog', ['$scope', function ($scope) {
alert('test');
}]);
});
While the main.js file loads along with all its dependencies, the second one doesn't get loaded. The controller is basically not found. Can anyone give me pointers as to where I may be going wrong.?
Thanks

The sintax in blog.module.js looks like you are trying to create two modules with same name 'app'.
Change your controller module like this
(function(window, angular, undefined) {
'use strict';
angular.module("app")
.controller('Blog', ['$scope', function ($scope) {
alert('test');
}]);
});

I quote you :
App = angular.module("app", ['ui.bootstrap',
...
angular.module("app", [])
You cant redeclare a module you can either reopen it
App = angular.module("app", ['ui.bootstrap',
...
angular.module("app")
or create another one
App = angular.module("app", ['ui.bootstrap', 'app.controller'
...
angular.module("app.controller")

Related

Dependency injection hell, what is expected?

I'm trying to separate components into several files for a simple application but angular's dependency injector is giving me headaches and I don't really know what is expected.
Unknown provider: servicesProvider <- services <- maincontroller
Is the error I'm getting.
app.js
//Application definition with injected dependencies
var app = angular.module('leadcapacity', ['services', 'utils', 'customfilters', 'controllers']);
services.js
var services = angular.module('services', []);
services.service('xrmservice',
[
'$http', function($http) {
var oDataUrl = Xrm.Page.context.getClientUrl() + '/XRMServices/2011/OrganizationData.svc/';
var service = {};
service.query = function(entitySet, query) {
return $http.get(oDataUrl + entitySet + '?' + query);
};
return service;
}
]);
controllers.js
var ctrls = angular.module('controllers', ['utils', 'services']);
ctrls.controller('maincontroller',
function ($scope, services, utils) {
};
});
And the include order in index.html
<script src="service.js"></script>
<script src="controllers.js"></script>
<script src="app.js"></script>
Looks fine to me. I know this is perhaps not the best way to organize things, but getting a "Hello world" first would be nice.
Thanks.
Error message appearing in console clearly says that, services
dependency isn't exists in the module.
You have injected incorrect service name in maincontroller controller factory function, basically you were trying to to inject services(module name) instead of xrmservice(service name)
function ($scope, services, utils) {
should be
function ($scope, xrmservice, utils) {
Additional
Do follow Inline Array annotation of DI, as you were already used the same in your xrmservice service JS file, so that in future you don't need to go back and change that when you face javascript minification related issues.
Controller
ctrls.controller('maincontroller', [ '$scope', 'xrmservice', 'utils',
function ($scope, xrmservice, utils) {
//code goes here
//....
};
}]);
Although you have injected them into the module, you need to give them to the function so you can use the injected modules
ctrls.controller('maincontroller',
['$scope', 'services', 'utils', function ($scope, services, utils) {
};
}]);

Using Browserify with Angular JS - - Passing a service into a Controller

As the title suggests I've recently started a new project where I'm using Browserify (and Gulp) to concatenate my Angular JS files (and the Angular sourcefile) into a single file - bundle.js.
I've decided to split my controllers, services and directives into separate files and then "require" them into my app.js file using Browserify like this:
(function () {
'use strict';
require('angular');
var tabCtrl = require('./controllers/tabs'),
dataService = require('./services/');
angular.module("citiToolsApp", [])
.service('dataService', ['$scope', dataService])
.controller('TabController', ['$scope', tabCtrl]);
}());
However when I try to access my service - dataService - from within my Tab Controller like this:
module.exports = function($scope, tabController) {
dataService.getPrograms(function (response) {
console.log(response.data);
});
};
I get an undefined error. I believe I need to pass dataService into the tabController but I'm unsure on the syntax to do this. Can anyone help with this?
Thanks
EDIT
I've also added the contents of my service file for further detail:
module.exports = function($http) {
this.getPrograms = function(callback) {
$http.get('/programs')
.then(callback);
};
};
I've realised my own mistake. I needed to pass in $http rather than $scope. So instead of:
(function () {
'use strict';
require('angular');
var tabCtrl = require('./controllers/tabs'),
dataService = require('./services/');
angular.module("citiToolsApp", [])
.service('dataService', ['$scope', dataService])
.controller('TabController', ['$scope', tabCtrl]);
}());
It should be:
(function () {
'use strict';
require('angular');
var tabCtrl = require('./controllers/tabs'),
dataService = require('./services/');
angular.module("citiToolsApp", [])
.service('dataService', ['$http', dataService])
.controller('TabController', ['$scope', tabCtrl]);
}());

Putting app, controllers & services in separate files

I'm trying to move angular code into separate files before the project grows too big.
I tried moving the app, controllers and services into separate files but the errors stopped referencing points in the code (or they were too generic).
I have decided to put the file contents in on big <script> tag so I can work through the errors and get it working. Unfortunately I have come across this (Failed to instantiate module protonApp due to...) and don't know how to track the problem down (I'm new to angular)
The
(function () {
'use strict';
...
}());
I have round the code is because the (little) research I have done says you should have your code between these when they are in separate files.
(function () {
'use strict';
var app = angular.module('protonApp',['ui.router','protonAppControllers','protonAppServices']);
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
...
}]);
app.value('debug',true);
app.run(function($rootScope,$state,$http,debug,LeftMenuService) {
...
});
}());
(function () {
'use strict';
angular.module('protonAppControllers', ['$scope','$http','LeftMenuService']);
}());
(function () {
'use strict';
angular.module('protonAppServices', ['$rootScope','$http']);
}());
(function () {
'use strict';
angular.module('protonAppControllers').controller('loginController',['$scope','$http','$state',function($scope,$http,$state){
...
}]);
}());
(function () {
angular.module('protonAppControllers').controller('surveyListController',['$scope','$http','LeftMenuService',function($scope,$http,LeftMenuService){
...
}]);
}());
(function () {
'use strict';
angular.module('protonAppControllers').controller('surveyHelpController',['$scope','$http','LeftMenuService',function($scope,$http,LeftMenuService){
...
}]);
}());
(function () {
'use strict';
angular.module('protonAppServices').service('LeftMenuService', function($http,$rootScope){
...
});
}());
EDIT
Further digging reveals I can not access $rootScope or $scope inside any of my controller files
In your module injection you don't have to add $scope and $http :
angular.module('protonAppServices', []);
Inject these in the controller but not in the module declaration
You dont need to inject anything while declaring a module, you could use them in you controller as mentioned #ThibauDL
I usually prefer declaring the modules just above the angular app declaration.
I have modified your a code in plnkr which should give you an idea as to how the code must be organized.
(function() {
'use strict';
angular.module('protonAppControllers', []);
angular.module('protonAppServices', []);
var app = angular.module('protonApp', ['ui.router', 'protonAppControllers', 'protonAppServices']);
app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
//...
}
]);
app.value('debug', true);
app.run(function($rootScope, $state, $http, debug, LeftMenuService) {
//...
});
}());
(function() {
'use strict';
angular.module('protonAppServices').service('LeftMenuService', function($http, $rootScope) {
//...
});
}());
(function() {
'use strict';
angular.module('protonAppControllers').controller('loginController', ['$scope', '$http', '$state',
function($scope, $http, $state) {
$scope.login = "Hi Please login!";
// ...
}
]);
}());
(function() {
angular.module('protonAppControllers').controller('surveyListController', ['$scope', '$http', 'LeftMenuService',
function($scope, $http, LeftMenuService) {
//...
}
]);
}());
(function() {
'use strict';
angular.module('protonAppControllers').controller('surveyHelpController', ['$scope', '$http', 'LeftMenuService',
function($scope, $http, LeftMenuService) {
$scope.test = "Hxxxxi";
//...
}
]);
}());
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="protonApp">
<div ng-controller="loginController">
<input type="text" ng-model='login' />
</div>
</body>
Also you could now place them in separate files as you wanted.
Hope that helps.

angularjs add new dependency

I want to add a new dependency, the 'angular-file-upload' dependency, but what ever I do, my app crashes, I can't understand how it works. What I've got now is:
in app.js
var myApp = angular.module('myApp', ['ui.bootstrap']);
in appController.js
myApp.controller('appCtrl', ['$scope', function ($scope) {
I've got all necessary resource files (angular-file-upload.js) and references to them, I just don't know how to properly inject the new dependency. I'm thinking I only need to edit the two provided lines, or do I have to create a whole new controller, and if so, what should that look like?
It says that my question is a possible duplicate of another, but on the other question it's about injecting dependencies into config() modules, this is not the case here.
Assuming you mean this project: https://github.com/danialfarid/ng-file-upload
then the snytax is like this:
var myApp = angular.module('myApp', ['ui.bootstrap', 'angularFileUpload']);
myApp.controller('appCtrl', ['$scope', 'FileUploader', function ($scope, FileUploader) {
}]);
The example below describes how to inject the stuff you would like to use. It is from here
//inject angular file upload directives and services.
var app = angular.module('fileUpload', ['ngFileUpload']);
app.controller('MyCtrl', ['$scope', 'Upload', function ($scope, Upload) {
^^^^^^^^ ^^^^^^
$scope.$watch('files', function () {
$scope.upload($scope.files);
});
$scope.upload = function (files) {
if (files && files.length) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: 'upload/url',
fields: {'username': $scope.username},
file: file
}).progress(function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name);
}).success(function (data, status, headers, config) {
console.log('file ' + config.file.name + 'uploaded. Response: ' + data);
}).error(function (data, status, headers, config) {
console.log('error status: ' + status);
})
}
}
};
}]);
Add the dependency to the Angular instance
var myApp = angular.module('myApp', ['ui.bootstrap', 'angularFileUpload']);
And add into your controller:
myApp.controller('appCtrl', ['$scope', 'FileUploader', function($scope, FileUploader) {
See the example on their Git page https://github.com/nervgh/angular-file-upload/blob/master/examples/simple/controllers.js
You need following ways.
If you have FileUploader.js file
track the files to your main html page after angular.js script before main.js(app.js)
Then configure it by this way
var myApp = angular.module('myApp', ['ui.bootstrap', 'fileUpload']);
myApp.controller('appCtrl', ['$scope', 'fileUpload', function ($scope, fileUpload) {
// Your code
}]);
If you have any doubt, please see this discussion :- Injecting Dependencies in config() modules - AngularJS
From the angular-file-upload wiki:
Add the dependency in your module declaration, these will be all the angular modules your application needs.
var myApp = angular.module('myApp', ['ui.bootstrap', 'angularFileUpload']);
To use its components in your controller you'll have also to inject FileUploader so you can access its API.
myApp.controller('appCtrl', ['$scope', 'FileUploader', function ($scope, FileUploader) {
You should write it like following:
var myApp = angular.module('myApp', ['ui.bootstrap', 'angular-file-upload']);
That's it. The dependence module should work fine.
You have to add the file to your angular.module:
var myApp = angular.module('myApp', ['ui.bootstrap', 'angular-file-upload']);
And import the file (for example in your index.html):
<script src="yourpath/ui-bootstrap-tpls.js"></script>
<script src="yourpath/angular-file-upload.js"></script>
If you correctly install your dependency, it should works :)

All AngularJS Controllers Not Loading with LazyLoad

I am trying to lazy load my controllers for my AngularJS app I built along side with requireJS. I have created a custom "lazyLoad" library that creates a resolve object in app.config() routes (also I am using ui-router). If I code the state (without my library) to look like so it works
define(['angular', 'lazyLoader', 'uiRouter'], function(angular, lazyLoader, uiRouter){
var app = angular.module('myApp', ['ui.router']);
app.config(function ($stateProvider, $urlRouterProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
window.lazy = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
$urlRouterProvider.otherwise('/');
$stateProvider
.state('campaigns', {
url:'/campaigns',
views: {
"top-nav" : {
templateUrl: 'views/home/top-nav.html',
resolve : {
load : ['$q', '$rootScope', function($q, $rootScope){
var d = $q.defer();
require(['../app/controllers/header-controller'], function() {
$rootScope.$apply(function(){
d.resolve();
});
});
return d.promise;
}]
}
},
"fullpage": {
templateUrl: 'views/home/index.html',
resolve : {
load : ['$q', '$rootScope', function($q, $rootScope){
var d = $q.defer();
require(['../app/controllers/home-controller'], function() {
$rootScope.$apply(function(){
d.resolve();
});
});
return d.promise;
}]
}
//controller: 'home-controller'
}
}
});
});
return app;
});
If I attempt to replace the resolve object with my library function it looks would look like this:
define(['angular', 'lazyLoader', 'uiRouter'], function(angular, lazyLoader, uiRouter){
and
.state('home', lazyLoader.route({
url:'/',
views: {
"top-nav" : {
templateUrl: 'views/home/top-nav.html',
controllerUrl: '../app/controllers/header-controller'
},
"fullpage": {
templateUrl: 'views/home/index.html',
controllerUrl: '../app/controllers/home-controller'
}
}
}));
lazyLoader.js
define(function () {
'use strict';
function LazyLoader() {}
LazyLoader.prototype.route = function(config){
var controllerPath;
if(config && config.views){
var singleView = Object.keys(config.views);
for(var i in singleView){
var viewName = singleView[i];
controllerPath = config.views[viewName].controllerUrl;
delete config.views.controllerUrl;
config.views[viewName].resolve = {
load : ['$q', '$rootScope', function($q, $rootScope){
var d = $q.defer();
require([controllerPath], function() {
$rootScope.$apply(function(){
d.resolve();
});
});
return d.promise;
}]
};
}
}
return config;
}
return new LazyLoader();
});
Example Controller
define(['app/module'], function (module) {
lazy.controller('header-controller', ['$scope', function ($scope) {
// stuff here
}]);
});
On a side note I plan on implementing something better than attaching lazy variable to window.
When I code the router like the first example it works. When I use my lazyLoader the one of the two views loads it's controller, the second view's controller's file is started to load (console.logs at the beginning show this) but it cannot resolve "module" in the example above.
link to error: AngularJS Error
Again this issue only happens when using my lazyloader which is producing the same resolve object that I have hard coded in for the version that works.
I have searched high and low and there are a lot of resources out there but I could not find anything that addressed this issue.
Any advice is appreciated!
You are taking too much pain to do lazy loading of controllers & services. There is simple approach to lazy load files with ocLazyLoad. This article might help you resolve the same issue.
https://routerabbit.com/blog/convert-angularjs-yeoman-spa-lazyload/
What you should do is
Add a reference of ocLayzLoad & updated JS files’ reference to load on demand from app.js or .html file of their views.
`bower install oclazyload --save-dev`
Now load the module ‘oc.lazyLoad’ in application. Update app.js file
angular
.module('helloWorldApp', [
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'oc.lazyLoad',
])
Load JS file by adding reference of JS in .html file
<div oc-lazy-load="['scripts/controllers/about.js', 'scripts/services/helloservice.js']">
<div ng-controller="AboutCtrl as about">
Your html goes here
</div>
</div>
If you using Grunt, update Gruntfile to uglyfy, renamed file name & update references in the final .html or .js file.
On the 'myApp' module definition, shouldn't you be returning app variable instead of myApp?
And to avoid exposing lazy to window, you could define it as a property of app variable, this way when you define new functions, you require app first and you can use it:
app.js:
app.lazy = {
controller: $controllerProvider.register,
directive: $compileProvider.register,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
...
return app;
controller.js:
define(['app'], function (app) {
app.lazy.controller('header-controller', ['$scope', function ($scope) {
// stuff here
}]);
});

Categories

Resources