Javascript wrong binding: function disappear but variables ok - javascript

The problem is that when I am binding this to function in .then() of Promise all variables is binded but 1 which is function, not.
define([
'Service/service',
'core/widget'], function (service, widget) {
return widget.extend({
init: function (options) {
this.options = options;
console.log('this.options: ', this.options); //{actionToDo:function(),variables...}
service.getFile('app/Core/Widgets/Button/Views/button.html')
.then(
function(){
console.log('this.options: ', this.options); //{actionToDo:undefined,...}
}.bind(this)
)
}
});});
I am creating the object by:
new Button(
{
elementToAppend: this.className + ' .actions > .actionButtons',
class: action.class,
icon: action.icon,
text: action.text,
unique: action.unique,
actionToDo: function(){//some code}
}
);
And the widget:
define(['underscore'], function (_) {
function Widget() {
}
return {
extend: function (methods) {
var widget = new Widget();
widget.prototype = {
trigger: function (event) {
switch (event) {
case 'click':
{
this.onClick.call(this);
break;
}
}
}
};
var Widget_Extended = _.extend(widget.prototype, methods);
return function (options) {
Widget_Extended.init(options);
return Widget_Extended;
};
}
};});
Could you tell me why inside function in .then() 1 parametr of options is undefined?

The solve of the problem (I guess) is:
define(['underscore'], function (_) {
function Widget() {
}
return {
extend: function (methods) {
return function (options) {
var widget = new function () {
};
widget.prototype = {
trigger: function (event) {
switch (event) {
case 'click':
{
this.onClick.call(this);
break;
}
}
}
};
var Widget_Extended = _.extend(widget.prototype, methods);
Widget_Extended.init(options);
return Widget_Extended;
};
}
};});

Related

How to make module pattern each function a promise?

I use Angular 1.5 and I made a factory function which is return a literal object like this:
return {
item: null,
get: function() {
return item;
},
create: function() {
if (this.get()){
this.remove();
}
this.item = {};
},
remove: function() {
var item = this.get();
if (item) {
this.item = null;
}
},
add: function() {
if (!this.get()) {
this.create();
}
this.item.newprop = 'value';
}
}
please do not ask me to change to function declaration. I want a object with his own actions(functions) and properties that is working on.
This pattern (like get inside create so on..) I didn't copied from anywhere. so I'm wonder if has a name? It is best way to deal with function-black boxes?
What is the best way to put Promise inside? so every function should return a promise
every then function I need to use bind???
todo like this:
create: function () {
this.get()
.then(remove)
.then(function () {
this.item = {}; // BUT this === undefined!!
});
}
You have to use bind in every then callback function:
var myModule = {
item: null,
get: function() {
return Promise.resolve(this.item);
},
create: function() {
return this.remove().then(function() {
this.item = {};
}.bind(this));
},
remove: function() {
return this.get().then(function(item) {
if (item) {
this.item = null;
}
}.bind(this));
},
add: function() {
return this.get().then(function(item) {
return item || this.create();
}.bind(this)).then(function() {
this.item.newprop = 'value';
}.bind(this));
}
}
// Let see it working:
myModule.create().then(function() {
return myModule.get();
}).then(function(item) {
console.log("After create: ", item);
return myModule.remove();
}).then(function() {
return myModule.get();
}).then(function(item) {
console.log("After remove: ", item);
return myModule.add();
}).then(function() {
return myModule.get();
}).then(function(item) {
console.log("After add: ", item);
});

Simulating drag drop with react testutils not working

I'm try to test my ReactJS mixin for drag and drop functionality using jasmine, karma and React TestUtils.
No exception is thrown but when debugging it seems that the function bound to the event listener not being executed when the event is simulated.
You can clone the it here:
https://github.com/itsh01/react-dragdrop/tree/testing-simutale-events
Thank you very much in advance.
Here is my test:
beforeEach(function () {
var CompDrag = React.createClass({
mixins: [DragDropMixin],
dragDrop: function dragDrop() {
return {
draggable: true,
dropType: 'test',
dataTransfer: {
test: true
}
};
},
render: function render() {
return React.createElement('div', {});
}
});
var CompDrop = React.createClass({
mixins: [DragDropMixin],
dragDrop: function dragDrop() {
var self = this;
return {
droppable: true,
acceptableTypes: ['test'],
drop: function (data) {
self.setState(data);
}
};
},
render: function render() {
return React.createElement('div', {});
}
});
elementDrag = React.createElement(CompDrag, {});
elementDrop = React.createElement(CompDrop, {});
});
...
it('should attach drop functionality when configured', function () {
var renderedDrag = TestUtils.renderIntoDocument(elementDrag);
var renderedDrop = TestUtils.renderIntoDocument(elementDrop);
var nodeDrag = renderedDrag.getDOMNode();
var nodeDrop = renderedDrop.getDOMNode();
var mockEvent = {
preventDefault: function () {},
dataTransfer: {
types: ["objtopass"],
setData: function () {},
getData: function () {
return JSON.parse({
dropType: 'test',
data: {
test: true
}
});
}
}
};
TestUtils.SimulateNative.dragStart(nodeDrag, mockEvent);
TestUtils.Simulate.dragOver(nodeDrop, mockEvent);
TestUtils.Simulate.drop(nodeDrop, mockEvent);
expect(renderedDrop.state).not.toBeNull();
});
Here is the mixin:
'use strict';
var _ = lodash;
var DragDropMixin = {
/*
* usage:
*
* mixins: [DragDropMixin],
* dragDrop: function () {
*
* return {
*
* // when dragging an item
* draggable: true,
* dropType: 'myItem',
* dataTransfer: { myItemData: property }
*
* // when dropping an item:
* droppable: true,
* acceptableDrops: ['myItem'],
* drop: function (myItem) {},
* };
* }
*
*/
isAttrEnabled: function (attr) {
return this.dragDropData && this.dragDropData[attr];
},
isDroppable: function () {
return this.isAttrEnabled('droppable');
},
isDraggable: function () {
return this.isAttrEnabled('draggable');
},
componentDidMount: function () {
var node = this.getDOMNode();
this.dragDropData = this.dragDrop();
if (this.isDroppable()) {
node.addEventListener('dragover', this.handleDragOver, this);
node.addEventListener('drop', this.handleDrop, this);
}
if (this.isDraggable()) {
node.draggable = true;
node.addEventListener('dragstart', this.handleDragStart, this);
}
},
componentWillUnmount: function () {
var node = this.getDOMNode();
if (this.isDroppable()) {
node.removeEventListener('dragover', this.handleDragOver);
node.removeEventListener('drop', this.handleDrop);
}
if (this.isDraggable()) {
node.removeEventListener('dragstart', this.handleDragStart);
}
},
handleDragOver: function (e) {
e.preventDefault();
},
handleDrop: function (e) {
var jsonData = e.dataTransfer.getData('objToPass'),
passedObj = JSON.parse(jsonData),
acceptableDrops = this.dragDropData.acceptableDrops;
e.preventDefault();
if (!this.dragDropData.drop) {
throw new Error('Must define drop function when using droppable');
}
if (_.includes(acceptableDrops, passedObj.dropType)) {
this.dragDropData.drop(passedObj.data);
}
},
handleDragStart: function (e) {
var objToPass = {
data: this.dragDropData.dataTransfer,
dropType: this.dragDropData.dropType
};
e.dataTransfer.setData('objToPass', JSON.stringify(objToPass));
}
};
Thanks again.
OK, got it.
I was actually listening to native events and simulating React synthetic events.
Fixed it by changing the mixin:
componentDidMount: function () {
var node = this.getDOMNode();
this.dragDropData = this.dragDrop();
if (this.isDroppable()) {
node.ondragover = this.handleDragOver;
node.ondrop = this.handleDrop;
}
if (this.isDraggable()) {
node.draggable = true;
node.ondragstart = this.handleDragStart;
}
},
And testing by triggering a native event
nodeDrag.ondragstart(mockEvent);
nodeDrop.ondragover(mockEvent);
nodeDrop.ondrop(mockEvent);
expect(DragDropMixin.handleDrop).toHaveBeenCalled();
expect(renderedDrop.state).toBeNull();

TypeScript - JavaScript using knockout.js not working in IE8 - "Object doesn't support this property or method"

I have this code (also shown below) that is giving me an error in IE8 but is fine in Chrome and PhantomJS.
The error is "Object doesn't support this property or method knockout-2.2.1.debug.js, line 2319 character 35", which is called from currentPage(pages[pages.indexOf(current) + steps]);
I have no clue why it's not working, so any help would be greatly appreciated!
var Page = (function () {
function Page(index, name, canNavigateToPage, navigatedToThisPage) {
this.index = index;
this.name = name;
this.canNavigateToPage = canNavigateToPage;
this.navigatedToThisPage = navigatedToThisPage;
}
Page.prototype.navigateToPage = function () {
if (this.canNavigateToPage()) {
this.navigatedToThisPage(this);
}
};
return Page;
})();
var AccountSearchParameters = (function () {
function AccountSearchParameters() {
this.reference = ko.observable();
this.scheme = ko.observable();
this.lastName = ko.observable();
this.sufficientInputToSearchForAccount = ko.computed(function () {
return this.reference() && this.scheme() && this.lastName();
}, this);
}
return AccountSearchParameters;
})();
function viewModel() {
var self = this,
currentPage = ko.observable(),
accountSearchParameters = new AccountSearchParameters(),
forwardPageProgressionGuards = {
'1': function canMoveToPage2() {
return accountSearchParameters.sufficientInputToSearchForAccount();
},
'2': function canMoveToPage3() {
return true;
},
'3': function canMoveToPage4() {
return true;
}
},
canMoveToNextPage = function (currentlyOnPage) {
function disallowPageMovementNotExplicitlyDefined() {
return false;
}
return (forwardPageProgressionGuards[currentlyOnPage] || disallowPageMovementNotExplicitlyDefined)();
},
canMoveToPreviousPage = function (currentlyOnPage) {
return currentlyOnPage > 1;
},
pages = [
new Page(1, 'Customer details', function () {
return true;
}, function (page) {
currentPage(page);
}),
new Page(2, 'Bank details', forwardPageProgressionGuards['1'], currentPage),
new Page(3, 'Payment details', forwardPageProgressionGuards['2'], currentPage),
new Page(4, 'Confirmation', function () {
return true;
}, currentPage)],
pageNavigator = function (canNavigate, steps) {
current = currentPage();
console.log(canNavigate(current.index));
if (canNavigate(current.index)) {
currentPage(pages[pages.indexOf(current) + steps]);
}
};
currentPage(pages[0]);
self.page = ko.computed(function () {
return currentPage();
});
self.accountSearchParameters = accountSearchParameters;
self.nextPage = function () {
pageNavigator(canMoveToNextPage, 1);
};
self.previousPage = function () {
pageNavigator(canMoveToPreviousPage, -1);
};
self.canMoveToNext = ko.computed(function () {
return canMoveToNextPage(currentPage().index);
});
return self;
}
$(function () {
ko.applyBindings(viewModel());
});
indexOf in IE8 does not supported, use $.inArray

Javascript variable scope

Is it possible for me to call selectCompanyJump(this) internally without calling it from App.site.profile?
Instead of doing App.site.profile.selectStateJump(this); can I do like parent.selectStateJump(this); without reassigning this outside of the .change() call?
$(document).ready(function () {
App.site = function () {
return {
init: function () {
this.profile.init();
},
profile: function () {
var profile;
return {
init: function () {
profile = $('div#profile');
$('select[name="company_id"]', profile).change(function () {
App.site.profile.selectCompanyJump(this);
});
$('select[name="state_id"]', profile).change(function () {
App.site.profile.selectStateJump(this);
});
},
selectCompanyJump: function (select) {
$(select.parent()).submit();
},
selectStateJump: function (select) {
$(select.parent()).submit();
}
}
}()
}
}();
App.site.init();
});
You can reference the "this" scope you want as another variable outside change() function definitions:
profile: function () {
var profile;
return {
init: function () {
profile = $('div#profile');
var self = this;
$('select[name="company_id"]', profile).change(function () {
self.selectCompanyJump(this);
});
$('select[name="state_id"]', profile).change(function () {
self.selectStateJump(this);
});
},
selectCompanyJump: function (select) {
$(select.parent()).submit();
},
selectStateJump: function (select) {
$(select.parent()).submit();
}
}
}()
Assuming that you are just using the select argument of your functions to reference the element that triggered the event you could just pass a pointer to the event binder and then use the this keyword.
profile: function () {
var profile;
return {
init: function () {
profile = $('div#profile');
$('name="state_id"', profile).change(this.selectStateJump);
},
selectStateJump: function () {
$(this).parent().submit();
}
}
you can do the following
$(document).ready(function () {
App.site = function () {
var me = this;
me.selectStateJump = function selectStateJump (select) {
$(select.parent()).submit();
}
return {
....
selectStateJump: selectStateJump
}
and you'll be able to call just me.selectStateJump()
EDIT:
actually below would be enough
$(document).ready(function () {
App.site = function () {
function selectStateJump (select) {
$(select.parent()).submit();
}
return {
method : function(select) {
selectStateJump(select);
}
selectStateJump: selectStateJump
}

Variable Scope: cross-class function call

I have a vehicle and a product object and I need vehicle to call a function within product.... I can't seem to figure it out, what should I do here?
var vehicle = function () {
return {
init: function () {
var that = this;
jQuery('.vehicle-year-profile .options .delete').bind('click', function (e) {
e.preventDefault();
that.remove(jQuery(e.currentTarget).parents('.vehicle-year-profile'));
});
jQuery('.vehicle-year-profile .options .edit').bind('click', function (e) {
e.preventDefault();
that.edit(jQuery(e.currentTarget).parents('.vehicle-year-profile').attr('id'));
});
jQuery('#association-detail .save').bind('click', function (e) {
e.preventDefault();
that.save();
});
},
edit: function (id) {},
save: function () {},
remove: function (el) {},
reset: function () {}
}
}();
var product = function () {
return {
refreshHistory: function () {}
};
}();
Have you tried
product.refreshHistory();
?? The variable "product" is global (or at least relatively global), so code inside the "vehicle" object can refer to it directly.

Categories