I feel like this is probably a dumb question but I'm having trouble visualizing how to make this work.
I have a factory used to share data between controllers, like this:
app.factory('DataShare', function(){
//Share Data between controllers via the sharedItem object and the get/set functions
var sharedItem = {};
function set(sharedData){
sharedItem = sharedData;
}
function get(){
return sharedItem;
}
return{
set: set,
get: get
};
});
It works just fine. The issue is that are several times in my application where I need to share data. Currently, I have multiple factories with different names containing the same methods shown above. Can someone advise on the best way to create an abstract factory that I could reuse to share different data between different controllers?
Create a new file and declare a new object.
var mySharedLib = mySharedLib || {}; // declare a new namespace for the shared code.
mySharedLib.DataShare = function() {
// your factory logic
}
Then, the angular side:
app.factory('DataShare', mySharedLib.DataShare);
Related
Am moving some javascript logic into an Angular 2 app. Part of it involves a homegrown library of "formatter" functions [they do more than just formatting, so pipes are not an option] Currently these are passed by name (string) and the receiving function uses window[fName] to convert them to a function reference.
So there's a formatter function:
var tickPositionerYMD = function() { ticks=[]; ... complex logic ... return ticks; }
And a build function:
build(x, y, formatterName) {
...
formatter = window[formatterName];
...
}
And the build is called with a particular formatter:
build(xData, yData, 'tickPositionerYMD');
In javascript, window[] is used to create a function reference.
Question is ... what's the best way to do this in an Angular 2 component? Have seen one approach where a service is created with a reference to window ... this is passed in through DI.
A second approach is to create a factory function which given a name, returns a function.
Given those choices, am inclined to go with the factory function. Being new to Angular, was wondering if I might be missing a better approach.
You should use Angular services.
Each service is a singleton, so when you inject it to your components all all refferences will be pinting to the same instance.
So when you define formatters int your service, you should expose either method getFormatter(formatterName) or Map of Formatters and use it like this:
// method:
let formatter = formatterService.getFormatter('myForm');
// Map:
let anotherFormatter = formatterService.formatters['myForm']
Just don't forget that you inject services not instantiate.
I'm looking for some way to add IOC to my angularjs application.
My app is a multi tenant app and I need to use different services for different tenants with the same registration name.
I'm using TypeScript as well and it works well with using concrete types over interfaces.
My main problem is how can I decide how to register the correct service to my application.
This is an example:
var app = angular.module('app',[]);
// common registrations
app.service('commonService1', commonServiceFunction1);
app.service('commonService2', commonServiceFunction2);
app.service('commonService3', commonServiceFunction3);
app.service('commonService4', commonServiceFunction4);
// here I want to register the same service name with a different implementation
app.service('serviceName', serviceOneFunction); // sometimes I will need this service
app.service('serviceName', serviceTwoFunction); // sometimes I will need this service
Things I thought about:
Add some logic and download the correct js files per source - Function names will stay the same and I will need to figure out a way to provide the correct js file that includes the correct functions.
Override the registrations (e.g. register the common service and then override the registration with a specific implementation).
Both solutions ugly and not scalable to me.
I would like to have a IOC container or some other solution that is a bit more nice and scalable.
If I have understood question correct, you can register services(which are actually providers) as provider which you configure at angular configuration step.
So, it may look like this:
var app = angular.module('app',[]);
// common registrations
app.service('commonService1', commonServiceFunction1);
app.service('commonService2', commonServiceFunction2);
app.service('commonService3', commonServiceFunction3);
app.service('commonService4', commonServiceFunction4);
app.provider('serviceName', function ServiceNameProvider() {
var service = DefaultService;
this.setService = function(newService) {
service = newService
}
this.$get = [function() {
return service;
}];
});
app.config(["serviceNameProvider", function(serviceNameProvider) {
if(someCondition) {
serviceNameProvider.setService(ServiceImpl1);
} else {
serviceNameProvider.setService(ServiceImpl2);
}
}]);
Services, factory are just syntactic sugar over provider. You can determine your service function at configuration stage of angular. ServiceImpl1, ServiceImpl2 are just functions but you can use dependency injection there as they will be called by provider with $injector.invoke. Read about providers
Hope this will help you. Try Using angular factory.
angular.module('app').factory('tenantService', function() {
var tenantService = undefined;
if(tenantType == "1"){
tenantService = new TenantService1();
} else if(tenantType == "2"){
tenantService = new TenantService2();
} else {
tenantService = new TenantDefService();
}
return tenantService;
});
I wanted to know if its good practice to use it like following since I used a global field cacheObj
I need to parse the data and share it between other modules,any module can take any property but only the first module which called to this parser is responsible to provide the data to parse(I need to do this parse just once and share properties in different modules)
This code is from other SO post and I want to use it
var Parser = require('myParser'),
_ = require('lodash');
var cacheObj; // <-- singleton, will hold value and will not be reinitialized on myParser function call
function myParser(data) {
if (!(this instanceof myParser)) return new myParser(data);
if (!_.isEmpty(cacheObj)) {
this.parsedData = cacheObj;
} else {
this.parsedData = Parser.parse(data);
cacheObj = this.parsedData;
}
}
myParser.prototype = {
//remove `this.cacheObj`
getPropOne: function () {
return this.parsedData.propOne;
},
getPropTwo: function () {
return this.parsedData.propTwo;
}
};
module.exports = myParser;
It kindda looks like the Context Object pattern, which is used for maintaining state and for sharing information. Some consider it a bad practice and prefer Singleton when it comes to share the object between layers, but if suites your case (in the same module) - my advice is to use it.
UPDATE
The main reason why you shouldn't use ContextObject through your layes is because it binds all sub-systems together( one object is referencing everything else). While Singleton is not just for creating objects, it is also services as access point that can be loaded by the corresponding sub-system. Having a Singleton represent every service access point allows for seamless vertical integration of cooperating components/modules. Simple code example:
Singleton:
// returns the "global" time
var time = Clock.getInstance().getTime();
Context object:
// allows different timezones to coexist within one application
var time = context.getTimezoneOffset().getTime();
I'd like to know how would be a good way to store data in angular.js that will be accessed across the app from different controllers. I'm using restangular to access the data on the backend. I have my own services to access the data, something like this:
app.factory('models.user', function(Restangular) {
var users;
users = {};
return {
get: function(user_id) {
return users[user_id] || (users[user_id] = Restangular.one('users', user_id).get());
}
};
});
For all models I define a service to access it. Using this, from any place of the app when I call User.get(1) I get the same model instance.
I'd like to find a better way to do so. What do you guys do in to keep the same instances in your Angular.js apps?
This is the pretty best way. Why do you confused by this code?
I want to add views and stores in controller dynamically. So, I've had this:
Ext.define('App.controller.MyController', {
extend: 'Ext.app.Controller',
stores: ['App.store.Users'],
views: ['App.view.Users.Index'],
I'm creating this controller dynamically with:
var controller = this.getController("Users");
How can I add store and views dynamically, something like:
var controller = this.getController(moduleID);
controller.stores = [];
controller.views = [];
controller.stores.push('App.store.Users');
controller.views.push('App.view.Users.Index');
But when I do that, it's not working. Console is telling me that Ext can't get "buffered from undefined" so I'm thinking that I have to do this with Ext.apply() or Ext.merge() or something like that to get getters and setters for stores.
What do you think?
EDIT for #asgoth:
When you use this.getController("nameOfController"); and if the controller doesn't exists, Ext-JS creates one for you. That's working 100% because when I console.log(controller); I'm getting data (and docs says that too). :)
You do not have that much choices, because you will need to have the arrays ready when you are instantiating the controller. By default this happens only once cause it should be managed by the Ext.app.Application Controller (instance).
First point is that you cannot use the getController method here because it does not accept any additional configuration. So the easiest solution would be the implementation of your own getController method, slightly renamed to avoid overriding.
here is a example one:
getControllerInstance: function(name, cfg) {
var me = this.application,
controllers = me.controllers,
controller = controllers.get(name);
if (!controller) {
controller = Ext.create(me.getModuleClassName(name, 'controller'), Ext.ApplyIf({
application: me,
id: name
},cfg);
controllers.add(controller);
if (me._initialized) {
controller.doInit(me);
}
}
return controller;
}
Please note that this variant does not add values to any array param instead it will override any any existing param!
Also note that all your controller will need to inherit from the controller that has this method.