Pass dynamic parameters to callback function in a loop - javascript

I wanted to set some jQuery animatios dynamically.
The code:
function anim(data) {
for (index in data) {
(function(){
var props = {};
props[data[index].property] = data[index].value;
data[index].elem.animate(
props,
500,
function() {
data[index].callback();
}
);
})();
}
}
var data =[
{
elem: elem1,
property: 'prop1',
value: 'val1',
callback: function() {
console.log('callback1');
}
},
{
elem: elem2,
property: 'prop2',
value: 'val2',
callback: function() {
console.log('callback2');
}
},
];
anim(data);
The problem is binding callbacks. When the callback is fired, data[index] is not available in current scope. Can somebody tell me how to set those callback propery?

Here you used a closure of Immediately-invoked function expression. You have to pass data[index] as parameter.
(function(dindex){
var props = {};
props[dindex.property] = dindex.value;
dindex.elem.animate(
props,
500,
function() {
dindex.callback();
}
);
})(data[index]);

You can try like this as an alternative,
function anim(data) {
$.each(data, function(x,y){
var props = {};
props[y.property] =y.value;
y.elem.animate(
props,
500,
function() {
y.callback();
}
);
});
}

Related

Access correct "this" from callback function in array of functions inside an object

I’m trying to access “helperFunction” from inside a function in “steps” array. Obviously using “this” doesn’t refer to the correct object but I can’t seem to work out the proper solution.
const bannerAnimation = {
property: 0,
steps: [
function one() {
this.property = this.helperFunction();
},
function two() {
console.log(this);
}
],
helperFunction() {
// do some calculations and return the result
return 1;
},
doSteps(steps = this.steps) {
steps.forEach(step => {
setTimeout(step, 100);
});
}
};
bannerAnimation.doSteps();
All help much appreciated!
You can achiever this by using bind inside the callback to setTimeout to correctly bind the this to the correct context.
const bannerAnimation = {
property: 0,
steps: [
function one() {
this.property = this.helperFunction();
},
function two() {
console.log(this);
}
],
helperFunction() {
// do some calculations and return the result
return 1;
},
doSteps(steps = this.steps) {
var self = this;
steps.forEach(step => {
setTimeout(step.bind(self), 100);
});
}
};
bannerAnimation.doSteps();

How to check when data changes in component by itself with vue js?

I have method that changes data in itself, simple example:
Vue.component('component', {
template: '#component',
data: function () {
return {
dataToBeWatched: ''
}
},
methods: {
change: function (e) {
var that = this;
setTimeOut(function() {
that.dataToBeWatched = 'data changed';
}, 2000);
},
makeSmthWhenDataChanged: function () {
// ajax request when dataToBeWatched changed or when dataToBeWatched isn't empty
}
}
});
How to create such watcher using correct methods vue js?
Or I need to use props watching it in component?
Vue components can have a watch property which is an object. The object keys need to be the name of the prop or data that needs to be watched, and the value is a function that is invoked when the data changes.
https://v2.vuejs.org/v2/guide/computed.html#Computed-vs-Watched-Property
Vue.component('component', {
template: '#component',
data: function () {
return {
dataToBeWatched: ''
}
},
methods: {
change: function (e) {
var that = this;
setTimeOut(function() {
that.dataToBeWatched = 'data changed';
}, 2000);
},
makeSmthWhenDataChanged: function () {
// ajax request when dataToBeWatched changed or when dataToBeWatched isn't empty
}
},
watch: {
dataToBeWatched: function(val) {
//do something when the data changes.
if (val) {
this.makeSmthWhenDataChanged();
}
}
}
});

JS observer pattern

I try the observer pattern (by these two Urls: https://davidwalsh.name/pubsub-javascript, http://www.dofactory.com/javascript/observer-design-pattern) but listeners array is empty when I call the publish function.
main.pagination.event= (function () {
var listeners = [];
return {
subscribe: function (fn) {
listeners.push(fn);
return {
unsubscribe: function (fn) {
listeners= listeners.filter(
function (item) {
if (item !== fn) {
return item;
}
}
);
}
};
},
publish: function () {
//it's empty
listeners.forEach(function (item) {
item("...");
});
}
};
})();
main.pagination.init = function () {
$('ul li').click(function () {
main.pagination.event.publish();
};
};
main.update.init = function() {
var event = main.pagination.event.subscribe(main.update.listener);
};
main.update.listener = function (tbl) {
alert(tbl);
};
Thanks for help.
It is empty because you call subscribe after publish which does not contain anything inside the listeners array. Just change the order of the calls like so
main.update.listener = function (tbl) {
alert(tbl);
};
main.pagination.init = function () {
$('ul li').click(function () {
main.pagination.event.publish();
};
};
main.update.init = function() {
var event = main.pagination.event.subscribe(main.update.listener);
};
main.update.init(); // invoke subscribe first to add the listener to the array
main.pagination.init();

javascript: extending methods between objects, like mixins

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()

unable to access function from another function using this within same object

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.

Categories

Resources