Wrapping an object with a delegate - javascript

A bad title and this might not be the best way to do what I'm trying to do (still learning javascript) but I'm trying to wrap a object using a delegate. The object in this case is an XMLHttpRequest.
var wrapper = function() {
this._delegate = /* get the delegate */
this._delegate.onreadystatechange = function() {
wrapper.readyState = this.readyState;
/* stuff that synchronizes wrapper goes here */
if(wrapper.onreadystatechange) {
wrapper.onreadystatechange();
}
};
return this;
}
The above is a simplification but when problem is that when I add an onreadystatefunction to the wrapper object like:
wrapper.onreadystatechange = function() {alert("hi)};
and the wrapper._delegate.onreadystatechange function is called, wrapper.onreadystatechange is always undefined and the alert popup never comes up. I think I'm getting my scope stuff wrong but I'm not exactly sure how to fix this. Would appreciate other suggestions but I would also like to know how to fix what I'm doing wrong. Thanks!
EDIT
Yup it was an incomplete example. sorry about that. I realized after trying to rewrite it into a complete example what my cause my issue. It seems if I don't have the outer "WRAP_FUNCTION" then it will work fine. I had written something like
WRAP_FUNCTION = (function() {
var originalXMLHttpRequest = window.XMLHttpRequest;
var wrapper = function() {
if(wrapper.wrapped) {
this._delegate = new originalXMLHttpRequest;
} else {
this._delegate = new window.XMLHttpRequest
}
this._delegate.onreadystatechange = function() {
wrapper.readyState = this.readyState;
/* stuff that synchronizes wrapper goes here */
if(wrapper.onreadystatechange) {
wrapper.onreadystatechange();
}
};
return this;
};
wrapper.prototype.open = function(method, url, async) {
this._delegate.open(method, url, async);
}
wrapper.prototype.send = function() {
this._delegate.send();
}
wrapper.wrapped = true;
return wrapper;
}
window.XMLHttpRequest = WRAP_FUNCTION;
HTML code:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="xmlhttp.js"></script>
<script type="text/javascript">
(function() {
var test = new XMLHttpRequest();
test.open("GET", "xmlhttp.js", true);
test.onreadystatechange=function()
{
if (test.readyState==4 && test.status==200)
{
alert("yay");
}
};
test.send();
})();
</script>
</body>
</html>

Try this.
var wrapper = function() {
// in this time var wrapper not yet defined completly
// if you want use wrapper on the finction
// need to use this instead of wrapper
var self= this;
this._delegate = /* get the delegate */
this._delegate.onreadystatechange = function() {
//this means _delegate is in this time
//if you want to use this(wrapper)
//set the value out of function
//like var self= this
//wrapper.readyState = this.readyState;
self.readyState = this.readyState;
/* stuff that synchronizes wrapper goes here */
//if(wrapper.onreadystatechange) {
// wrapper.onreadystatechange();
//}
if(self.onreadystatechange) {
self.onreadystatechange();
}
};
return this;
}

Related

JS prototyping Cannot set property 'moveRight' of undefined

I've a problem with this simple prototyping:
Game = function (moduleConfig, gameConfig) {
this.moduleConfig = moduleConfig;
this.gameConfig = gameConfig;
// Game-Commands
this.keyCommands = {
moveLeft: false,
moveRight: false
};
this.catcher = null;
this.stage = null;
return this;
}
/**
* Left arrow down
*/
Game.prototype.onKeyboardLeftDown = function () {
this.keyCommands.moveLeft = true;
}
/**
* Left arrow up
*/
Game.prototype.onKeyboardLeftUp = function () {
this.keyCommands.moveLeft = false;
}
I always get the error message: Uncaught TypeError: Cannot set property 'moveRight' of undefined when calling onKeyboardLeftDown and onKeyboardLeftUp. But i have declared moveLeft in the constructor in the keyCommands object.
The two methods were called on key down and key up events:
Game.prototype.init = function () {
// ...
// =========================================================================
// Set keyboard
KeyboardJS.on('left', this.onKeyboardLeftDown, this.onKeyboardLeftUp);
KeyboardJS.on('right', this.onKeyboardRightDown, this.onKeyboardRightUp);
// =========================================================================
};
My index.html looks like this:
<!DOCTYPE html>
<html>
<head>
<title>pixi.js example 1</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #000000;
}
</style>
<script src="js/pixi.dev.js"></script>
<script src="js/keyboard.js"></script>
<script src="js/moduleConfig.js"></script>
<script src="js/moduleResult.js"></script>
<script src="js/game.js"></script>
</head>
<body style="background-color: #EEEEEE">
<script>
var game = new Game(moduleConfig, {
screenWidth: (window.innerWidth - 10),
screenHeight: (window.innerHeight - 10),
bgColor: 0xEEEEEE
});
game.init();
</script>
</body>
</html>
Does some one see the failure? I have searched a lot, but i'm very confused (normally i develop only in c#...)
You're binding is wrong.
// Set keyboard
KeyboardJS.on('left', this.onKeyboardLeftDown, this.onKeyboardLeftUp);
this.onKeyboardLeftDown and this.onKeyboardLeftUp are called without the correct context
to fix this do something like:
KeyboardJS.on('left', this.onKeyboardLeftDown.bind(Game), this.onKeyboardLeftUp.bind(Game));
I would not recommend using bind() - for browser compatibility, but you can use something like lodash's bind or an bind "emulator" like:
function bind(fn, ctx) {
return function bound() {
return fn.apply(ctx, arguments);
};
}
Another way would be
var self = this;
KeyboardJS.on('left',
function(){self.onKeyboardLeftDown()},
function(){self.onKeyboardLeftUp()}
);
Your question is not complete, I do not see the relevant code where you try to define moveRight.
Possible problems:
you might have a typo, that keyCommands is spelled exactly
you might refer to keyCommands outside its scope
you might refer to keyCommands.moveRight before keyCommands is initialized
you might assign another value to keyCommands before referring to moveRight

get variable from a jQuery Plugin

I need to know how is possible to get a plugin variable outside the plugin, to test it with some test framework.
So this is my simplified plugin:
(function ($) {
$.fn.extend({
myPlugin: function (argumentOptions) {
var defaults = {
image: 'img/default.png',
};
this.textSend = '';
var options = $.extend(defaults, argumentOptions);
var globalHere = this;
return this.each(function () {
obj.mouseup(function(e) {
globalHere.textSend = 'test';
});
});
}
});
})(jQuery);
I need to the variable this.textSend outside the plugin.
I have tried in this way:
$(document).ready(function(){
var testfield = $('.txt');
testfield.myPlugin({
image:"../img/twitter.png"
});
testfield.focus();
testfield.trigger($.Event( "mouseup"));
console.log($.fn.myPlugin.textSend);
});
but the console.log return me undefined
How can i get that variable outside?
Thanks
You will want to make sure you are returning this like so:
(function($) {
$.fn.extend({
myPlugin: function(argumentOptions) {
var self = this;
self.textSend = 'something';
self.inc = 0;
self.mouseup(function(e) {
self.textSend = 'new thing #' + self.inc;
self.inc++;
});
return self;
}
});
})(jQuery);
var instantiated = $('button').myPlugin({});
$('input').val(instantiated.textSend);
$('button').click(function(e) {
$('input').val(instantiated.textSend);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<label>Current textSend:</label>
<input />
<br/>
<button>Change textSend</button>
Hopefully will get you on the right track.
Update
Try new code.
You can store it inside the closed scope you created around your plugin and expose it through another function. Of course it'll need some refactoring, but this is the general idea:
(function ($) {
var whateverNameYouWant; //here
$.fn.extend({
myPlugin: function (argumentOptions) {
var defaults = {
image: 'img/default.png',
};
this.textSend = '';
whateverNameYouWant = this.textSend; //here
var options = $.extend(defaults, argumentOptions);
var globalHere = this;
return this.each(function () {
obj.mouseup(function(e) {
globalHere.textSend = 'test';
whateverNameYouWant = this.textSend; //here
});
});
}
});
$.extend({
getWhateverNameYouWant: function() {
return whateverNameYouWant;
}
})
})(jQuery);
var value = $.getWhateverNameYouWant();
At line console.log($.fn.myPlugin.textSend);
use testfield.textSend . now it has become proprty of selector via myplugin.

jQuery - Why does my function break if called on document.ready?

I'm doing some HTML prototyping to explore some UX stuff. Whilst trying to work out why a Javascript function (which uses a lot of jQuery) wasn't working I broke it out into a JS Fiddle. It seems that when the function is called on document.ready it won't work and can't be executed with a click event. However, if it isn't called at document.ready then it will work! I'm probably missing something obvious...
Working: http://jsfiddle.net/NWmB5/
$(document).ready(function() {
$('#targetFirstDiv').click(function() {
setTimelinePosition($('#anotherDiv'));
});
$('#targetSecondDiv').click(function() {
setTimelinePosition($('#testDiv'));
});
});
var toDoCategories = [$("#testDiv"),$("#anotherDiv")];
/* Show current position on timeline */
function setTimelinePosition($position) {
var $theTimelineTrigger = $('span.timelineTrigger');
toDoCategories.forEach(function(currentCategory) {
var $deselectTimelinePositionElement = $(currentCategory, $theTimelineTrigger);
$($deselectTimelinePositionElement).removeClass('currentPosition');
});
var $selectTimelinePositionElement = ($($position,$theTimelineTrigger));
$($selectTimelinePositionElement).addClass('currentPosition');
}
Not Working: http://jsfiddle.net/NWmB5/5/
$(document).ready(function() {
setTimelinePosition($('#thirdDiv'));
$('#targetFirstDiv').click(function() {
setTimelinePosition($('#anotherDiv'));
});
$('#targetSecondDiv').click(function() {
setTimelinePosition($('#testDiv'));
});
});
var toDoCategories = [$("#testDiv"),$("#anotherDiv"),$("thirdDiv")];
/* Show current position on timeline */
function setTimelinePosition($position) {
var $theTimelineTrigger = $('span.timelineTrigger');
toDoCategories.forEach(function(currentCategory) {
var $deselectTimelinePositionElement = $(currentCategory, $theTimelineTrigger);
$($deselectTimelinePositionElement).removeClass('currentPosition');
});
var $selectTimelinePositionElement = ($($position,$theTimelineTrigger));
$($selectTimelinePositionElement).addClass('currentPosition');
}
You trying to get $("#testDiv"),$("#anotherDiv"),$("thirdDiv") before DOM ready event fired that's where the exact problem.Try after DOM ready fired
var toDoCategories = [$("#testDiv"),$("#anotherDiv"),$("thirdDiv")];
So get $("#testDiv"),$("#anotherDiv"),$("thirdDiv") after DOM ready event dispatched.
var toDoCategories; //NOTE HERE
$(document).ready(function() {
toDoCategories = [$("#testDiv"),$("#anotherDiv"),$("thirdDiv")]; //NOTE HERE
setTimelinePosition($('#thirdDiv'));
$('#targetFirstDiv').click(function() {
setTimelinePosition($('#anotherDiv'));
});
$('#targetSecondDiv').click(function() {
setTimelinePosition($('#testDiv'));
});
});
/* Show current position on timeline */
function setTimelinePosition($position) {
var $theTimelineTrigger = $('span.timelineTrigger');
toDoCategories.forEach(function(currentCategory) {
var $deselectTimelinePositionElement = $(currentCategory, $theTimelineTrigger);
$($deselectTimelinePositionElement).removeClass('currentPosition');
});
var $selectTimelinePositionElement = ($($position,$theTimelineTrigger));
$($selectTimelinePositionElement).addClass('currentPosition');
}

jQUery plugin issue in IE

I have created my jQuery custom plugin as;
(function($){
$.fn.userForm = function(){
var element = this;
var UserDataObj = {
name:"John",
email:"john#example.com",
phone:"9999999999",
desc:"some description"
}
this.supports_html5_storage = function()
{
};
this.saveFormData = function(param)
{
}
if (this.supports_html5_storage())
{
}
else
{
}
};
})(jQuery);
Now I am trying to call a method within my plug in as;
var myPlugin = new $.fn.userForm();
myPlugin.saveFormData(".formFieldUserData");
For some reason, the code breaks in IE while executing
var myPlugin = new $.fn.userForm();
How do I fix this issue?

ckeditor - onshow overiding custom definition

when using the ckeditor link dialog, I have custom code for some extra options. I would also like to grab the selected text to use - so I have called:
selectedContents = CKEDITOR.instances['my_editor'].getSelection().getSelectedText();
I want this to happen when the dialog is loaded. So I wrote an "onShow()" handler function... but that messes up the customizations that I have made to the dialog. I'm guessing that my onShow is grabbing the normal process for that event - how can I continue with the normal processing at that point?
dialogDefinition.onShow = function(evt)
{
contents = CKEDITOR.instances['my_editor'].getSelection().getSelectedText();
// now here, continue as you were...
}
Ok, I still have some issues, but the answer to this question is to grab the existing "onShow" handler before overwriting it. Use a global, then it can be called within the new handler:
var dialogDefinition = ev.data.definition;
var oldOnShow = dialogDefinition.onShow;
dialogDefinition.onShow = function(evt) {
// do some stuff
// do some more stuff
// call old function
oldOnShow();
}
Depending on Andy Wallace code:
var oldOnShow = dialogDefinition.onShow;
var newOnShow = function () {
//your code
}
and then:
dialogDefinition.onShow = function(){
oldOnShow.call(this, arguments);
newOnShow.call(this, arguments);
}
It helps me!
Correct syntax is:
/* if new picture, then open the Upload tab */
CKEDITOR.on('dialogDefinition', function(ev) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
var dialog = dialogDefinition.dialog;
if (dialogName == 'image2') {
dialogDefinition.onShow = CKEDITOR.tools.override(dialogDefinition.onShow, function(original) {
return function() {
original.call(this);
CKEDITOR.tools.setTimeout( function() {
if (dialog.getContentElement('info', 'src').getValue() == '') {
dialog.selectPage('Upload');
}
}, 0);
}
});
}
});

Categories