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.
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 wrote a small Angular1 app which has a Database service that is using LokiJS.
I was wondering if there is a way to dynamically add properties/functions to a Service/Factory.
I'm trying to add dynamic getter for every collection that is created via this Service.
Here my example:
Database.js
angular.module('MyApp')
.factory('Database', ['$log', '$q', 'Loki',
function Database($log, $q, Loki)
{
var _db,
dbInitialized = false;
function init(config)
{
// some logic here
}
function addCollection(name, cfg) {
// some logic here
_db.addCollection(name, cfg);
// this doesnt work, but is desired ->
/*this['get'+name] = this.getCollection.bind(this, name);*/
}
function getCollection(collectionName) {
// some logic here
return something;
}
return {
init: init,
addCollection: addCollection,
getCollection: getCollection
};
}
]
);
app.js
angular
.module('MyApp', ['lokijs'])
.run(['Database',
function (Database) {
Database.init();
Database.addCollection("MyCollection", {});
// then fill collection, afterwards ->
var collection = Database.getCollection("MyCollection");
// I would like to use Database.getMyCollection()
}]);;
Is there a way to modify a initialized Service/Factory?
The most appropriate place for that is decorator
app.decorator('Database', ['$delegate', function ($delegate) {
var Database = $delegate;
Database.init();
Database.addCollection("MyCollection", {});
...
return Database;
}]);
The recipe doesn't really differs from run block, but it guarantees that service will be initialized on injection, while run blocks depend on their order.
I have an Angular application where in I'm pulling from a model some data which is saved on the load of the app. For simplicity sake, I've explicitly defined the data which is being pulled.
The issue I have is that in one of my controllers I am running a function on load of the controller which modifies the data pulled from the model. The point is that I want that extra data for that page which is using that controller only. I don't want that data to be saved back into the model (which is what's happening).
My model:
'use strict';
(function () {
var PotsMod = function ($log, _) {
return {
pots: [
{"comp" : "comp1"},
{"comp" : "comp2"}
],
getPots: function () {
return this.pots;
},
};
};
angular
.module('picksApp.models')
.factory('PotsMod', PotsMod);
})();
My controller:
(function () {
function AdmCtrl($log, $routeParams, PotsMod) {
var vm = this;
vm.pots = PotsMod.getPots();
vm.init = function() {
// populate pot.competition
_.forEach(vm.pots, function(pot) {
pot.comp = "test";
});
console.log(PotsMod.getPots());
}
vm.init();
}
angular
.module('picksApp.controllers')
.controller('AdmCtrl', AdmCtrl);
})();
The final line in vm.init(), PotsMod.getPots(), returns to me the updated model, with the values of "comp" as test.
So I tried this instead - I put the debug line under vm.pots like so:
var vm = this;
vm.pots = PotsMod.getPots();
console.log(vm.pots);
vm.init = function() {....
This also returns to me the array where the object values are test...
So I tried one final thing and added an extra debug line in the vm.init() function too:
var vm = this;
vm.pots = PotsMod.getPots();
console.log(vm.pots);
vm.init = function() {
// populate pot.competition
_.forEach(vm.pots, function(pot) {
console.log(pot.comp);
pot.comp = "test";
});
console.log(PotsMod.getPots());
}
vm.init();
The result of this confuses me... The output in the console reads:
[{"comp":"test"},{"comp","test"}]
comp1
comp2
[{"comp":"test"},{"comp","test"}]
I must be missing something here because I don't understand how it can be defining a variable using a model's value, printing that variable with the updated values, then using the old values and printing them, then printing the updated values again from the model (even though nothing in this code touches the model).
Any help would be brilliant please, I see to be making a fundamental mistake somewhere. Thank you.
You're referencing the service's pots object in your controller, so your controller code is also modifying the service's code.
I created a Plunker to demonstrate how angular.copy() creates a deep copy of your service's 'pots', and thus your controller's model is no longer referencing the original.
In your case, all you need to change is vm.pots = angular.copy(getPots());
http://plnkr.co/edit/jg5mWIWds1KMJd51e3o5?p=preview
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 ...
}]);
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()
{
});