If i am inside hello.world.planet and i reference this.two, that will get siblings, how can i reference hello.planet without referring to the name of the variable, something similar to 'this'
var hello = {
world: {
one: {
},
two: {
},
three: {
}
},
planet: {
}
}
I'm not completely following where you want to make a reference, but you could try using .bind(). I hope this is what you're after to:
var hello = {
world: {
one: {
},
two: function() {
alert(this.planet);
}.bind(hello),
three: {
}
},
planet: {
}
}
Related
I want to share or reuse some logic between differents objects, that they will be pretty similar, just changing the "scope".
var Mixin = {
show: function () {
this.container.show();
},
hide: function () {
this.container.hide();
},
play: function (data) {
data.map().append();
}
};
var ObjectA = {
container: $('#container_a');
foo: function () {
this.play(otherData); // Mixin common method?
}
};
var ObjectB = {
container: $('#container_b'),
foo: function () {
this.play(data); // Mixin common method?
}
};
ObjectA.show() // show $('#container_a');
ObjectB.show() // show $('#container_b');
I was trying using underscore
_.extend(ObjectA, Mixin);
but it seems like I have issues with the reference of the Mixin (this reference to the last extended object), like if i need to clone the object and extend it?
Is there any approach to do something similar?
Thanks!!
EDIT: I having issue with the scope of 'this', that is referencing to window, when a pass as a callback a function inherits from the mixin, like this.
PersonMixin = {
mixinFoo: function () {
this.handleResponse();
}
};
Person = {
personMethod: function () {
OtherLibrary.libMehtod(this.mixinFoo);
}
};
Object.assign(Person, PersonMixin);
and then, something like this will fail, this an example stack trace
Person.personMethod();
OtherLibrary.libMethod(callbackMixin);
Ajax.post(callbackMixin);
callbackMixin(response); // this.handleResponse() is not defined, because this reference to window object.
EDIT 2: I can solve this issue using bind()
You can do this in a number of ways, my preference is adjusting the objects __proto__ property on creation which will cause it to inherit your mixin via its prototype chain. This does not require the use of underscore.
I adjusted your example for ES6 and made it a bit simpler but should get the point across.
const PlayerType = (
{ show() {
console.info(`show ${this.name}`)
}
, hide() {
console.info(`hide ${this.name}`)
}
, play: function (data) {
data.map().append();
}
}
)
const objA = { __proto__: PlayerType
, name: 'objA'
, foo(...args) {
this.play(...args)
}
}
const objB = { __proto__: PlayerType
, name: 'objB'
, foo(...args) {
this.play(...args)
}
}
objA.show()
objB.show()
Simpler and no ES6:
var Mixin = (
{ show() {
console.info('show ' + this.name)
}
, hide() {
console.info('hide ' + this.name)
}
}
)
var a = { __proto__: Mixin, name: 'a' }
var b = { __proto__: Mixin, name: 'b' }
a.show()
b.show()
Alternate - Does the same thing with Object.create().
var Mixin = (
{ show() {
console.info('show ' + this.name)
}
, hide() {
console.info('hide ' + this.name)
}
}
)
var a = Object.create(Mixin, { name: { value: 'a', enumerable: true } })
var b = Object.create(Mixin, { name: { value: 'b', enumerable: true } })
a.show()
b.show()
It works, just check your syntax also.
var Mixin = {
show: function() {
console.log(this.tmp);
}
}
var oA = {
tmp: 'tmpA'
}
var oB = {
tmp: 'tmpB'
}
var mA = Object.assign(oA, Mixin);
var mB = Object.assign(oB, Mixin)
mA.show();
mB.show()
I have the following:
$scope.option = {
generateID:function(){
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
},
values : [
{id:this.generateId()},
{id:this.generateId()},
{id:this.generateId()},
{id:this.generateId()}
],
markCorrect : function(option){
},
remove:function(option)
{
this.values = this.values.filter(function(value){return value.id!=option.id})
}
}
I always get a this.generateId is not a function error. I am pretty sure that i am missing something fundamental here!
It may be better to store the id generator function in a separate function so it is easier to reference:
function generateId = function() {
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
}
$scope.option = {
generateID: generateId,
values : [
{id: generateId()},
{id: generateId()},
{id: generateId()},
{id: generateId()}
],
markCorrect : function(option){
},
remove:function(option)
{
this.values = this.values.filter(function(value){return value.id!=option.id})
}
}
The primary issue is that you're trying to access properties of $scope.option in the middle of declaring it. Try doing something like this instead:
$scope.option = (function () {
function generateId () {
/* logic */
}
return {
values: [
{id: generateId()}
// ...
],
markCorrect: function () {},
remove: function () {}
};
}) ();
This is the 'revealing module pattern', i.e. a function that returns an object forming a closure on some other data or functionality.
There is a typo; rename generateID to generateId.
I would like to make nested JavaScript functions as a prove of concept. I found an example and modified it a little to fit my prove of concent:
var t = {
nestedOne: {
nest: function() {
alert('nest');
this.nestedTwo.nest2();
},
nest3: function() {
alert('nest3');
},
nestedTwo: {
nest2: function() {
alert('nest2');
t.nestedOne.nest3();
}
}
}
};
t.nestedOne.nest();
// *** Output is nest, nest2 and nest3 ***
This works, but I wonder why in nest2, I have to call by t.nestedOne.nest3, and not this.nestedOne.nest3, similar to how I call from nest2.
Its all about the context of this
The easiest way to explain, is to make a slight change to your code:
var t = {
nestedOne: {
nest: function() {
console.log('nest',this);
this.nestedTwo.nest2();
},
nest3: function() {
console.log('nest3',this);
},
nestedTwo: {
nest2: function() {
console.log('nest2',this);
t.nestedOne.nest3();
}
}
}
};
t.nestedOne.nest();
The output from the above is
nest Object { nestedTwo={...}, nest=function(), nest3=function()}
nest2 Object { nest2=function()}
nest3 Object { nestedTwo={...}, nest=function(), nest3=function()}
Note that in the second call, this refers to the function, no longer the object.
Now, you can make the following 2 changes
call next2 passing in the context of this:
this.nestedTwo.nest2.call(this);
use this in nest2:
this.nest3();
And all works as expected:
var t = {
nestedOne: {
nest: function() {
console.log('nest',this);
this.nestedTwo.nest2.call(this);
},
nest3: function() {
console.log('nest3',this);
},
nestedTwo: {
nest2: function() {
console.log('nest2',this);
this.nest3();
}
}
}
};
t.nestedOne.nest();
The context of a function call is determined by the object on which the function is called, not the left-most object in the path used to get to it.
this:
this.nestedTwo.nest2();
^^^^^^^^^
not this:
this.nestedTwo.nest2();
^^^^
I'm tring to map this
{ items: [
{ id: 1 },
{ id: 2 },
{ id: 3 }
]};
when creating something in the array I add a function to remove the item from the collection.
var mapping = {
'items': {
key: function(data) {
return ko.utils.unwrapObservable(data.id);
},
create: function(options) {
var o = (new(function() {
this._remove = function() {
options.parent.items.mappedRemove(options.data);
};
ko.mapping.fromJS(options.data, {}, this);
})());
return o;
}
}
};
this method works if I am removing an item added using items.mappedCreate but donĀ“t work with the items mapped on ko.mapping.fromJS.
When debugging I noticed that options.parent are not the same in the different situation.
Why? Should both methods return as parent the items observableArray?
I have set up a jsfiddle with an example http://jsfiddle.net/fampinheiro/9CcME/.
Thank you
I posted my problem in knockout ggroups
https://groups.google.com/d/topic/knockoutjs/cqBr_CPsfqc/discussion
and Roy Jacobs solved my jsfiddle problem.
I have an object that defines the name and parameters of a function to be called in the click event of a page element.
object_array = [
{
id: "id1",
onclick: "load_file(filename.php);",
},
{
id: "id2",
onclick: "open_url('http://url.com');",
}
];
That information must be retrieved dynamically. I'd like in the click event to call the onclick function for a given object in the array.
$('element').click(function() {
// call object.onclick
});
Seems that eval() is not a good choice. Is there a different way of calling that function?
You should refactor the object_array to:
[{
id: "id1",
action: "load_file",
url: "filename.php"
}, {
id: "id2",
action: "open_url",
url: 'http://url.com'
}];
Then you can call it with:
var actions = {
load_file: function(url) {
...
},
open_url: function(url) {
...
},
...
};
object_array.forEach(function(ob) {
$("#"+ob.id).click(function() {
actions[ob.action](ob.url);
});
});
If you have more complex arguments, you could also deliver an arguments array instead of url and use apply() on the function.
Or, if you just want a lookup-table of functions, use:
var object = {
"id1": function() {
load_file('filename.php');
},
"id2": function() {
open_url('http://url.com');
}
};
$('element').click(function() {
object[this.id]();
});
Here's a working jsfiddle:
http://jsfiddle.net/Zh6Fv/1/
Like so:
object_array = [
{
id: "id1",
// Encapsulate in an anonymous function
onclick: function(){ load_file('filename.php'); },
},
{
id: "id2",
// Encapsulate in an anonymous function
onclick: function(){ open_url('http://url.com'); },
}
];
Then actually bind it it like this ::
$('element').click(obj.onclick);
Presumably you would be using it like this::
object_array.forEach(function(obj){
// Note there is no need to wrap the obj.onclick
// into another anonymous function anymore!
$("#" + obj.id).click(obj.onclick);
});
Here's a working jsfiddle:
http://jsfiddle.net/Zh6Fv/1/
you can declare a function like
onclick : function()
{
action(arguments);
}