Undefined even with null check - javascript

listener returns undefined, and I believe in start property. This is an observer object.
var updateP = {
cb: function (event, properties) {
"listener" in window? listener.next(properties):null
},
start: function (listener) {
dataset.on("update", this.cb)
},
stop: function () {
dataset.off("update", this.cb)
},
}

The listener variable is local to the start function, so you can't access it as a global variable.
Move the definition of this.cb inside updateP.start, then it will be able to acecss the lexical variable.
var updateP = {
start: function(listener) {
function asdf(ab) {
console.log(ab)
}
this.cb = function(event, properties) {
listener.next(properties)
};
dataset.on("update", this.cb)
},
stop: function() {
if (this.cb) {
dataset.off("update", this.cb);
}
},
}

Related

Calling a private/nested javascript function from an outer scope

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;
},
}

Using getter and setter on an object property that has his own properties

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
}
});

Console logging "this" returns "null"

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'.

Use of functions between inner object literals in javascript

My issue is I have 2 inner objects in my js class and I'm trying to use the methods from one of those objects in my other object (examples of what I'm trying to do below). I understand why this doesn't work because of a the scope. I'm just wondering if there is a way to get it to work.
var Class1 = {
self : this,
Obj1 : {
Obj1Method : function () {
alert("Do something");
},
Obj1Method2 : function () {
alert("Do something else");
},
InnerObj1 : {
InnerNestObj1Method : function (val) {
alert(val + 2);
}
}
},
Class1Method2 : function () {
this.Obj1.Obj1Method2();
},
Obj2 : {
Obj2Method : function (val2) {
self.Obj1.InnerObj1.InnerNestObj1Method(val2);
},
Obj2Method2 : function () {
self.Class1Method2();
}
}
};
Class1.Obj1.InnerObj1.InnerNestObj1Method(3); //works
Class1.Class1Method2(); //works
Class1.Obj2.Obj2Method2(); //No bueno
Class1.Obj2.Obj2Method(5); //No bueno
You can fix your example by replacing self with Class1.
The line self : this, is setting Class1.self to point to the global object (this when that line is evaluated).
var Class1 = {
self : this,
Obj1 : {
Obj1Method : function () {
alert("Do something");
},
Obj1Method2 : function () {
alert("Do something else");
},
InnerObj1 : {
InnerNestObj1Method : function (val) {
alert(val + 2);
}
}
},
Class1Method2 : function () {
this.Obj1.Obj1Method2();
},
Obj2 : {
Obj2Method : function (val2) {
Class1.Obj1.InnerObj1.InnerNestObj1Method(val2);
},
Obj2Method2 : function () {
Class1.Class1Method2();
}
}
};
Class1.Obj1.InnerObj1.InnerNestObj1Method(3); //works
Class1.Class1Method2(); //works
Class1.Obj2.Obj2Method2(); //bueno
Class1.Obj2.Obj2Method(5); //bueno
What happens when you do self: this
// If this is running in non strict mode, from the global scope, `this` points
// To the global object because there was no function call setting `this`
var Class1 = {
self : this,
};
What you need to understand is that this is set by whoever called the function using this. In the example above, there is no caller, so the runtime sets this to point to the global object.
Here's how you could you could make your object a bit more reusable and give yourself a reference to the outer object:
function createClass() {
var self = {
Obj1: {
Obj1Method: function() {
alert("Do something");
},
Obj1Method2: function() {
alert("Do something else");
},
InnerObj1: {
InnerNestObj1Method: function(val) {
alert(val + 2);
}
}
},
Class1Method2: function() {
self.Obj1.Obj1Method2();
},
Obj2: {
Obj2Method: function(val2) {
self.Obj1.InnerObj1.InnerNestObj1Method(val2);
},
Obj2Method2: function() {
self.Class1Method2();
}
}
};
return self;
}
var Class1 = createClass();
Class1.Obj1.InnerObj1.InnerNestObj1Method(3); //works
Class1.Class1Method2(); //works
Class1.Obj2.Obj2Method2(); //works
Class1.Obj2.Obj2Method(5); //works
You can do it with Classes:
"use strict"
class Class1 {
constructor() {
this.Obj1 = {
Obj1Method: function() {
alert("Do something");
},
Obj1Method2: function() {
alert("Do something else");
},
InnerObj1: {
InnerNestObj1Method: function(val) {
alert(val + 2);
}
}
};
var self = this;
this.Obj2 = {
Obj2Method: function(val2) {
self.Obj1.InnerObj1.InnerNestObj1Method(val2);
},
Obj2Method2: function() {
self.Class1Method2();
}
};
}
Class1Method2() {
this.Obj1.Obj1Method2();
}
};
var c1 = new Class1();
c1.Obj1.InnerObj1.InnerNestObj1Method(3); //works
c1.Class1Method2(); //works
c1.Obj2.Obj2Method(3); //works
c1.Obj2.Obj2Method2(); //works

javascript calling parent method from child

I have the following object:
var party =
{
food:
{
serve: function () {
// I want to call turnOff method from here
}
cleanUp: function () {
}
}
music:
{
turnOff: function () {
}
}
}
So as the comment points out, I want to call the turnOff method from the music object, how can I do this? this refers to the food object but I need to access the music object...
var party =
{
food:
{
serve: function () {
party.music.turnOff();
},
cleanUp: function () {
}
},
music:
{
turnOff: function () {
}
}
}
Use a constructor instead of a literal with a variable referencing the parent object
var party = new (function()
{
var self = this;
this.food =
{
serve: function () {
self.music.turnoff();
},
cleanUp: function () {
}
}
this.music =
{
turnOff: function () {
}
}
})();
Call it as party.music.turnOff().
FYI, your above code block isn't valid. You're missing some commas - after the serve and food closing braces.

Categories