Issue while running browserify on a simple angular app - angularjs

I'm making this very preliminary attempt of using node/npm/browserify to build my angular app. The ./app/controllers, ./app/directives, ./app/services basically have index.js files which in turn require() the js files! Below is the root js file i.e. public/index.js.
require('./app/controllers/');
require('./app/directives/');
require('./app/services/');
var app = angular.module('myApp', ['ngRoute'])
app.config(function($routeProvider) {
$routeProvider
.when("/movie/:movieId", {
template: require('./views/movie.html'),
controller: 'MovieCtrl as movie'
})
.when("/movie/:movieId/scene/:sceneId", {
template: require('./views/scene.html'),
controller: 'SceneCtrl as scene'
});
});
module.exports = app;
Now after running below command i do get a bundle.js however,
browserify public/index.js -o release/bundle.js
However, the below line in bundle.js throws the error "Uncaught ReferenceError: app is not defined"
app.controller('MainCtrl', function ($route, $routeParams, $location, MyFactory) {
Now, i was assuming because var app is specified in index.js it should be accessible in MainCtrl.js. Could someone suggest how i could make this work?
----- Adding some more info ------
app/controllers/index.js contains below code:-
require('./MainCtrl.js')
require('./MovieCtrl.js')
require('./SceneCtrl.js')
And MainCtrl.js contains below code:-
app.controller('MainCtrl', function ($route, $routeParams, $location, MyFactory) {
//...
})

I don't know where the line in your code is... it isn't clear from the question, but anyway:
Now, i was assuming because var app is specified in index.js it should be accessible in MainCtrl.js.
That assumption is false. You will need to pass in a reference to whatever you need when you instantiate whatever you included.
For example..
var mainCtrl = new MainCtrl(app);

Ok, so i kind of understood what was going on. var app is local and cannot be accessible anywhere else. Once i set app to the global scope (which is obviously a horrible thing!) and required files after declaring app, it worked. This is mostly not the correct way of doing it, but as i mentioned this was a very preliminary attempt.
app = angular.module('myApp', ['ngRoute'])
app.config(function($routeProvider) {
$routeProvider
.when("/movie/:movieId", {
template: require('./views/movie.html'),
controller: 'MovieCtrl as movie'
})
.when("/movie/:movieId/scene/:sceneId", {
template: require('./views/scene.html'),
controller: 'SceneCtrl as scene'
});
});
require('./app/controllers/');
require('./app/directives/');
require('./app/services/');

Related

$controller is not a function error for single page applications

I am very new to Angularjs. I have a single page application where index.html is the root page.it contains below content
index.html
//links to other pages
//ng-view
I have an app.js file linked to index.html which loads the respective pages when user clicks on links in index.html using ngRoute.
my app.js page looks something like this
app.js
'use strict';
angular.module('myApp', [ 'ngRoute', 'ngAnimate', 'ngSanitize',
'ui.bootstrap', 'checklist-model', 'blockUI','isteven-multi-select' ]);
var App = angular.module('myApp');
//ngroute code
Now a page search_name.html and search_name_controller.js loaded when user clicks on one of the links in index.html
search_name_controller looks something like this.
search_name_controller.js
'use strict';
App.controller('SearchCifCtrl', [ '$scope', '$location', '$uibModal',
'WorkflowService', 'ConstantService', function($scope, $location, $uibModal,
WorkflowService, ConstantService) {
//some code
} ]);
Snce it is a single page application angular.module statement is written only in app.js file. It is not written in any other js file. Now i want to test search_name_controller.js using KARMA.I have written test code like below
search_name_controller.test.js
describe('search_name_controller', function () {
beforeEach(function() {
module('myApp');
});
var $controller;
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
//code to test method
});
While i try to run this test, I am getting error as "$controller is not a function". i feel the error is because the angular.module part is not defined in search_name_controller.js file. When i try to add it ,i am able to run the test.But i am not allowed to make any changes to existing code. Is there any way where my test file can read angular.module part of app.js file even if i write test scenario for search_name_controller.js.
Kindly help
beforeEach(inject(function($controller){
controller = $controller('SearchCifCtrl', {
$scope: scope
});
}));
//try this to inject your controller

Angular JS problems with Ng-Route, Gulp, and Json

I'm pretty new to the world of front end development and I'm working through my first project with AngularJS. I'm also using Yeoman, Gulp, Bower to set up my project, which is also bran new to me... I've kind of crafted a build from the yo generator Gulp Angular and put my own personal touches to it. I'm sure I did more harm than good :p but I'm learning.
Anyways I've been coding all day and am really stumped why my project is having trouble when I use the ng-route. The home display works correctly but when I try to click on a link to a deeper page it just refreshes back to the home. I'm using Json files rather than a server and the Gulp Angular set up has all my files compiled to another folder when launching a server. Is there any chance the issue could lie within the compiler?
I'm starting to go crazy so I think I'm gonna call it quits for the night but if anyone has the time and the generosity to look over my github repo I would be over joyed :)
Thanks
https://github.com/jleibham/BhamDesigns.git
App Module
(function() {
'use strict';
var bhamDesignsApp = angular.module('bhamDesignsApp', ['ngAnimate', 'ngTouch', 'ngSanitize', 'ngMessages', 'ngAria', 'ngRoute', 'mm.foundation', 'appControllers']);
bhamDesignsApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/projects', {
templateUrl: 'partials/projects.html',
controller: 'ProjectsController'
}).
when('/projects/:projectId', {
templateUrl: 'partials/gallery.html',
controller: 'GalleryController'
}).
otherwise({
redirectTo: '/projects'
});
}]);
})();
App Controller
(function() {
'use strict';
var appControllers = angular.module('appControllers', []);
appControllers.controller('ProjectsController', ['$scope', '$http',
function ($scope, $http) {
$http.get('app/json/projects.json').success(function(data){
$scope.projects = data;
});
$scope.orderProp = '-year';
}]);
appControllers.controller('GalleryController', ['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.projectId = $routeParams.projectId;
}]);
})();
You are calling the wrong url and your routes do not recognize the url you do call with your href, so it redirects you. In you are going to call this:
href="#/json/galleries/(what ever the project.id is)
Then your routing should look similar to this:
when('/json/galleries/:projectId', { /// the rest of your code
You are going to want to use $routeParameters with ngRoute. here is a great example

Constant not injected to config()

I'm trying to modularize my first angular project. Need to make my module views relative to this module. In example below i have sample main module, that require controllers module. I can inject VIEWS_PATH to controller, but no to config(). As i know constant can be injected into config(). What is wrong with that ?
mainModule.js
angular.module('mainModule', ['app.main.controllers'])
.constant('VIEWS_PATH', 'js/modules/main/views');
controllersMain.js
angular.module('app.main.controllers', [])
.config(function($routeProvider, VIEWS_PATH) { // error
$routeProvider.when('/hello', {
templateUrl: VIEWS_PATH+'/hello.html',
controller: 'HelloController'
})
})
.controller('HelloController', function($scope, VIEWS_PATH) {
$scope.hello = 'Hello World!';
console.log('VIEWS_PATH: '+VIEWS_PATH); // ok
});
It's because you defined your VIEWS_PATH constant in one module -mainModule and you're trying to use it in a different module - app.main.controllers.
You can define that constant in app.main.controllers module if you wish to use it in the configuration of that module.
angular.module('app.main.controllers', [])
.constant('VIEWS_PATH', 'js/modules/main/views')
.config(function($routeProvider, VIEWS_PATH) {
$routeProvider.when('/hello', {
templateUrl: VIEWS_PATH+'/hello.html',
controller: 'HelloController'
});
});
But Constants from app.main.controllers module will work in mainModule as it listed as dependency in mainModule like below.
angular.module('mainModule', ['app.main.controllers']);
For example, let's say we defined two modules - MyApp & SomeModule
var someModule = angular.module('SomeModule',['someOtherModule']);
someModule.constant('SOME_CONSTANT','SomeValue');
var myApp = angular.module('MyApp',['SomeModule']);
myApp.constant('TEST_CONSTANT','Test');
myApp.config(function(SOME_CONSTANT){
console.log("from dependent module "+SOME_CONSTANT);
});
With the above setup, SOME_CONSTANT from SomeModule can be used in MyApp but TEST_CONSTANT from MyApp cannot be used in SomeModule.
Here's a sample Pen in action.

Why use dependency injection in angularjs for controllers?

I came across this tutorial.
http://justinvoelkel.me/laravel-angularjs-part-two-login-and-authentication/
The author used dependency injection to inject the login controller in app.js like this.
app.js:
var app = angular.module('blogApp',[
'ngRoute',
//Login
'LoginCtrl'
]);
app.run(function(){
});
//This will handle all of our routing
app.config(function($routeProvider, $locationProvider){
$routeProvider.when('/',{
templateUrl:'js/templates/login.html',
controller:'LoginController'
});
});
The login controller file looks like this.
LoginController.js:
var login = angular.module('LoginCtrl',[]);
login.controller('LoginController',function($scope){
$scope.loginSubmit = function(){
console.dir($scope.loginData);
}
});
I don't understand why the dependency injection is required here.
Here is my version of app.js and LoginController.js which works perfectly fine.
app.js:
var app = angular.module('ilapp', ['ngRoute']);
app.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.when('/login', {
controller: 'LoginController'
});
}]);
LoginController.js:
angular.module('ilapp').controller('LoginController', [function () {
this.loginSubmit = function () {
console.dir(this.loginData);
};
}]);
Is there any advantage to the author's approach? What am I missing?
First of all, both are correct way and it should work but you can choose any one method depends upon your project.
Approach 1
In your question, the first approach is modular way. Means, you can register a LoginController controller in a new module LoginCtrl. Here module name LoginCtrl is confusing. you can change the name as loginModule. This approach is helpful for you to organize the files structure for your big application. Also, look this post Angular - Best practice to structure modules
var login = angular.module('loginModule',[]);
login.controller('LoginController',function($scope){
$scope.loginSubmit = function(){
console.dir($scope.loginData);
}
});
var app = angular.module('blogApp',[
'ngRoute',
'loginModule'
]);
app.run(function(){
});
//This will handle all of our routing
app.config(function($routeProvider, $locationProvider){
$routeProvider.when('/',{
templateUrl:'js/templates/login.html',
controller:'LoginController'
});
});
Approach 2
If your application contains minimal pages and no need to split multiple modules, then you can write all your controllers in app.js itself

AngularJS - Error: Unknown provider: searchResultsProvider

EDIT: I have managed to get my unit tests running - I moved the code containing the services to a different file and a different module, made this new module a requirement for fooBar module, and then before each "it" block is called, introduced the code beforeEach(module(<new_service_module_name)). However, my application still won't run. No errors in console either. This is the only issue that remains - that when I use global scope for controllers definition, the application works, but when I use angular.module.controller - it does not.
I have a file app.js that contains the following:
'use strict';
var app = angular.module('fooBar', []);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/form-view.html',
controller: FormViewCtrl
}).
when('/resultDisplay', {
templateUrl: 'partials/table-view.html',
controller: TableViewCtrl
}).
otherwise({redirectTo: '/'});
}]);
app.service('searchResults', function() {
var results = {};
return {
getResults: function() {
return results;
},
setResults: function(resultData) {
results = resultData;
}
};
});
I have another file controllers.js that contains the following:
'use strict';
var app = angular.module('fooBar', []);
app.controller('FormViewCtrl', ['$scope', '$location', '$http', 'searchResults',
function ($scope, $location, $http, searchResults) {
//Controller code
}]);
searchResults is a service that I created that simply has getter and setter methods. The controller above uses the setter method, hence the service is injected into it.
As a result, my application just does not run! If I change the controller code to be global like this:
function ($scope, $location, $http, searchResults) {
//Controller code
}
then the application works!
Also, if I use the global scope, then the following unit test case works:
'use strict';
/*jasmine specs for controllers go here*/
describe('Foo Bar', function() {
describe('FormViewCtrl', function() {
var scope, ctrl;
beforeEach(module('fooBar'));
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('FormViewCtrl', {$scope: scope});
}));
}
//"it" blocks
}
If I revert to the module scope, I get the error -
Error: Unknown provider: searchResultsProvider <- searchResults
Thus, by using global scope my application and unit tests run but by using app.controller, they seem to break.
Another point that I have noted is that if I include the controller code in app.js instead of controllers.js, then the application and unit tests start working again. But I cannot include them in the same file - how do I get this to run in the angular scope without breaking the application and unit tests?
You don't need to go that route. You can use the modular approach, but the issue is with your second parameter.
In your app.js you have this:
var app = angular.module('fooBar', []);
Then in your controller, you have this:
var app = angular.module('fooBar', []);
What you're doing there is defining the module twice. If you're simply trying to attach to the app module, you cannot pass in the second parameter (the empty array: []), as this creates a brand new module, overwriting the first.
Here is how I do it (based on this article for architecting large AngularJS apps.
app.js:
angular.module('fooBar',['fooBar.controllers', 'fooBar.services']);
angular.module('fooBar.controllers',[]);
angular.module('fooBar.services', []);
...etc
controllers.js
angular.module('foobar.controllers') // notice the lack of second parameter
.controller('FormViewCtrl', function($scope) {
//controller stuffs
});
Or, for very large projects, the recommendation is NOT to group your top-level modules by type (directives, filters, services, controllers), but instead by features (including all of your partials... the reason for this is total modularity - you can create a new module, with the same name, new partials & code, drop it in to your project as a replacement, and it will simiply work), e.g.
app.js
angular.module('fooBar',['fooBar.formView', 'fooBar.otherView']);
angular.module('fooBar.formView',[]);
angular.module('fooBar.otherView', []);
...etc
and then in a formView folder hanging off web root, you THEN separate out your files based on type, such as:
formView.directives
formView.controllers
formView.services
formView.filters
And then, in each of those files, you open with:
angular.module('formView')
.controller('formViewCtrl', function($scope) {
angular.module('formView')
.factory('Service', function() {
etc etc
HTH
Ok - I finally figured it out. Basically, if you wish to use the module scope and not the global scope, then we need to do the following (if you have a setup like app.js and controllers.js):
In app.js, define the module scope:
var myApp = angular.module(<module_name>, [<dependencies>]);
In controllers.js, do not define myApp again - instead, use it directly like:
myApp.controller(..);
That did the trick - my application and unit tests are now working correctly!
It is best practice to have only one global variable, your app and attach all the needed module functionality to that so your app is initiated with
var app = angular.module('app',[ /* Dependencies */ ]);
in your controller.js you have initiated it again into a new variable, losing all the services and config you had attached to it before, only initiate your app variable once, doing it again is making you lose the service you attached to it
and then to add a service (Factory version)
app.factory('NewLogic',[ /* Dependencies */ , function( /* Dependencies */ ) {
return {
function1: function(){
/* function1 code */
}
}
}]);
for a controller
app.controller('NewController',[ '$scope' /* Dependencies */ , function( $scope /* Dependencies */ ) {
$scope.function1 = function(){
/* function1 code */
};
}
}]);
and for directives and config is similar too where you create your one app module and attach all the needed controllers, directives and services to it but all contained within the parent app module variable.
I have read time and time again that for javascript it is best practice to only ever have one global variable so angularjs architecture really fills that requirement nicely,
Oh and the array wrapper for dependencies is not actually needed but will create a mess of global variables and break app completely if you want to minify your JS so good idea to always stick to the best practice and not do work arounds to get thing to work
In my case, I've defined a new provider, say, xyz
angular.module('test')
.provider('xyz', function () {
....
});
When you were to config the above provider, you've inject it with 'Provider' string appended.
Ex:
angular.module('App', ['test'])
.config(function (xyzProvider) {
// do something with xyzProvider....
});
If you inject the above provider without the 'Provider' string, you'll get the similar error in OP.

Resources