I have problems with call a factory in one module from another module. I am using angular.js + require.js.
Here is my code
Module 1:
define(['angular', 'app/admin/app.admin', 'app/admin/account/services'], function (angular, app, services) {
app.controller('MainCtrl', ['$scope', 'providerService', function ($scope, providerService) {
$scope.showMe = false;
$scope.provider = providerService.Providers;
}]);
return app;
});
Module 2
define(['angular', 'app/admin/config/index'], function (angular) {
'use strict';
var service = angular.module('app.admin.account.services', []);
service.factory('providerService', ['app.admin.config',
function (config) {
var providers = [
{ name: 'google+', url: config.AUTH_URL + '/google' },
{ name: 'facebook', url: config.AUTH_URL + '/facebook' }
];
return {
Providers: providers
};
}
]);
return service;
});
When i try to call providerService in module 2 from module 1. I got an error say providerService is not there. Can someone tell me what I did wrong here?
Cheers
It is perfectly fine to use RequireJS and AngularJS together, however the term "module" has different meaning between the two and is a little bit confusing when it comes to dependencies.
In RequireJS a "module" is a typical Javascript file that encapsulates a piece of code. You define the dependencies using RequireJS in order to pass in/around other modules as dependencies and ensure correct script load ordering.
In AngularJS the term "module" specifically means an AngularJS "module", which is a container for a number of controller/services/directive etc. declarations.
You use RequireJS to define the order and dependencies of your script files. You then also need to tell Angular which "Angular modules" your module depends on, essentially importing all of the controllers/services/directives along with it.
In 'app/admin/app.admin' make sure you define the dependencies for your AngularJS module by passing in the 'app.admin.account.services' module as a second parameter e.g.
var app = angular.module('app.admin', ['app.admin.account.services']);
That will then import the 'app.admin.account.services' module into your main module making your providerService available for dependency injection.
Related
According to an excellent explanation of how to add translation using angular-translate (https://technpol.wordpress.com/2013/11/02/adding-translation-using-angular-translate-to-an-angularjs-app/)
I have a breaking my head error and I'm wondering why that happens? And what am I doing wrong?
Error:
angular.js:36 Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.2.26/$injector/modulerr?p0=app&p1=Error%3A%20…alhost%3A9085%2FScripts%2Fcomponents%2Fangular%2Fangular.min.js%3A18%3A170)
Aim:
Partial loading translations in my entire app
What I've done:
Downloaded (both) via bower and included into the project.
angular-translate
angular-translate-loader-partial
Added them into ReguireJS config file (after Angular)
'angular': '../Scripts/components/angular/angular.min',
'ngAnimate': '../Scripts/components/angular-animate/angular-animate.min',
'ngResource': '../Scripts/components/angular-resource/angular-resource.min',
'ngRoute': '../Scripts/components/angular-route/angular-route.min',
'ngCookies': '../Scripts/components/angular-cookies/angular-cookies.min',
'pascalprecht.translate': '../Scripts/components/angular-translate/angular-translate.min',
'angularTranslate': '../Scripts/components/angular-translate-loader-partial/angular-translate-loader-partial.min'
Added shim:
'pascalprecht.translate': {
deps: ['angular']
},
'angularTranslate': {
deps: ['pascalprecht.translate']
}
In app.js file included dependencies (at the end, after angular stuff):
'pascalprecht.translate',
'angularTranslate',
var app = angular.module('app', ['...',
'pascalprecht.translate',
'angularTranslate' ]);
App.js config
app.config(['$routeProvider', '$locationProvider', '$httpProvider', '$translateProvider', '$translatePartialLoaderProvider',
function ($routeProvider, $locationProvider, $httpProvider, $translateProvider, $translatePartialLoaderProvider) {
Stuff in controllers config:
define(
[
'angular',
'./services/services',
'./controllers/controllers',
'./directives/directives',
'./filters/filters',
'pascalprecht.translate'
],
function(angular) {
'use strict';
var module = angular.module('common', ['common.services', 'common.controllers', 'common.directives', 'common.filters', 'pascalprecht.translate']);
return module;
});
Controller
define(function (require) {
'use strict';
function angularTranslate ($translateProvider, $translatePartialLoaderProvider) {
$translateProvider.useLoader('$translatePartialLoader', {
urlTemplate: '../Translations/locale-{part}.json'
});
$translateProvider.preferredLanguage('en');
}
return angularTranslate;
});
After precisely following above tutorial I still get thi error.
I albo searched in github and stackoverflow but nothing works for me.
Please help!
Short: You dependency management in RequireJS is not correct. The controller's module should require angularTranslate, not pascalprecht.translate.
Long:
At first I would advice you using the official documentation and guide which you will found at https://angular-translate.github.io/
I also recommend using both the latest AngularJS (which is 1.5.x atm) and angular-translate (which is 2.10.x atm).
Additionally, I would also advice using only the non minified versions of libraries because they will give you a much better experience. Minified source files are not for the developer.
And I would also appreciate working demo using JSFiddle, Plnkr or others because they give everyone a running proof of concept/bug.
Said this, it is not clear which version of angular-translate you are using. If you have run bower install angular-translate, you will probably have the latest already -- but the page behind the link you have referenced is made with an older one (about three years old). APIs have changed.
Coming to you actual issue: I would say you have mixed the problems both in AngularJS and RequireJS which leads in such exceptions.
First of all: Your (shim) configuration for RequireJS is misleading/confusing. You should not name the partial loader plugin as angularTranslate.
'angularTranslate': '../Scripts/components/angular-translate-loader-partial/angular-translate-loader-partial.min'
and
'angularTranslate': {
deps: ['pascalprecht.translate']
}
Less confusing would be a name like pascalprecht.translate.partialLoader.
And now the RequireJS module dependency management:
You have defined a shim dependency angularTranslate -> pascalprecht.translate. Whenever the last one will be requested, the first one will be loaded before. That's fine.
You have defined your app depends on both pascalprecht.translate and angularTranslate (which is the partial loader actually). This is fine, but the first one is actually obsolete. It will be available automatically because you have defined the shim dependency already.
However the controller's module only requires the core library pascalprecht.translate.
This means: The dependency management resolver of RequireJS will not wait for the partial loader (no reason it should do this) and therefor it can/will be not available when processing the AJS injections (here: translatePartialLoaderProvider).
Disclaimer: I'm the co-maintainer of the AngularJS plugin angular-translate.
app.js looked like this:
define(
[
...
'pascalprecht.translate',
'angularTranslate',
],
var app = angular.module('app', ['...',
'pascalprecht.translate',
'angularTranslate' ]);
but it should be like:
define(
[
...
'pascalprecht.translate',
'angularTranslate',
],
var app = angular.module('app', ['...',
'pascalprecht.translate' ]);
I've defined submodule angular-translate-loader-partial as normal module and that causes the error. Dependency between both modules (angular-translate and angular-translate-loader-partial) should be made only in requirejs shim.
I have Done a Library Management App with Angular JS and Mongo Lab will Act as a DB Part, I am facing issuse with Require JS Dependency While Crating Unit test Case
Error: [$injector:modulerr] Failed to instantiate module lmaApp due to:
Error: [$injector:nomod] Module 'lmaApp' is not available!
The Above error I am facing,kindly help me to get out from this.
MyCode:
Controller.js
define(
['modules'],
function(lmaApp) {
lmaApp.controller('gridControl',['$scope' , '$http' , 'internal' , 'commonValues', function($scope , $http , internalFn , commonValues){
jQuery('ul.navbar-nav li').removeClass('active');
jQuery('ul.navbar-nav li:nth-child(1)').addClass('active');
$('.loaderImg').removeClass('no-loading');
var lmaTableData = internalFn.getTableData(commonValues.mongoAPIurl,commonValues.bookTableName,'');
var promise = lmaTableData
.success(function(tbData) {
if(tbData.length > 0){
$scope.nobook=0;
$scope.books =tbData;
}
else{
$scope.nobook =1;
}
}).then(function (response) {$('.loaderImg').addClass('no-loading');});
}]);
});
modules.js
define(
['app_config','angularRoute'],
function() {
var lmaApp =angular.module('lmaApp',['ngRoute'])
return lmaApp;
});
app_config.js
define(
['angular','angularRoute','modules'],
function() {
angular.element(document).ready(function() {
angular.bootstrap(document, ['lmaApp'], {});
});
});
My spec File
controllerSpec.js
define(['angular', 'angular-mocks'], function() {
describe('gridControl', function(){
beforeEach(module('lmaApp'));
it('should get the book table Datas', inject(function($controller) {
var scope = {},
ctrl = $controller('gridControl', {$scope:scope});
expect(scope.phones.length).not.toEqual(0);
}));
});
});
Here i have a doubt with require js dependecy like i have to mention modules.js as a dependency in Spec file too.
Your controller-spec.js is wrong, you need to call its dependencies which is your module.js, app_config.js, Controller.js also 'angularRoute'. In other ot make your app to able to boostrap.
try it like this
define(['angular', 'angular-mocks','modules', 'app_config', 'Controller', 'angularRoute'], function() { ... }
Still I have nothing to be sure that it will work for you. Because if any of your configuration is wrong. It will be broken. Using requireJS with AngularJS in unit testing is very tricky/complex in the configuration.
You should read more about requireJS config, and using shim for define dependencies for your script. It will be lots clearer and eaiser to handle when your app getting bigger. For example you can do something like this in your config file:
shim: {
'modules': ['angular', 'app_config', 'angular-mocks'],
'app_config': ['angular', 'angularRoute', 'modules'],
'Controller': ['modules']
}
and your controller-spec.js will be like this
define(['modules', 'app_config', 'Controller'], function(){ ... });
Also Bootstraping angular on element ready is not a good idea for testing. It may cause some conflict in loading simulating of karma. I am not sure but don't feel right about it
Sencond Your app_config.js and modules.js are dependency of each other. So what do you think if there's something require an order in loading. Which will need to load first? since Both required the other to be loaded before it got to be injeacted by requireJS.
Still I don't think my solution will work. Because your config seem so wrong.
When trying to implement the session part in the tutorial of John Papa Pluralsight Video.
I got the following error:
Uncaught TypeError: Object # has no method 'extendQ'
(function () {
'use strict';
var app = angular.module('app', [
// Angular modules
'ngAnimate', // animations
'ngRoute', // routing
'ngSanitize', // sanitizes html bindings (ex: sidebar.js)
// Custom modules
'common', // common functions, logger, spinner
'common.bootstrap', // bootstrap dialog wrapper functions
// 3rd Party Modules
'ui.bootstrap', // ui-bootstrap (ex: carousel, pagination, dialog)
//'breeze.angular.q'
]);
// Handle routing errors and success events
app.run(['$route', '$rootScope', '$q', function ($route, $rootScope, $q) {
// Include $route to kick start the router.
breeze.core.extendQ($rootScope, $q);
//use$q($rootScope,$q);
}]);
})();
It's important to know that the version of breeze that I'm working on is newer than the used on the original video.
I search for some answers on the breeze website and I've found this:
The to$q has been deprecated. It is superseded by the Breeze Angular Service.
But I didn't make it work on the tutorial example. How to change the deprecated implementation with the new one?
UPDATE:
this link helped solve the problem:
http://www.breezejs.com/documentation/breeze-angular-service
The breeze library was updated and the answer is on this link: http://www.breezejs.com/documentation/breeze-angular-service
Specifically this code from the bottom of the post:
Migration is pretty painless.
Remove the breeze.angular.q.js script from your project.
Uninstall-Package Breeze.Angular.Q if you used NuGet.
Install breeze.angular.js as explained above.
Update your index.html, changing breeze.angular.q.js to breeze.angular.js.
Update your app module to depend on "breeze.angular".
Find the one place in your code where you call "use$q" and replace it with the "breeze" dependency.
For example, you might go from this:
var app = angular.module('app', [
// ... other dependencies ...
'breeze.angular.q' // tells breeze to use $q instead of Q.js
]);
app.run(['$q','use$q', function ($q, use$q) {
use$q($q);
}]);
to this:
var app = angular.module('app', [
// ... other dependencies ...
'breeze.angular'
]);
app.run(['breeze', function () { }]);
You should also track down and eliminate code that configures Breeze to use the "backingStore" model library adapter and $http. For example, you could go from this:
function configBreeze($q, $http, use$q) {
// use $q for promises
use$q($q);
// use the current module's $http for ajax calls
var ajax = breeze.config.initializeAdapterInstance('ajax', 'angular');
ajax.setHttp($http);
// the native Breeze 'backingStore' works for Angular
breeze.config.initializeAdapterInstance('modelLibrary', 'backingStore', true);
breeze.NamingConvention.camelCase.setAsDefault();
}
to this:
function configBreeze() {
breeze.NamingConvention.camelCase.setAsDefault();
While taking the same course by John Papa I also hit breeze.core.extendQ not available on step 4.10.
This is what I did to solve the issue:
1 - In app.js pass breeze dependency directly:
// Handle routing errors and success events
// Trigger breeze configuration
app.run(['$route', 'breeze', function($route, breeze)
{
// Include $route to kick start the router.
}]);
2 - In datacontext.js do:
return EntityQuery.from('Sessions')
.select('id, title, code, speakerId, trackId, timeSlotId, roomId, level, tags')
.orderBy(orderBy)
.toType('Session')
.using(manager).execute()
.then(querySucceeded, _queryFailed);
You can also get rid of breeze.to$q.shim.js from index.html and delete the file from the \Scripts folder in the project since it's not needed anymore.
Here's the updated source code of the same project I'm doing now [ including the fixes ].
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.
i have a weird problem regarding angular resource. when i try to define it it causes the app to create an error. i dunno but is this the correct style of defining an angular Resource? tIA
main.js
'use strict';
require.config({
paths: {
jquery: 'libs/jquery/jquery-1.9.1',
angular: 'libs/angular/angular.min',
ngResource: 'libs/angular/angular-resource.min'
},
shim: {
angular: {
exports: 'angular'
},
resource : { deps : ['angular'], 'exports' : 'ngResource'},
}
});
require([
'jquery',
'angular',
//'ngResource',
'app',
'routes',
],
function ($, angular, app, routes) {// set main controller
$(function(){
var $html = $('html');
angular.bootstrap($html, [app['name']]);
$html.addClass('ng-app');
});
});
Just to help out those users who are not familiar with the code above; The code shows RequireJS configuration and initialization structure, and only a small part at the end is the actuall AngularJS code.
You have correctly configured RequireJS to include ngResource before initialization, but you didn't actually tell Angular to use it.
I'm not sure what app['name'] stands for, but your angular bootstrap call should include the ngResource module:
angular.bootstrap($html, ['ngResource']);
And, btw, I don't think you need to add the class ('ng-app') at the end.
In your callback when all resources are loaded, try to explicitly define the modules and dependancies before bootstrapping, like this:
angular.module('fooApp', ['ngResource']); // Module name and list of dependancies.
angular.bootstrap(document, 'fooApp');
There is no need to manually add the ng-app class, when this class is used to do bootraping automatically, witch is not what you want. You want to load the applicatiopns module when all scripts are loaded, with the ngResource module as a dependancy.
Hope this helps.