I am trying to create a js object, I want either the user passes in some json data or the objects properties are set by default as shown below. After that is all set, I finally want to call an init function that runs and does the work. Thanks for any help. I am not trying to create a jQuery plugin.
var PictureDialog = function (settings) {
settings = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1,
init: function() {
//Do work
//Show dialog
}
},settings;
}
Would the call look something like this
PictureDialog({prevID:1}).init();
Not sure why you would need an init function at all. This is how I would do it:
(function () {
var defaultSettings = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1
};
PictureDialog = function (settings) {
settings = settings || defaultSettings;
//Do work
//Show dialog
};
})();
The outer function is just to make sure that defaultSettings doesn't pollute the global scope.
If I understand correctly you want to set some default values, with the help of jQuery you can use $.extend like this:
function Foo( settings ) {
var _defaults = { a: 'a', b: 'b' };
settings = $.extend( settings, _defaults );
}
With pure JavaScript you'd have to do something like this:
function Foo( settings ) {
var _defaults = { a: 'a', b: 'b' };
settings.a = settings.a || _defaults.a;
settings.b = settings.b || _defaults.b;
}
As for the init method, you can just add it to the prototype and execute it in the constructor so you don't even have to call it when you create a new instance:
function Foo( settings ) {
var _defaults = { a: 'a', b: 'b' };
...
this.init();
}
Foo.prototype = {
init: function() {
console.log('initialized!');
}
}
The quick and simple way would be this:
var PictureDialog = function (settings)
{
settings = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1,
init: function()
{
//Do work
//Show dialog
return this;//<--return object, too
}
};
return settings;//return the object
};
foo = PictureDialog().init();//the init will be called on the return value of PictureDialog
I don't, however, get why the PictureDialog function expects a settings argument. Either pass nothing to the function at all, or alter the passed value:
var PictureDialog = (function()
{
var defaults = {
allowShortKey: true,
prevID: null,
prevCounterNumber: null,
startValue: 0,
nextValue: 1,
init: function()
{
//Do work
//Show dialog
return this;//<--Very important
};
return function (settings)
{
settings = settings instanceof Object ? settings : {};
for (var n in defaults)
{
if (defaults.hasOwnProperty(n))
{//set all properties that are missing from argument-object
settings[n] = settings[n] || defaults[n];
}
}
return settings;
};
}());
foo = PictureDialog({allowShortKey: false}).init();//will return full settings object
Related
I have a JS object that contains base options. If that object is initialized with a specific new option, I only want to change the one that was specified.
//Object :
var controller = function (){
var _id = id;
var _options = {
placeholder: "Search..."
value: "Some text",
width: 25,
...
};
// ==================================
// Public Functions
// ==================================
return {
init: function (id, options = null) {
...
}
}
}();
Example here i only change the placeholder property.
Call: controller.init('demo', options = { placeholder: 'Other value...' });
Expected change:
_options = {
placeholder: "Other value..."
value: "Some text",
width: 25,
...
};
You can use ... to merge the provided options into the default options.
var controller = function() {
var _id = id;
var _options = {
placeholder: "Search..."
value: "Some text",
width: 25,
// ...
};
// ==================================
// Public Functions
// ==================================
return {
init: function(id, options = {}) {
this.options = {..._options, ...options};
// ...
}
}
}();
You can use the below code.
_options = Object.assign(_options, options);
Here, _options will have default properties and values. options is input property with limited configuration. So, From this code, _options get only overuse with options properties.
Hope it's useful.
Object assign works too.
const thingy = (() => {
let myWords = {
favorite: "defenestrate",
leastFavorite: "whilst",
newest: "copacetic",
oldest: "dada",
};
return (words) => {
myWords = Object.assign(myWords, words);
console.log(JSON.stringify(myWords));
}
})();
// For the demo.
thingy({newest: "pyroclastic", fakest: "supercalifragilisticexpialidocious"});
I have my javascript code like this . Inside that I have an init() function and in that function I have an options JSON object and in that object I have a function defined as objectselected(). How I call that function in a button click event
I have tried like this WorkFlow.init().options.Objectselected() but it is not working,
var WorkFlow = {
connectionData: [],
selectedTouchpoints: [],
init: function () {
var options = {
palleteId: "myPaletteElement",
elementId: "playAreaContainer",
TextStoreList: ['One', 'Two', 'Three'],
LinkTextStoreList: $('#drpLinkType option').map(function () {
return this.text;
}).get(),
shapeList: ['RoundedRectangle', 'Circle', 'Rectangle', 'Ellipse', 'Square', 'Diamond', 'Card', 'Database'],
diagramUpdate: function (e) {
},
objectSelected: function (e) {
},
linkUpdate: function (e) {
},
initialize: function () {
}
myGraph = new Graph(options);
options.initialize();
},
}
How to call that function.
One way around is you can return options and than call it.
init: function () {
var options = {
...your code..}
return options;
},
and call it than
var options = WorkFlow.init();
options.Objectselected();
As it stands, you have no access to options because it's a local variable - that is, local to its scope.
To access its contents, you'll need to return it from init().
Think about it:
WorkFlow.init()
Currently this returns undefined, because your init() returns nothing. You're trying to chain like in jQuery, but that relies on the API always returning the instance. Your path finds a dead-end at init().
To fix this, have init() return options - or at least the part of it you want to access from outside - an "export".
So (basic example)
init: function() {
var options {
my_func: function() { }, //<-- we want outside access to this
private: 'blah' //<-- this can stay private - leave it out of the export
}
//return an export, exposing only what we need to
return {
my_func: options.my_func
}
}
You need to return options as it is inside init function's scope
var WorkFlow = {
connectionData: [],
selectedTouchpoints: [],
init: function () {
var options = {
palleteId: "myPaletteElement",
elementId: "playAreaContainer",
TextStoreList: ['One', 'Two', 'Three'],
LinkTextStoreList: $('#drpLinkType option').map(function () {
return this.text;
}).get(),
shapeList: ['RoundedRectangle', 'Circle', 'Rectangle', 'Ellipse', 'Square', 'Diamond', 'Card', 'Database'],
diagramUpdate: function (e) {
},
objectSelected: function (e) {
},
linkUpdate: function (e) {
},
initialize: function () {
}
myGraph = new Graph(options);
options.initialize();
return options;
},
}
And call it as WorkFlow.init().objectSelected();
Building on Patrick's comment, you'd need to return options from the init function:
var WorkFlow = {
connectionData: [],
selectedTouchpoints: [],
init: function () {
var options = {
palleteId: "myPaletteElement",
...
options.initialize();
return options;
},
}
I'm fairly new to getters and setters and am looking for a way to listen for changes in an object to store the data immediately, without calling a Save() function everytime a value gets changed. This is how I do it right now:
var myObject = {
Data: {
enabled: true,
show: false
},
Save: function () {
//store myObject.Data to local storage
},
Load: function () {
//load data from local storage and assign it to myObject.Data
},
doSomething: function () {
myObject.Load();
if (myObject.Data.enabled) {
myObject.Data.show = true;
myObject.Save();
}
}
Now I would like to optimize this code so everytime a property in myObject.Data is changed, myObject.Save() is executed. The problem I'm experiencing is that it seems only possible to define a getter for a property that has just one value, but not for a property that is an object itself.
var myObj = {
_Data: {
a: 0,
b: 1,
c: 3
},
set Data (a) {
console.log(a);
}
};
myObj.Data.a = 2;
This obviously doesn't work since myObj.Data is not an object and doesn't have the same properties as myObj._Data.
Thanks in advance for any help.
You are likely interested in the Proxy object.
I used a very simple debounce function callHandler in order to avoid calling the onSet method dozens of times during array modifications. Otherwise, [1, 2, 3].splice(0, 1) would call the set handler once per item in the original array.
'use strict';
var myObject = {
Data: {
a: [1, 2, 3],
b: {c: ['test']}
},
Save: function() {
console.log('Save called');
},
}
function recursiveProxy(target, onSet) {
// For performance reasons, onSet will only be called one millesecond
// after the set handler has last been called.
var timeout;
function callHandler() {
clearTimeout(timeout);
timeout = setTimeout(onSet, 1);
}
var recursiveHandler = {
get: function(target, property) {
// If the property is something that could contain another object,
// we want to proxy it's properties as well.
if (typeof target[property] == 'object' && target[property] != null) {
return new Proxy(target[property], recursiveHandler);
}
return target[property];
},
set: function(target, property, value) {
console.log('Set called - queueing onSet');
callHandler();
target[property] = value;
return true;
}
}
return new Proxy(target, recursiveHandler);
}
myObject.Data = recursiveProxy(myObject.Data, myObject.Save);
myObject.Data.a.splice(0, 1);
myObject.Data.b.c[0] = 'test 2';
I believe you are looking for Defining a getter on existing objects using defineProperty
To append a getter to an existing object later at any time, use
Object.defineProperty().
var o = { a:0 }
Object.defineProperty(o, "b", { get: function () { return this.a + 1; } });
console.log(o.b) // Runs the getter, which yields a + 1 (which is 1)
For e.g:
var Data = {
enable: true,
show: false
};
Object.defineProperty(Data, 'doSomething', {
get: function() {
// get something;
},
set: function(something) {
// set something
}
});
I am trying to create a flux store for a React app I am building. I am using an object-assign polyfill npm package and Facebook's Flux library.
Initially I was getting the error "Cannot read property '_data' of null' error in the console which was refering to var currIds = this._data.map(function(m){return m.id;});. That method is currently the only one being called directly. I then did console.log(this) which returned "null".
I find this strange. What is going on?
My code:
var Assign = require('object-assign');
var EventEmitterProto = require('events').EventEmitter.prototype;
var CHANGE_EVENT = 'CHANGE';
var StoreMethods = {
init: function() {},
set: function (arr) {
console.log(this);
var currIds = this._data.map(function(m){return m.id;});
arr.filter(function (item){
return currIds.indexOf(item.id) === -1;
}).forEach(this.add.bind(this));
},
add: function(item){
console.log(this);
this._data.push(item);
},
all: function() {
return this._data;
},
get: function(id){
return this._data.filter(function(item){
return item.cid === id;
})[0];
},
addChangeListener: function(fn) {
this.on(CHANGE_EVENT, fn);
},
removeChangeListener: function(fn) {
this.removeListener(CHANGE_EVENT, fn);
},
emitChange: function() {
this.emit(CHANGE_EVENT);
},
bind: function(actionType, actionFn) {
if(this.actions[actionType]){
this.actions[actionType].push(actionFn);
} else {
this.actions[actionType] = [actionFn];
}
}
};
exports.extend = function(methods) {
var store = {
_data: [],
actions: {}
};
Assign(store, EventEmitterProto, StoreMethods, methods);
store.init();
require('../dispatcher').register(function(action){
if(store.actions[action.actionType]){
store.actions[action.actionType].forEach(function(fn){
fn.call(null, action.data);
})
}
});
return store;
};
I can't see where set is called, however your this can be null if the function is invoked through call (see here) or apply, and your first argument is null.
This also happens in your require.register callback:
fn.call(null, action.data) //First parameter is your 'this'.
I have an app-object constructer that looks like this:
var app = function(loadedsettings) {
return {
init: function() {
this.loop();
},
loop: function() {
this.update();
window.requestAnimationFrame(this.loop);
},
update: function() {
//loop through settings and call update on every object.
},
settings: [
//array of settings objects, all with update methods.
]
};
}
Then when I do:
var theApp = app(settings);
theApp.init();
I get:
Uncaught TypeError: Object [object global] has no method 'update'
because when requestAnimationFrame is called, the this-value inside the loop function is set to window.
Does anybody know how to call requestAnimatinFrame with the 'theApp' object set as the this-value?
You can create a bound function (with a fixed this), and pass that to requestAnimationFrame:
var app = function(loadedsettings) {
return {
init: function() {
this.loop();
},
loop: function() {
this.update();
window.requestAnimationFrame(this.loop.bind(this));
},
update: function() {
//loop through settings and call update on every object.
},
settings: [
//array of settings objects, all with update methods.
]
};
}
I think that a browser which supports requestAnimationFrame will also support Function.prototype.bind, but in case you come across one that doesn't, there are polyfills available.
You need to cache a reference to this:
var app = function(loadedsettings) {
var self = this;
return {
init: function() {
self.loop();
},
loop: function() {
self.update();
window.requestAnimationFrame(self.loop);
},
** snip **
...