I'm working on an Angular app and I'd like to create a config file. From what I read, I should use angular constant.
So I tried to create my constant. From what I read (here, here and also here + doc), it seems quiet easy.
Here is my file :
angular.module('app')
.constant('config', {
routers : {
Commandes: 'some_data',
Prestations: 'some_data',
Interventions: 'some_data'
},
serverPath : 'some_data'
});
As I read it's possible to inject it in a service, I tried to use it in a factory and to display it :
app.factory('myFactory', [function(config) {
console.log('config : '+config);
return // something;
}]);
But the config appears "undefined" (no error here, just console.log things).
It seems that I'm not gettong it, but what the hell did I miss ?
To retrieve the constant from the factory service you have to use the whole path as you defined in your config file.
In your example:
config.serverPath
config.routers.Commandes
// etc...
Another thing is that you need to define the constants as dependencies inside the square brackets:
app.factory('myFactory', ['config', function(config) {
console.log('config : '+config);
return // something;
}]);
Related
I use angularjs and requirejs in my spa. For the organization of imports and so on I use require. In requirejs I can use e.g. baseUrl: Every import path is resolved with the baseUrl. Now I would like to resolve the templateUrls the same way. Therefore I can use e.g.:
templateUrl = requirejs.toUrl("modules/test/chuck.directive.html")
The problem that I would like to resolve every templateUrl of every directive this way.
So: Is there a possibility to jump into the template loading process of directives in angular and run the above code?
Thanks for any hint.
I would decorate $templateRequest service if you know for sure that you want to intercept all template loading requests and modify template URL. Something like this:
.config(function($provide) {
$provide.decorator('$templateRequest', function($delegate) {
return function(tpl, ignoreRequestError) {
tpl = requirejs.toUrl(tpl); // modify original tpl
return $delegate.call(this, tpl, ignoreRequestError);
};
});
})
I am currently building a base for AngularJS in combination with RequireJS and so far I got everything working. there's just a little thing that I do not understand at this point. I have a file which creates the angular module, when this module is created it requires a controller and assigns it to the module. The strange thing though, the controller needs the module as dependency while in the module's file the module has not been returned yet because the require statement is executed before the return statement. This somehow seems to work but it has a bad smell to it.
Module file:
// Home is defined here and can later be used in controllers (and Services)
define('home', ['require', 'angular'], function(require, angular) {
var homeModule = angular.module('AngularBase.home', ['AngularBase.core']);
homeModule.config(['$controllerProvider', '$provide', '$compileProvider', function($controllerProvider, $provide, $compileProvider) {
// We need this in order to support lazy loading
homeModule.controller = $controllerProvider.register;
homeModule.factory = $provide.factory;
// And more, not relevant at this moment
}]);
// It loads the controller that depends on this module here
require(['modules/home/controllers/homeController'], function() {
// Dependencies loaded
});
// Yet in my mind controllers that need this module can only use it when the following return statement is called.
return homeModule;
});
Controller File:
// As you can see this controller depends on home while home hasn't returned its module yet
// Yet it seems to work just fine
define(['home'], function(home) {
home.controller('homeController', ['$scope', 'homeService', function($scope, homeService) {
$scope.title = 'Home controller';
}]);
});
I assume that it is not a good approach to do it like this and therefore I need some suggestions on how to make this happen in a clean way. I thought about grabbing the AngularBase.home module via angular.module('AngularBase.home') in the controller file and defining my controller on this. This however no longer allows me to insert a mockModule for testing in this controller via RequireJS's map function.
map: {
'*' : {
'home' : 'mock-module'
}
}
Any suggestions on how to refactor this into a more clean solution?
I have found the solution to my problem. In the end it seems to be just fine to do it the way I am currently doing it. When a file is called and has a define statement in it it will wait until all dependencies are available until the function is executed. This means that the controller will actually wait for the module to finish initializing before calling its function to register itself.
The way I am doing it above is just fine.
Source: http://www.slideshare.net/iivanoo/handlebars-and-requirejs (slides 11 till 24)
I'm trying to return the object with a specific "ID" from the json service. I can see the objects in my console log but any attempt to iterate or use underscore _find gives me "undefined"
var metaresult = _.find($scope.results.results, function(rw){ return rw.id == $scope.answer1 });
gives me this error:
TypeError: Cannot read property 'find' of undefined
at k.$scope.metaResult (https://evening-taiga-2443.herokuapp.com/js/controllers/MainController.js:173:21)
Here is my factory:
app.factory('results', ['$http', function($http) {
return $http.get('js/services/results.json')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
any my json structure:
{
"results": [
{
"id": "a"
},
.... and so on
EDIT: So the issue seems to be dependency. I tried using ng-underscore instead and I'm loading as follows:
<script src="js/ng-underscore.min.js"></script>
then the app.js
var app = angular.module("quizApp", ['720kb.socialshare', 'ngUnderscore']);
Then in my controller
app.controller('MainController', ['$scope', 'quiz', 'results', function($scope, quiz, results, underscore)
typing "underscore" into console gives me:
Uncaught ReferenceError: underscore is not defined
EDIT: Figured it out just need to use lodash
var metaresult = _.find( ...
TypeError: Cannot read property 'find' of undefined
This error means that javascript didn't know what is _. _ is undefined and when you do _.find then error is generated. It seems you're not loading libraries properly. Kindly make sure you have added the underscore js module. Once underscore is loaded, _ will reference to the js module and you will be able to use all the methods.
Once get the libs to load correctly, it should be:
var metaresult = _.findWhere($scope.results.results, { id: $scope.answer1.id });
http://underscorejs.org/#findWhere
_ would be referring to either lodash or underscore which are both javascript utility libraries. I would suggest that you take a look at bower which is a package manager for front end libraries and make sure that you both have the necessary files in your project and also that they are being referenced in your HTML.
I would personally recommend that you use lodash instead of underscore as it is essentially a drop in replacement and offers performance benefits. That being said, there is absolutely no reason to use an angular module wrapper in based on the code that you've shown here. Simply downloading lodash and including it in your HTML will make it available for use inside your controller without having to worry about any module dependencies or controller injection.
I am developing an Angular JS application.
I would like to know what is the best practice to include string values in our code.
I am planning to use another JS File which contains all the constant values. I will call this JS file in each and every JS(Controller) to refer the string values.
You can define constants in angular like
angular.module('moduleName',[]).constant('constName',string|object|array);
You can inject in directive or controller or wherever you want.
angular.module('moduleName',[]).directive('directiveName', ['constName', function(constName){...});
You have several options.
Global value. You can use your constants in form of the javascript object which would be globally accessible across the application. For example, your file could look something like this:
config = {
host: 'domain',
port: '1234'
};
Obvious disadvantage is that those values are not really a constants and can be easily changed, so it's error prone.
Angular config module. More reliable and cleaner option is to create a separate module to be used as a dependency for main app module. You would still have separate file for your constants but instead of some global variable this file would hold angular module with constant service. Something like this:
angular.module('app.config', []).constant('config', {
host: 'domain',
port: '1234'
});
Then in main application you would configure app like
angular.module('app', ['app.config']).config(function(config) {
// console.log(config);
});
Here is the sample code;
var app = angular.module('plunker', []);
app.constant('configs', {host:'localhost',port:8080});
app.controller('MainCtrl', function($scope, configs) {
$scope.name = configs.host;
});
here is demo plunker
Angular has a built in way of providing constants, e.g:
angular.module('foo', ['ngRoute']) // Your angularjs module
// Decide a name for the bucket of constants, then just declare the
// constants in turn as an object literal:
.constant("HTTP_CONSTANTS", {
"URL": "http://localhost",
"PORT": "80"
})
Then you can load it anywhere where you have access too you foo module using dependency injection, i.e.:
angular.module('foo')
.controller('bar', function (HTTP_CONSTANTS) {
... // Use HTTP_CONSTANTS.URL or HTTP_CONSTANTS.PORT, for example
})
Here's a good primer on using constants:
http://twofuckingdevelopers.com/2014/06/angularjs-best-practices-001-constants/
You can use factory for this purpose and inject this factory where ever you want these constants.
var app=angular.module('Myapp', []);
app.factory('ConstantService', function(){
var constant={temp:'c'};
var getConstants=function(){
return constant;
};
return{
constants:getConstants;
}
});
app.controller('MyController',['ConstantService' function (ConstantService){
var constant= ConstantService.constants;
}]);
I have a set of angular $resource defined in a module called 'App.API' in a single file which I cannot touch because it is generated. (With loopback-angular, a tool to generate angular $resource from server side model definitions)
Let's take the Product dependency as en example, later in the app, I want to override its prototype, like this :
module('App.NewModule', ['App.API']).run(['Product', function(Product) {
Product.prototype.getTitle = function() {
return 'Product name is ' + this.name;
};
// From now on I can use p.getTitle() on every Product $resource
});
It works.
The thing is, I have many different files, each containing modules, and I am experiencing a dependency injection issue : I can access the getTitle function inside NewModule, but not inside other modules.
Question : How can I override a dependency object prototype and make it available to other modules ?
I tried to define the prototype functions in this way instead, thinking that Product prototype would be modified. Maybe not early enough :
module('App.API').run(['Product', function(Product) {
Product.prototype.getTitle = function() {
return 'Product name is ' + this.name;
};
});
It does not work : using getTitle in another module (using App.API/Product as a dependency) on a Product instance still throws a undefined is not a function error, even while Product object is correctly injected.
Actually, I just messed up the dependency definitions / orders.
I have three files :
app.js for module App (dependant on module App.API)
api.js for module App.API
product.js containing Product prototype
As stated in the question, I was doing :
// in product.js
module('App.API').run(['Product', function(Product) { ... }]);
// in app.js
var appModule = module('App', ['App.API']);
But the App.API module was defined in another file, which is a bit messed up because you never know for sure which one will load first, unless dealing with in in the js loader and loosing parallel downloads.
So I explicitly specified the modules and dependencies, at the expense of adding more dependency to declare in my app (but it works and is more stable) :
// in product.js
module('ApiProduct', ['App.API']).run(['Product', function(Product) { ... }]);
// in app.js
var appModule = module('App', ['App.API', 'ApiProduct']);
Note : In my first attempt, I defined the prototype in a new module in a .config() block, but it was not working, maybe because App.API services were not loaded yet. With .run() it works and my getTitle prototype is available everywhere I need Product provider.