Object property is undefined inside event handler - javascript

For some reason when I call generateTabs I get this.divRow1 is undefined.
However when I instantiate Criteria it is not undefined.
What am I doing wrong?
function Criteria() {
this.divPortfolio = $("#portfolio_div");
this.divImport = $("#lstimprt_div");
this.rolling = $('#rolling');
this.datePickers = $("#datepickers");
this.dateStart = $("#datepicker");
this.dateEnd = $("#datepicker2");
this.btnToggle = $("#toggle");
this.btnRun = $("#run_report");
this.divRow1 = $("#Row1");
this.dateChoice = $("#datechoice");
this.minDate = $(".minDate");
}
Criteria.prototype.generateToggle = function () {
/** Toggle button toggle elements chosen open/closed **/
button.click(function () {
this.divRow1.toggle("slow");
this.divImport.toggle("slow");
$("#mindate_div").toggle("slow");
$("#header_row").toggle("slow");
return false; //Stops postback
});
};
/** When page loads **/
$(document).ready(function () {
var controls = new Criteria();
var mindate = controls.minDate.html();
controls.onloadHide();
controls.generatePicker(controls.dateStart);
controls.generatePicker(controls.dateEnd);
controls.generateToggle(controls.btnToggle);
});

it is because of the execution context of the callback method is not the Criteria object, it is the clicked button.
One solution to this is to pass a custom execution context using $.proxy()
button.click($.proxy(function () {
this.divRow1.toggle("slow");
this.divImport.toggle("slow");
$("#mindate_div").toggle("slow");
$("#header_row").toggle("slow");
return false; //Stops postback
}, this));
Another solution is to use a closure variable
var that = this;
button.click(function () {
that.divRow1.toggle("slow");
that.divImport.toggle("slow");
$("#mindate_div").toggle("slow");
$("#header_row").toggle("slow");
return false; //Stops postback
});

button.click(function () {
this.divRow1.toggle("slow");
this.divImport.toggle("slow");
$("#mindate_div").toggle("slow");
$("#header_row").toggle("slow");
return false; //Stops postback
});
this has a different scope within the click event than outside of it. Specifically, jQuery will bind this to the item the event is being fired on (the button in this case). If you set a breakpoint and examine this in the dev console at this point you'll see it refers to a DOM element.
You can get around this by setting a self variable like this, and referencing that instead.
Criteria.prototype.generateToggle = function () {
var self = this;
/** Toggle button toggle elements chosen open/closed **/
button.click(function () {
self.divRow1.toggle("slow");
self.divImport.toggle("slow");
$("#mindate_div").toggle("slow");
$("#header_row").toggle("slow");
return false; //Stops postback
});
};

Criteria.prototype.generateToggle = function () {
var that = this;
/** Toggle button toggle elements chosen open/closed **/
button.click(function () {
that.divRow1.toggle("slow");
that.divImport.toggle("slow");
$("#mindate_div").toggle("slow");
$("#header_row").toggle("slow");
return false; //Stops postback
});
};
The "this" context has changed inside the button click. Try the above

Related

Module overwrite previous attached window mouseup event

I am currently working on a javascript module which open and close boxes, tooltip or similar, the function works great the only problem is when I call it twice on a page where the 'boxes' classes are different the window mouseup event will be overwritten and only one of the two module instances of boxes can now be closed after opening them.
var boxRevealer = (function () {
var buttons;
var boxes;
var element;
var drp_active = false;
var boxConstruct = function (btns, bxs) {
buttons = document.querySelectorAll(btns);
boxes = document.querySelectorAll(bxs);
boxEvents();
};
var boxEvents = function () {
buttons.forEach(function (e) {
e.addEventListener("click", function (ee) {
element = document.getElementById(e.getAttribute("data-drp"));
element.classList.toggle("displayn");
drp_active = true;
});
});
window.addEventListener("mouseup", function (e) {
if (drp_active === true) {
if (!e.target.classList.contains("filt_holy")) {
boxes.forEach(function (e) {
console.log("ELEMENT");
console.log(e);
e.classList.add("displayn");
});
}
}
}, false);
};
return {
boxConstruct: boxConstruct,
boxEvents: boxEvents
};
})();
Here is how i call the module
window.addEventListener("load", function(e){
boxRevealer.boxConstruct(".head_drp_btn", ".head_drp");
boxRevealer.boxConstruct(".mkt_drp_btn", ".mkt_drp");
});
So my question is, should I always name the boxes the same, or is there a work around?
Just remove the event before adding it, I think the same event is getting called twice.
So updated code will be as follows:
// Attach an event handler to <div>
e.addEventListener("mousemove", myFunction);
// Remove the event handler from <div>
e.removeEventListener("mousemove", myFunction);
And remove the window event as well before adding it.

Jquery Dailog not returning the user given value for Confirmation PopUp.

Hi I'm using JQUERY Dialog for a confirmation popup. I have a common javascript file, in which i had a function which used to call window.ShowModalDialog. Now from the same function i am calling the jquery dialog, but as it is an asynchronous call, the calling function returns the value(yes/no) without even accepting Values from dialog. How can i return the proper value(yes/no)
If I have correctly understood the problem ...
and if something is wrong, add the example of your code
Try using this pattern:
(function ($, undefined) {
$.fn.dialog = function (options) {
options = $.extend({}, $.fn.dialog.options, options);
return this.each(function () {
var dialog = $(this);
dialog.children(".ok").click(function (e) {
options.ok.call(this, e);
dialog.close();
});
dialog.children(".close").click(function (e) {
options.close.call(this, e);
dialog.close();
});
});
};
$.fn.open = function () {
this.get(0).showModal();
};
$.fn.close = function () {
this.get(0).close();
};
$.fn.dialog.options = {
ok : function () {},
close : function () {}
};
})(jQuery);
and using callback
var dialog = $(".myDialog").dialog({
ok : function () {
alert("ok!!");
}
});
Do everything you need in callback, but avoid callbackhell.
see example

Calling function outside file

im trying to call this function outside JSfile on main js but the console its throwing
Uncaught ReferenceError: Boxlayout is not defined main.js?fc8b2171b5ceebf37d7deb392265939f71c1a998:6(anonymous function)
this is my boxlayout.js
boxlayout.js
Boxlayout = (function () {
var $el = $('#bl-main'),
$sections = $el.children('section'),
// works section
$sectionWork = $('#bl-work-section'),
// work items
$workItems = $('#bl-work-items > li'),
// work panels
$workPanelsContainer = $('#bl-panel-work-items'),
$workPanels = $workPanelsContainer.children('div'),
totalWorkPanels = $workPanels.length,
// navigating the work panels
$nextWorkItem = $workPanelsContainer.find('nav > span.bl-next-work'),
// if currently navigating the work items
isAnimating = false,
// close work panel trigger
$closeWorkItem = $workPanelsContainer.find('nav > span.bl-icon-close'),
transEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'msTransition': 'MSTransitionEnd',
'transition': 'transitionend'
},
// transition end event name
transEndEventName = transEndEventNames[Modernizr.prefixed('transition')],
// support css transitions
supportTransitions = Modernizr.csstransitions;
function init() {
initEvents();
}
function initEvents() {
$sections.each(function () {
var $section = $(this);
// expand the clicked section and scale down the others
$section.on('click', function () {
if (!$section.data('open')) {
$section.data('open', true).addClass('bl-expand bl-expand-top');
$el.addClass('bl-expand-item');
}
}).find('span.bl-icon-close').on('click', function () {
// close the expanded section and scale up the others
$section.data('open', false).removeClass('bl-expand').on(transEndEventName, function (event) {
if (!$(event.target).is('section')) return false;
$(this).off(transEndEventName).removeClass('bl-expand-top');
});
if (!supportTransitions) {
$section.removeClass('bl-expand-top');
}
$el.removeClass('bl-expand-item');
return false;
});
});
// clicking on a work item: the current section scales down and the respective work panel slides up
$workItems.on('click', function (event) {
// scale down main section
$sectionWork.addClass('bl-scale-down');
// show panel for this work item
$workPanelsContainer.addClass('bl-panel-items-show');
var $panel = $workPanelsContainer.find("[data-panel='" + $(this).data('panel') + "']");
currentWorkPanel = $panel.index();
$panel.addClass('bl-show-work');
return false;
});
// navigating the work items: current work panel scales down and the next work panel slides up
$nextWorkItem.on('click', function (event) {
if (isAnimating) {
return false;
}
isAnimating = true;
var $currentPanel = $workPanels.eq(currentWorkPanel);
currentWorkPanel = currentWorkPanel < totalWorkPanels - 1 ? currentWorkPanel + 1 : 0;
var $nextPanel = $workPanels.eq(currentWorkPanel);
$currentPanel.removeClass('bl-show-work').addClass('bl-hide-current-work').on(transEndEventName, function (event) {
if (!$(event.target).is('div')) return false;
$(this).off(transEndEventName).removeClass('bl-hide-current-work');
isAnimating = false;
});
if (!supportTransitions) {
$currentPanel.removeClass('bl-hide-current-work');
isAnimating = false;
}
$nextPanel.addClass('bl-show-work');
return false;
});
// clicking the work panels close button: the current work panel slides down and the section scales up again
$closeWorkItem.on('click', function (event) {
// scale up main section
$sectionWork.removeClass('bl-scale-down');
$workPanelsContainer.removeClass('bl-panel-items-show');
$workPanels.eq(currentWorkPanel).removeClass('bl-show-work');
return false;
});
}
return {
init: init
};
})();
and im trying to init that function with
main.js
Meteor.startup(function(){
Boxlayout.init();
});
this code works outside meteor on other applications also i use the $.(function(){}); from JQuery, but now im working on Meteor this just don't work, i read some documentation and stack overflow questions so i find this and try
Older stack overflow Question
Because your function is wrapped in parenthesis and called immediately with (), you are actually assigning Boxlayout to be the result of an anonymous IIFE (Immediate Invoked Function Expression), but that function does not currently return anything, so Boxlayout is set to undefined (and not the function itself). You first need to return this from the IIFE.
e.g. literally add this code at the end of the function:
return this;
You can structure it as a class instance and sets its init property to a function, within the "constructor" (removed all the rest of your code for clarity):
Boxlayout = (function () {
// Set an init property of this instance to be a function
this.init = function () {
alert("init")
}
// return the instance of this anonymous class
return this;
})();
// Then to use it later
$(function () {
// Call the init method on the specific single instance we created
Boxlayout.init();
});
JSFiddle: http://jsfiddle.net/hzz9jqjc/1/

How to mock/stub callback function with sinon.js?

I want to write unit tests with QUnit and Sinon.Js. I have an application, where the user can click on a button and a modal dialog appers to handle downloading some files. The user can close the dialog and it triggers a method to run to reset some variables. My test code:
$(function() {
$.fn.copy_button = function(){};
ln_download_view = new DownloadModalView();
ln_download_view.modal = {'modal': function() {}};
var download_modal_dialog = $('.download-modal');
download_modal_dialog.modal = function(param){};
var modal_mock = sinon.mock(ln_download_view.modal);
var download_modal_dialog_mock = sinon.mock(download_modal_dialog);
//Should be inserted, because ln_download_view.modal is mocked
//The close button even handler
$('#btn_close_modal').click(function(){
download_modal_dialog.modal('hide');
});
//Dirty stuff to do after the window closes
//Basicly the click triggers this event handler
$('.download-modal').on('hide',function() {
window.clearInterval(window.periodicalTimer);
});
$('div .option-container').click(function() {
if(!$(this).hasClass("selected-option"))
{
$('div #option-presenting').toggleClass("selected-option");
$('div #option-editing-and-presenting').toggleClass("selected-option");
$('.image').toggle();
}
});
module("views");
test("Download modal dialog is displayed", function(){
var modal_triggered = modal_mock.expects("modal").once();
ln_download_view.handleDownloadClick();
ok(modal_triggered.verify());
});
test("Download modal dialog is closed",function(){
var modal_triggered = download_modal_dialog_mock.expects("modal");
$('#btn_close_modal').trigger('click');
ok(modal_triggered.verify());
});
});
What I do not understand is, how can I test/mock/stub this piece of code:
$('.download-modal').on('hide',function() {
window.clearInterval(window.periodicalTimer);
});
I do not have the deep understanding yet.
You can't mock/stub an anonymous function. But you can make a refactoring and stub/mock the named callback.
$('.download-modal').on('hide', onHide);
var onHide = function() {
window.clearInterval(window.periodicalTimer);
};
// ...
sinon.stub(onHide);
Here's my method for this:
In your before each, make a function that doesn't do anything:
var doNothing = function(){};
Then in your test, spy on that:
var spy = sinon.spy(this, 'doNothing');
Then call your method, passing in a callback that fires the doNothing method:
var self = this;
whatever.doSomethingAwesome(
{
finished: function(){
self.doNothing();
}
});
expect(spy.callCount).toEqual(1);

Repetitive javascript call. can not disable

I use a JavaScript function to change the page when a function is clicked. An ajax call is made inside the function.
As the browser is slow. If I click more than one time on the button before the page changes (AJax div load. Page actually not changed), an ajax call is made for each click.
I used the following method to prevent. But even it is called many times. How can I prevent it?
var isClicked = function() {}
isClicked.init = function() {
this.clicked = false;
}
function myAjaxFunction {
//some statements
if(isClicked.clicked == 'undefined')
isClicked.clicked = false;
if(isClicked.clicked)
return false;
isClicked.clicked = true;
// my ajax call here
isClicked.clicked = false;
//some statements
}
var isClicked = false;
function AjaxFunction(){
if(isClicked){
return false;
}
// Set your variable.
isClicked = true;
// Do yourAjaxCall and use isClicked = false in the callback of that function.
}

Categories