In my project I divided angular services in different files, each file/service should belongs to a common module named 'com.mysite.services', for example:
ServiceA.js
ServiceB.js
ServiceC.js
...and so on
however by defining them in this way:
angular.module('com.mysite.services', []).
service('ServiceA', function()
{
});
I overwrite the module for each file. In order to solve the problem I defined a wrapper function which will create the module if not defined and return instead a reference to it if defined:
function angular_module(name, deps)
{
var m;
try
{
m = angular.module(name);
}
catch (e)
{
m = angular.module(name, deps || []);
}
return m;
};
So, I can simple replace the "." with "_" in the declaration:
angular_module('com.mysite.services', []).
service('ServiceA', function()
{
});
This solved my problem, but my question is: is there a way to avoid my wrapper in favor of an Angular-ish solution? (it seems so dumb :P)
Not sure this is what you will need but you can do something like that
In a dedicated file create this :
// Bootstrap.js
angular.module('com.mysite.services', ['com.mysite.services.ServiceA', 'com.mysite.services.ServiceB', ....]);
And now for every service you can do something like
// ServiceA.js
angular.module('com.mysite.services.ServiceA', []).
service('ServiceA', function(){});
//ServiceB.js
angular.module('com.mysite.services.ServiceB', []).
service('ServiceB', function(){});
You can now depend on 'com.mysite.services' in your app and all your services will be made accessible.
You can create an App.js
var myModule = angular.module('com.mysite.services', []);
And in ServiceA.js :
myModule.service('ServiceA', function()
{
});
Related
I am having one condition i.e
if(localstorage.testEnv){
env.apiUrl='testUrl.com';
}else{
env.apiUrl='liveUrl.com';
}
I need to inject this code in all the services. Is there any way I can implement this so that their won't be any code duplication.
Also, would this code work? I am trying to update env const (apiUrl) here?
Simplest way is to make a Utils Service and expose all common functions in this file, in this case a function which checks testEnv from local Storage and returns the corresponding URL. In this case getAPIBaseUrl is the function.
define(["../module"], function(services) {
"use strict";
services.service("Utils", [
"$localStorage",
function($localStorage) {
this.getAPIBaseUrl = function() {
if ($localStorage.testEnv) {
return "testUrl.com";
}
return "liveUrl.com";
};
}
]);
});
Unless the API url can change in the runtime, you may want to define the apiUrl and an AngularJS constant.
var app = angular.module('app', []);
app.constant('apiUrl', (function() {
return localStorage.testEnv ? 'testUrl.com' : 'liveUrl.com'
})());
app.controller('SomeController', function(apiUrl) {
console.log(apiUrl)
});
Main benefit of using a constant is that it can be injected in the configuration phase, e.g:
app.config(function(apiUrl) {
console.log(apiUrl)
})
I'm having an issue with RequireJS. Essentially, I'm not able to access a function defined inside another file from another one.
I need to do that because I want to export a given subset of functions like
define('submodule', [], function() {
let myFunction1 = function(){ return "Hello"; }
let myFunction2 = function(){ return " From"; }
let myFunction3 = function(){ return " Submodule!"; }
return {
myFunction1 : myFunction1,
myFunction2 : myFunction2,
myFunction3 : myFunction3,
};
});
And accessing them from another file
define('main', ['config', 'sub1', 'sub2', 'submodule'],
function(config, sub1, sub2, submodule) {
//Config
alert(config.conf);
//Submodule
let callSubmodule = function() {
alert(submodule.myFunction1() +
submodule.myFunction2() +
submodule.myFunction3());
}
//sub1
let callSub1 = function() {
alert(sub1.myFunction1());
}
//sub2
let callSub2 = function() {
alert(sub2.myFunction1());
}
});
The fact is that usually I'm able to do this with sub1 and
sub2, but, with submodule, I simply can't. I think it's somehow caused by the dependencies in require.config.js.
My require.config.js:
require(['common'], function () { //contains vendors
require(['config'], function () { //contains a js config file
require(['main'], function () { //main file
require(['sub1', 'sub2'], function () { //some subfiles
require(['submodule']);
});
});
});
});
For submodule.myFunction1() and othe two related functions I'm getting:
Uncaught (in promise) TypeError: Cannot read property 'myFunction1' of undefined
This is weird since I'm able to do that in other situations and I really can't understand why this is happening. For instance, I'm able to call sub1 and sub2 functions from main and other files but not submodule in particular.
Index.html
//Taken from Plunker
. . .
<script data-main="common" data-require="require.js#2.1.20" data-semver="2.1.20" src="http://requirejs.org/docs/release/2.1.20/minified/require.js"></script>
<script src="require.config.js"></script>
. . .
<button onclick = "callSubmodule()">Call Submodule</button>
<button onclick = "callSub1()">Call Sub1</button>
<button onclick = "callSub2()">Call Sub2</button>
common.js contains vendors, here's just an example
requirejs.config({
baseUrl : "",
paths : {
"jquery" : "http://code.jquery.com/jquery-latest.min.js"
}
});
sub1.js
define('sub1', ['submodule'], function(submodule) {
let myFunction1 = function(){ return "called sub1"; }
return {
myFunction1 : myFunction1
};
});
sub2.js
define('sub2', ['submodule'], function(submodule) {
let myFunction1 = function(){ return "called sub2"; }
return {
myFunction1 : myFunction1
};
});
I set up a Plunker with #SergGr help that tries to replicate application's structure but all the modules get undefined on click. On the real application this does not happen.
How can I solve this?
This is your code:
define('main', ['submodule'], function(submod) {
console.log(submodule.myFunction());
});
You have submod in the parameter list. But you then try to access submodule. Note that you return the function straight from your module (return myFunction), so your module has the value of the function myFunction and thus the module is what you should call. The code should be:
define('main', ['submodule'], function(submod) {
console.log(submod());
});
I Managed to solve this issue. Essentially, it was caused by a circular-dependency between the modules. So, a needed b and b needed a leading to one of them being undefined on the dependency resolution.
I found a solution to that on the answer provided by #jgillich at requirejs module is undefined.
So, I managed to solve using, in main
define('main', ['config', 'sub1', 'sub2', 'require'],
function(config, sub1, sub2, submodule, require) {
//Config
alert(config.conf);
//Submodule
let callSubmodule = function() {
alert(require('submodule').myFunction1() +
require('submodule').myFunction2() +
require('submodule').myFunction3());
}
});
As #jgillich said:
If you define a circular dependency ("a" needs "b" and "b" needs "a"), then in this case when "b"'s module function is called, it will get an undefined value for "a". "b" can fetch "a" later after modules have been defined by using the require() method (be sure to specify require as a dependency so the right context is used to look up "a"):
//Inside b.js:
define(["require", "a"],
function(require, a) {
//"a" in this case will be null if "a" also asked for "b",
//a circular dependency.
return function(title) {
return require("a").doSomething();
}
}
);
http://requirejs.org/docs/api.html#circular
The way you've named your modules I would expect they all came from a require config file. I would not expect that requirejs would know how to load those files without some sort of explicit compilation process. I also suspect that your server is returning something due to a 404 that JS is almost able to interpret without exploding.
Your setup seems and naming scheme seems quite strange. If you have the ability to start from scratch below are my recommendations.
Recommendations:
I'm noticing that you're using absolute paths. I highly recommend using relative paths for everything. There are many reasons for this.
Your data-main should be what you call "require.config.js". Your common.js is actually a require.config.js.
You load require.config.js (which is your main) separately using a script tag. You can do this but it's strange.
You can use the "commonjs" style syntax to require files without needing to use the array to define all your dependencies. I recommend that.
This is my recommendation for a set-up:
index.html
<script src="/js/config.js" />
<script src="http://requirejs.org/docs/release/2.1.20/minified/require.js" />
<script>
require('/js/main', function(main) {
main({});
});
</script>
/js/config.js
// setting requirejs to an object before its loaded will cause requirejs to use it as the config
window.requirejs = {
baseUrl : "/",
paths : {
"jquery" : "http://code.jquery.com/jquery-latest.min.js"
}
};
/js/main.js
define(function(require) {
const sum = require('./sum');
return (a, b) => sum(a, b);
});
/js/sum.js
define(function(require) {
return (a, b) => a + b;
});
Update (March 02, 2017)
Your plunker obviously will not work because you have direct calls from HTML to your module functions.
<button onclick = "callSubmodule()">Call Submodule</button>
<button onclick = "callSub1()">Call Sub1</button>
<button onclick = "callSub2()">Call Sub2</button>
RequireJS doesn't work that way. One of key purposes of RequireJS is to provide modules isolation and thus it just can't work that way: imagine if several different modules had functions callSubmodule.
To the best of my knowledge there is no way to bind calls from HTML back to the code in a RequireJS module, it should be other way around: module binds to HTML. And if you fix those issues, everything works fine for me as you can see at this fork of your plunker.
Old Answer
The bug is in your subModule.js
define('submodule', [], function() {
let myFunction = function(){ return "Hello"; }
//return myFunction; // old, wrong
return { myFunction: myFunction };
});
Even if you want to return just 1 function you should not return it as is, you should wrap it into an object and give it an explicit name.
P.S. if this is not your real issuse, please provide us real Minimal, Complete, and Verifiable example
I'm using a framework called Radiant UI, which is a way to get HTML5 UI into Unreal Engine 4. I'm trying to pick up some modern Javascript while I do that, so I'm building the UI in AngularJS.
My understanding of Angular is still pretty weak though, and I'm a bit confused about what the best practice is here. The extension injects the following Javascript when it sets up.
var RadiantUI;
if (!RadiantUI)
RadiantUI = {};
(function() {
RadiantUI.TriggerEvent = function() {
native function TriggerEvent();
return TriggerEvent(Array.prototype.slice.call(arguments));
};
RadiantUI.SetCallback = function(name, callback) {
native function SetHook();
return SetHook(name, callback);
};
RadiantUI.RemoveCallback = function(name) {
native function RemoveHook();
return RemoveHook(name);
};
})();;
So this is simply pushing RadiantUI into the global namespace. That would be fine if the extension was always there, but it isn't. In the test environment (Chrome), it's not there. It's only there when running in the game engine. That, combined with the fact that globals suck, means I want to encapsulate it.
In the previous iteration of this, I had it wrapped in an AMD module, and it worked well. Like this:
define([], function()
{
if ("RadiantUI" in window)
{
console.log("RadiantUI in global scope already!");
return window.RadiantUI;
}
var RadiantUI;
if (!RadiantUI) {
RadiantUI = {};
RadiantUI.TriggerEvent = function() {}
RadiantUI.SetCallback = function() {}
RadiantUI.RemoveCallback = function() {}
}
console.log("Using fake RadiantUI bindings");
return RadiantUI;
});
So here's what I want to do:
I want to include radiant as a dependency to my app/stateProvider and have it injected, much the same way it would be in AMD. With the stub methods in place if the extension isn't present. What's the proper approach to this? A module? A service provider?
UPDATE: This is the working code using the answer given.
var myapp = angular.module('bsgcProtoApp', ['ui.router' ]);
myapp.value('radiant', window.RadiantUI || {
TriggerEvent: function()
{
console.log("TriggerEvent called");
},
SetCallback: function(name, callback)
{
console.log("Setcallback called");
},
RemoveCallback: function(name)
{
console.log("RemoveCallback called");
}
});
myapp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider )
{
$urlRouterProvider.otherwise("/mainmenu");
$stateProvider.state('mainmenu',
{
name: "mainmenu",
url: "/mainmenu",
templateUrl: 'templates/mainmenu.html',
controller: ['$scope', 'radiant', function($scope, radiant)
{
$scope.tester = function()
{
radiant.TriggerEvent("DuderDude");
console.log("Duder!");
}
}],
});
}]);
You presumably have an Angular module or app. For the sake of this answer, let's call it MyApp.
Now you can do
MyApp.value("RadiantUI", window.RadiantUI || {
TriggerEvent = function(){},
//... more properties
});
Now to access this value as a dependency in a controller for example, you'd do this
MyApp.controller(["$scope", "RadiantUI", function($scope, RadiantUI){
// ... controller code ...
}]);
I have a ServiceA() in module A and variable item is used in html.
angular.module("ModuleA").service("ServiceA", function () {
var item=[];
this.get(){
item.push("A");
}
});
Controller.js
angular.module("ModuleX").controller("Ctrl", function (ServiceA) {
$scope.service=ServiceA;
});
HTML:
<h1>{{service.item}}
</h1>
i am trying to achieve inheritance using angularjs .service(),I want to make serviceA() in moduleA as base service and create a service serviceB() in moduleB and this should inherit base service(serviceA()) and update variable 'item' in serviceA().
Controller code and html code remains same.
Is it possible? Is this a good approach? Can we achieve inheritance/abstraction using angularjs .service()?
angular.module("ModuleB").service("serviceB", function (serviceA) {
serviceA.item="B";
});
Whenever you define a module, you should pass a empty array or
dependencies as the second argument. i.e. angular.module("ModuleA",
[]) or angular.module("ModuleA", ['someDependent']).
The service is in one module whereas the controller is in the other module. So, you need to create a relation between them angular.module("ModuleX", ["ModuleA"]).
You are not returning anything from the service and you have written the method in wrong way.
Plnkr
Working Code
angular.module("ModuleA", []).service("ServiceA", function () {
var item=[];
this.get = function(){
item.push("A");
return item;
}
});
angular.module("ModuleX", ["ModuleA"]).controller("Ctrl", function ($scope, ServiceA) {
$scope.service = ServiceA.get();
console.log($scope);
});
following AngularJS in 60 minutes I'm trying to add factory to current code.
I have lineman angular app where angular is declared as follows:
angular.module("app", ["ngResource", "ngRoute"]).run(function($rootScope) {
// adds some basic utilities to the $rootScope for debugging purposes
$rootScope.log = function(thing) {
console.log(thing);
};
});
I want to add the following code but running into JS syntax issue
.factory('simpleFactory', function () {
var factory = {};
var customers = [];
factory.getCustomers = function () {
return customers;
};
return factory;
}
What's the right syntax to merge these 2 blocks? Also should I do mimic controllers directory to create factory or should I really add to the first block? Thanks
Technically you have already merged a certain block from another:
angular.module("app", ["ngResource", "ngRoute"])
.run(function($rootScope) {
// adds some basic utilities to the $rootScope for debugging purposes
$rootScope.log = function(thing) {
console.log(thing);
};
});
for your chain to continue invoking another method such that the "second block" you are talking about(technically its the third block right now), do not terminate the method invocation then simply remove the terminator ; and append the third block.
It must look like this:
angular.module("app", ["ngResource", "ngRoute"]).run(function($rootScope) {
// adds some basic utilities to the $rootScope for debugging purposes
$rootScope.log = function(thing) {
console.log(thing);
};
})
.factory('simpleFactory', function () {
var factory = {};
var customers = [];
factory.getCustomers = function () {
return customers;
};
return factory;
});
Note: Your third method invocation factory() was not closed properly, it lacks the closing parenthesis ) and the terminator symbol ;.
Make sure you chain the factory to your variable. It seems you broke your chain right now.