Multiple Factories in Node? - javascript

Trying to create multiple factories in Node. Do they have to be in separate files? If they are, how do I make sure to access both?
index.js
var myFunc = function () {
this.data = {
thingOne: null,
thingTwo: null,
thingThree: null
};
this.fill = function (info) {
for (var prop in this.data) {
if (this.data[prop] !== 'undefined') {
this.data[prop] = info[prop];
}
}
};
this.triggerAction = function () {
//make some action happen!
};
module.exports = function (info) {
var instance = new myFunc();
instance.fill(info);
return instance;
};
When I add another function below that it breaks the existing code with an object [object Object] has no method 'triggerAction:'
var myFunc2 = function () {
this.data = {
thingOne: null,
thingTwo: null,
thingThree: null
};
this.fill = function (info) {
for (var prop in this.data) {
if (this.data[prop] !== 'undefined') {
this.data[prop] = info[prop];
}
}
};
this.triggerAction2 = function () {
//make some action happen!
};
};
module.exports = function (info) {
var instance = new myFunc2();
instance.fill(info);
return instance;
};
So do I have to put the second function in a separate file? And if I do, how do I modify package.json to make sure it sees the second file? Thanks!

The short answer is no.
The error you are seeing is caused because you are overwriting the value of the exports property of the module - effectively replacing the first assignment with the last.
If you want these to be in the same module, you would need to export them separately:
module.exports.factoryA = function(...) {...}
module.exports.factoryB = function(...) {...}
To reference these from another module either of these patterns would work:
var factories = require('./myfactories');
var factoryAResult = factories.factoryA(...);
var factoryBResult = factories.factoryB(...);
or
var factoryA = require('./myfactories').factoryA;
var factoryAResult = factoryA(...);

Related

How do i share my World instance across multiple step definition files in CucumberJS?

I am implementing a CucumberJS scenario which uses multiple steps across two different step definition files. The first step sets some variables on the World which have to be used by a step in the other step definition file.
The variable gets set correctly but when the step on the other file tries to read it it's undefined. Any ideas how to solve this apart from merging the step definition files?
example:
world.js
var World = function World() {
this.client = '';
};
module.exports.World = World;
test.feature
Given a variable A
Then some other step
step1.steps.js
module.exports = function () {
this.World = require(process.cwd() + '/test/features/support/world').World;
this.Given(/^a Variable A$/, function () {
this.client = 'abc';
});
};
step2.steps.js
module.exports = function () {
this.World = require(process.cwd() + '/test/features/support/world').World;
this.Then(/^some other step$/, function () {
console.log(this.client);
});
};
You are setting this.client instead of this.World.client. Moreover you should use an object and not a constructor in world.js:
world.js
module.exports = {
client: ''
};
step1.steps.js
var world = require('./test/features/support/world.js');
module.exports = function () {
this.Given(/^a Variable A$/, function () {
world.client = 'abc';
});
};
step2.steps.js
var world = require('./test/features/support/world.js');
module.exports = function () {
this.Then(/^some other step$/, function () {
console.log(world.client);
});
};
You could directly parameterise your test.feature :
Given a variable "abc"
Then some other step
now pass this variable in your step
step1.steps.js
module.exports = function() {
this.World = require(process.cwd() + '/test/features/support/world').World;
this.Given(/^a Variable "([^"]*)"$/, function(variable) {
this.client = variable;
});
};
step2.steps.js
module.exports = function() {
this.World = require(process.cwd() + '/test/features/support/world').World;
this.Then(/^some other step$/, function() {
console.log(this.client); // would print abc
});
};

JavaScript "Class" Structure to avoid using x = new widget();

I would like use the following syntax where the parameter is an ID of HTML element, very similar as to how you setup JWPlayer but I can't figure out how they did it. This is so I can make it as simple as possible for someone else to use.
myWidget("htmlTargetId");
I'm trying to avoid having to do:
myWidget = new MyWidget("htmlTargetId");
I know that I can create the first by doing:
var myWidget = function(target) {
// Do something here
}
myWidget("htmlTargetId");
I need to add methods and properties etc but I would like a "constructor" that will create elements in the "htmlTargetId". What would be the best way to do this?
I tried a few variations, this is the latest attempt:
var myWidget = (function () {
var _target = undefined;
// constructor
var widget = function (target) {
_target = target;
version = 12;
};
widget.prototype = {
constructor: widget,
doSomething: function () {
console.log("I will so something to", target);
}
};
return widget;
})();
// Try out the new code
myWidget("htmlTargetId");
console.log(myWidget.version);
myWidget.doSomething();
But this gives me "undefined" and "Uncaught TypeError: undefined is not a function" I assume this is because the return statement is returning a function rather than an object because I'm not using "new"?
// Trying to avoid having to do this
superWidget = new myWidget("htmlTargetId");
Many thanks!
If you want to have multiple Widget instances,
var myWidget = (function () {
// constructor
var Widget = function (target) {
this._target = target;
};
Widget.prototype = {
constructor: Widget,
version: 12,
doSomething: function () {
console.log("...", this._target);
}
};
return function init(target) {
return new Widget(target);
};
})();
var widget1 = myWidget("foo"),
widget2 = myWidget("bar");
console.log(widget1.version); // 12
widget1.doSomething(); // "..." "foo"
widget2.doSomething(); // "..." "bar"
However, if you only need one "instance", you don't need any constructor:
var myWidget = function (target) {
myWidget._target = target;
};
myWidget.version = 12;
myWidget.doSomething = function () {
console.log("...", myWidget._target);
}
myWidget("foo");
console.log(myWidget.version); // 12
myWidget.doSomething(); // "..." "foo"

How to create a Javascript function that inspects objects/ function based on property names that will survive minifcation?

Suppose I have a function proxyThrough like this:
function proxyThrough(parentClass, childObjPropertyName, methodName) {
parentClass.prototype[methodName] = function() {
this[childObjPropertyName][methodName].apply(this[childObjPropertyName], arguments);
};
}
childPropertyName and methodName are both strings, and it looks up the functions by name.
I know that this will not survive minification as a result.
How can I get functions like this to survive minification?
Example
This is what I am doing currently:
var BaseView = require('./BaseView');
var FooView = require('./FooView');
function BarView() {
this._fooView = new FooView();
}
BarView.prototype = Object.create(BaseView.prototype);
BarView.prototype.constructor = BarView;
BarView.prototype.anAction = function() {
this._barView.anAction.apply(this._barView, arguments);
};
BarView.prototype.anotherAction = function() {
this._barView.anotherAction.apply(this._barView, arguments);
};
This is what I would like to do instead:
var BaseView = require('./BaseView');
var FooView = require('./FooView');
function BarView() {
this._fooView = new FooView();
}
BarView.prototype = Object.create(BaseView.prototype);
BarView.prototype.constructor = BarView;
function proxyThrough(parentClass, childObjPropertyName, methodName) {
parentClass.prototype[methodName] = function() {
this[childObjPropertyName][methodName].apply(this[childObjPropertyName], arguments);
};
}
['anAction', 'anotherAction'].forEach(proxyThrough.bind(null, BarView, '_fooView'));
I guess it depends on how the minifier works, but if it renames the same property name consistently, you could use a helper function to get the minified property name:
function minifiedName(obj) {
for (var prop in obj) {
return prop;
}
}
[
minifiedName({anAction: null}),
minifiedName({anotherAction: null})
].forEach(proxyThrough.bind(null, BarView, '_fooView'));

Extend the properties returned by a function?

I'm a JS beginner. I have defined a function on my Backbone model as follows.
myFunction: function () {
return {
firstAttr: this.model.get('value-attribute')
};
}
It is available to me as this.myFunction.
From somewhere else in the code, I want to extend this.myFunction to return another attribute. In other words, I'd like it to return a dict with two attributes: { firstAttr: 'something', secondAttr: true }.
How can I do this?
I've tried:
this.myFunction().secondAttr = true;
but I know that's the wrong thing to do.
Assuming your model prototype looks like
var MyModel = Backbone.Model.extend({
myFunction: function () {
return {
// I assume you work directly on a model
// the principle would be the same with a wrapper object
firstAttr: this.get('value-attribute')
};
}
});
you can either mask your method on a model by model basis like this:
var m = new MyModel({'value-attribute': 'attr, the first'});
console.log(m.myFunction());
m.myFunction = function () {
var res = MyModel.prototype.myFunction.call(this);
res.secondAttr = true;
return res;
};
console.log(m.myFunction());
See http://jsfiddle.net/V8zt2/ for a demo
Or dynamically modify your prototype to alter all instances :
var f = MyModel.prototype.myFunction;
MyModel.prototype.myFunction = function () {
var res = f.call(this);
res.secondAttr = true;
return res;
};
var m = new MyModel({'value-attribute': 'attr, the first'});
console.log(m.myFunction());
http://jsfiddle.net/V8zt2/1/
How about modifying your myFunction to :
myFunction : function () {
var i,
obj = {};
for (i=0; i< arguments.length;i++){
obj['attribute'+(i+1)] = this.model.get(arguments[i]);
}
return obj;
}
This way you can send keys of model, that you want to be in the returned object as arguments to myFunction.

Reference error "object property is not defined"

I have the following structure:
appInterface = {
mainWinCanvas: document.getElementById("mainwindow"),
mainWinContext: mainWinCanvas.getContext("2d"),
mainWinCanvasWidth: mainWinCanvas.width,
mainWinCanvasHeight: mainWinCanvas.height,
mainWinCanvasData: mainWinContext.getImageData(0, 0, mainWinCanvasWidth, mainWinCanvasHeight)
}
and get this error in Firebug:
mainWinCanvas is not defined
What's causing it? I'm sure the script is called AFTER body element previous children are fully loaded.
My goal is to make the code more readable, it's no-object version is working :(
All you have to do is wrap this in a function and return it as object so the this context should be available to your current appInterface Object. Also convert your properties to methods, so you can able to do method chaining.
var appInterface = function () {
return {
canvas: null,
ctx: null,
mainWinCanvas: function (elem) {
if (this.canvas === null) {
this.canvas = document.getElementById(elem);
}
return this;
},
mainWinContext: function () {
this.ctx = this.canvas.getContext("2d");
return this;
},
mainWinCanvasWidth: function () {
return this.canvas.width;
},
mainWinCanvasHeight: function () {
return this.canvas.height;
},
mainWinCanvasData: function () {
this.ctx.getImageData(0, 0, this.mainWinCanvasWidth(), this.mainWinCanvasHeight());
return this;
}
};
};
Usage:
appInterface().mainWinCanvas('mainWindow').mainWinContext().mainWinCanvasWidth();
There's not much more coding, when creating an object with a constructor function:
function AppInterface (cnvid) {
this.mainWinCanvas = document.getElementById(cnvid);
this.mainWinContext = this.mainWinCanvas.getContext("2d");
this.mainWinCanvasWidth = this.mainWinCanvas.width;
this.mainWinCanvasHeight = this.mainWinCanvas.height;
this.mainWinCanvasData = this.mainWinContext.getImageData(0, 0, this.mainWinCanvasWidth, this.mainWinCanvasHeight);
}
var appInterface = new AppInterface("mainwindow");
You can even reuse the constructor, if you'd need more than one "appInterFace" in your app.
The object has no local context, you need to acces by its main reference appInterface
appInterface = {
mainWinCanvas: document.getElementById("mainwindow"),
mainWinContext: appInterface.mainWinCanvas.getContext("2d"),
mainWinCanvasWidth: appInterface.mainWinCanvas.width,
mainWinCanvasHeight: appInterface.mainWinCanvas.height,
mainWinCanvasData: appInterface.mainWinContext.getImageData(0, 0, appInterface.mainWinCanvasWidth, appInterface.mainWinCanvasHeight)
}
If you want to have local context use functions instead
EDIT
use function constructor instead, you need a live instance for self referencing
var appInterface = new function(){
this.test = 4;
};
appInterface = {
anotherTest:appInterface.test
}
console.log(appInterface.test)
One lame workaround to escape writting functions and getters/setters is to do the following:
appInterface = new Object();
appInerface.mainWinCanvas = document.getElementById("mainwindow");
appInerface.mainWinContext = appInerface.mainWinCanvas.getContext("2d");
...
This is stupid, i'm not deeply in JS but don't see the difference between new Object() and corresponging defining of its properties, or structure in the question ...

Categories

Resources