It is possible to change variable inside function which is based on element is user clicks?
In my case this will fully work for one kind of menu but I need two fully identical menu
with one difference -
second click handler must load toggleDrawer with changed $sidebar to $navbar variable.
/*
Variables
*/
var $sidebar = $('#sidebar'),
$navbar = $('#navbar'),
drawerOpen = false,
/*
Functions
*/
closeDrawer = function() {
drawerOpen = false;
$body.css('overflow','').removeClass('sidebar-open');
$sidebar.removeClass('open');
$sidebar.animate({'right':'-50%'},{duration:300});
$(this).hide();
},
openDrawer = function() {
drawerOpen = true;
$body.addClass('sidebar-open').css('overflow','hidden');
$sidebar.addClass('open');
$sidebar.animate({'right':'0%'},{duration:300});
},
toggleDrawer = function() {
if (drawerOpen) {
closeDrawer();
}else{
openDrawer();
}
},
/*
Bind Events
*/
$document.on('click', '.drawer-toggle-sidebar', function(event){
toggleDrawer();
event.preventDefault();
});
$document.on('click', '.drawer-toggle-navbar', function(event){
toggleDrawer();
event.preventDefault();
});
To elaborate on the above comment, and show an example:
Here are your functions with passing in the element you wish to open/close:
/*
Functions
*/
closeDrawer = function(drawer) {
drawerOpen = false;
$body.css('overflow','').removeClass('sidebar-open');
drawer.removeClass('open');
drawer.animate({'right':'-50%'},{duration:300});
$(this).hide();
},
openDrawer = function(drawer) {
drawerOpen = true;
$body.addClass('sidebar-open').css('overflow','hidden');
drawer.addClass('open');
drawer.animate({'right':'0%'},{duration:300});
},
toggleDrawer = function(drawer) {
if (drawerOpen) {
closeDrawer(drawer);
}else{
openDrawer(drawer);
}
},
And your bind events:
/*
Bind Events
*/
$document.on('click', '.drawer-toggle-sidebar', function(event){
toggleDrawer(event.currentTarget);
event.preventDefault();
});
$document.on('click', '.drawer-toggle-navbar', function(event){
toggleDrawer(event.currentTarget);
event.preventDefault();
});
You could even combine the two on click events into one and just pass in the currentTarget.
I hope this helps.
Related
I am trying to create an event that fires some functions depending on the id of an input[type=radio]. If the Id clicked is different to maybe_evtDiag, it should call this.applySubConditionalRequired(); and this.bindUISubActions();. Why is my code not working?
var SubFormStuff = {
init: function()
this.applySubConditionalRequired();
this.bindUISubActions();
},
bindUISubActions: function() {
// when a radio or checkbox changes value, click or otherwise
$("input[type='radio'].stepThreeDiag").change(function() {
if($(this).attr("id") == "maybe_evtDiag") {
$(this).prop('checked', false);
}else{
//this is not working //
applySubConditionalRequired(this);
displaySubFormRequired(this);
}
});
},
applySubConditionalRequired: function() {
$(".require-if-subevent-active").each(function() {
var el = $(this);
// does something
});
},
displaySubFormRequired: function() {
$(".div-subevent-class").each(function() {
var el = $(this);
// does something else
});
}
};
SubFormStuff.init();
Like you did in the init(), add a reference to the object (this) to call a sibling function (not to lose the context):
bindUISubActions: function() {
var _SubFormStuff = this;
// when a radio or checkbox changes value, click or otherwise
$("input[type='radio'].stepThreeDiag").change(function() {
if($(this).attr("id") == "maybe_evtDiag") {
$(this).prop('checked', false);
} else{
_SubFormStuff.applySubConditionalRequired();
_SubFormStuff.displaySubFormRequired();
}
});
More details on scope and context in JavaScript
You should call the methods like this:
bindUISubActions: function() {
// Store the reference to the current object
var self = this;
// when a radio or checkbox changes value, click or otherwise
$("input[type='radio'].stepThreeDiag").change(function() {
if($(this).attr("id") == "maybe_evtDiag") {
$(this).prop('checked', false);
} else{
self.applySubConditionalRequired();
self.displaySubFormRequired();
}
});
}
This way you can assing to self the current scope, and use it later on any other function call in the same execution scope.
More about javascript scope
You are trying to call applySubConditionalRequired(this) and displaySubFormRequired(this) in the wrong context you should get applySubConditionalRequired and displaySubFormRequired are not defined.
Try this:
bindUISubActions: function() {
// when a radio or checkbox changes value, click or otherwise
var that = this;
$("input[type='radio'].stepThreeDiag").change(function() {
if($(this).attr("id") == "maybe_evtDiag") {
$(this).prop('checked', false);
}else{
//it should work now //
that.applySubConditionalRequired(this);
that.displaySubFormRequired(this);
}
});
},
http://codepen.io/oliecs/pen/womLPJ
var nav = {
init: function () {
console.log('nav init');
$nav = $('nav');
$navIcon = $('.nav-icon');
$navIcon.on('click',function(){
nav.show();
})
},
show: function () {
console.log('nav show');
$nav.addClass('active');
$_DOCUMENT.on('click.navisopen',function(){ //document is a global variable
nav.close();
})
},
close: function () {
console.log('nav close');
$nav.removeClass('active');
$_DOCUMENT.off('.navisopen');
}
};
I feel the pen describes this better than I can. I want to click the nav-icon to open the nav, then any clicks after this will close the nav. However, the close event is fired instantly after the first click, resulting in the nav opening and closing instantly. I don't know how to make this sequential.
Updated js file..Use this code
var ecs= {};
ecs.common = (function($) {
var $_DOCUMENT = $(document),
$_WINDOW = $(window),
$nav = $('nav'),
$navIcon = $('.nav-icon');
var nav = {
init: function () {
console.log('nav init');
$nav = $('nav');
$navIcon = $('.nav-icon');
$navIcon.on('click',function(){
nav.show();
})
},
show: function () {
console.log('nav show');
$nav.addClass('active');
// $_DOCUMENT.on('click.navisopen',function(){
// nav.close();
// })
},
close: function () {
console.log('nav close');
$nav.removeClass('active');
$_DOCUMENT.off('.navisopen');
}
};
//--------------------
// DOM Ready
//--------------------
$(function() {
nav.init();
});
$(document).mouseup(function (e) {
var container = $(".nav-icon");
if (!container.is(e.target) && container.has(e.target).length === 0) {
/* if the target of the click isn't the container && nor a descendant of the container */
$nav.removeClass('active');
}
});
})(jQuery);
You need to
$navIcon.on('click',function(event){
event.stopPropagation();
nav.show();
})
Because the first click is bubbling up the DOM all the way to the document where that event handler is triggered.
I am implementing a JS Event-Disabler class, to disable all Native and Programmable eventlisteners of a certain dom element and all its children.
So far I've been able to disable all JQuery events and the default browser events, but not the eventlisteners set like
document.getElementById('cin').addEventListener("click", function(){
alert('I should not alert when disabled');
});
So clicking on the element ('native element') shouldn't alert, but it does.
How do I stop that from happening, within my nothing function.
If there is away to not even need to call another function but just disable all events then that would also be fine, but need to be able to re-enable all again.
Also, I can assure you that the nothing() function executes first.
var tellme = function(who) {
//console.info('Event by: '+who+' #'+Date.now());
alert('Event by: ' + who + ' #' + Date.now());
}
$(window).load(function() {
/* SOME FUNCTION TO ENSURE OUR FUNCTIONS ARE THE FIRST TO BE CALLED */
$.fn.bindFirst = function(name, fn) {
this.on(name, fn);
this.each(function() {
var handlers = $._data(this, 'events');
for (var key in handlers) {
if (handlers.hasOwnProperty(key)) {
var listeners = handlers[key];
if (listeners.length > 1) {
var lastEvent = listeners.pop();
listeners.splice(0, 0, lastEvent);
if (listeners[1].handler.name === lastEvent.handler.name)
listeners.splice(1, 1);
}
}
}
});
};
function shouldbenothing() {
tellme('native catcher');
nothing();
}
/* THE DO NOTHING FUNCTION, NEEDS SOMETHING MORE, DOESN'T CANCEL ALL*/
function nothing() {
event.cancel = true;
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
//Needed for Jquery
throw new Error("NOT AN ERROR: Just forcefully stopping further events #" /*+Date.now()*/ ); //Add the Date.now to see that this code does run before the native function.
return false;
}
/* THIS WILL ONLY RETURN NON-NATIVE EVENTS, ONLY PROGRAMMED EVENTS*/
function getAllActiveEvents(element) {
var result = [];
var handlers = $._data(element, 'events');
for (var key in handlers) {
if (handlers.hasOwnProperty(key)) {
result.push(key);
}
}
return result.join(' ');
}
function getAllEvents(element) {
var result = [];
for (var key in element) {
if (key.indexOf('on') === 0) {
result.push(key.slice(2));
}
}
return result.join(' ');
}
/*SOME PROGRAMMED EVENTS, BESIDES THE NATIVE ONES*/
$('input').on('keyup', function() {
$('#text').html(this.value);
});
$('p').on('click', function() {
$('#text').html(this.innerHTML);
tellme('jquery');
});
document.getElementById('jsE').addEventListener("click", function() {
tellme('p:js');
});
document.getElementById('cin').addEventListener("click", function() {
tellme('input:js');
});
/* THE ACTUAL DISABLER CODE */
/*TOGGLE TO ACTIVE OR DISABLE EVENTS FROM TAKING PLACE NATIVE AND EXTRA*/
var isOn = false;
$('button').on('click', function() {
if (isOn)
$("#obj *").each(function() {
$(this).off(getAllEvents($(this)[0]), "", nothing);
$("#obj").css('pointerEvents','');
});
else {
$("#obj *").each(function() {
var elem = $(this)[0];
var events1 = getAllActiveEvents(elem); //Only programmed listeners
var events2 = getAllEvents(elem); //Native + other listeners
$(this).bindFirst(events2, nothing);
});
$("#obj").css('pointerEvents','none');
}
isOn = !isOn;
this.innerHTML = isOn;
});
});
p {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<style>p {pointer:hand;}</style>
<div id="obj">
<p>jquery event</p>
<p id="jsE">js event</p>
<p onclick="tellme('native');">native event</p>
<input id='cin' type="text" />
<p id="text">3</p>
</div>
<p>not catched</p>
<input type="text">
<button>toggle</button>
There might be a very simple, non-js, pure css-solution ... like this:
.whatever {
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
pointer-events:none;
}
... just add the whatever-class to any elements you want to disable completely from user-interaction.
So I found a solution shortly after.
By playing with the css code, I could disable all the relevant mouse events. This however doesn't stop the native events, say if you were to trigger the event via JS, but at least it stops it from user's point.
I actually also like the css method better, as it does allow me to still interact and trigger events, for instance when I want to show the user something without having the user interfere.
The css code:
//To Disable
$("#obj").css('pointerEvents','none');
//To Enable
$("#obj").css('pointerEvents','');
For anyone looking for the full Working Code: Here it is.
Make sure you add the css.
/* Event Disabler, disables all events */
/* How to use:
* Toggle Events: toggleEvents(selector);
* Disable all Events: toggleEvents('body',true);
* Enable all Events: toggleEvents('body',false);
*/
var toggleEvents = null;
$(window).load(function(){
/* SOME FUNCTION TO ENSURE OUR FUNCTIONS ARE THE FIRST TO BE CALLED */
$.fn.bindFirst = function(name, fn) {
this.on(name, fn);
this.each(function() {
var handlers = $._data(this, 'events');
for (var key in handlers) {
if (handlers.hasOwnProperty(key)) {
var listners = handlers[key];
if (listners.length > 1) {
var lastEvent = listners.pop();
listners.splice(0, 0, lastEvent);
//Removes duplicate eventListners
if (listners[1].handler.name === lastEvent.handler.name)
listners.splice(1, 1);
}
}
}
});
};
/* THE DO NOTHING FUNTION CANCELS ALL EVENTS, EVEN BY TRIGGERED*/
function nothing() {
event.cancel = true;
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
event.bubbles = false;
if(window.event){
window.event.cancelBubble=true;
}
//throw new Error("NOT AN ERROR: Forcefully stopping further events");
return false;
}
function getAllActiveEvents(element) {
var result = [];
var handlers = $._data(element, 'events');
for (var key in handlers) {
if (handlers.hasOwnProperty(key)) {
result.push(key);
}
}
return result.join(' ');
}
function getAllEvents(element) {
var result = [];
for (var key in element) {
if (key.indexOf('on') === 0) {
result.push(key.slice(2));
}
}
return result.join(' ');
}
var enabled = false;
toggleEvents = function(selector,flag) {
enabled = flag === undefined ? !enabled : flag;
if (enabled) {
$(selector+" *").each(function(){
//Only programmed and attached listners
var events1 = getAllActiveEvents($(this)[0]);
//All Native events attached or not
var events2 = getAllEvents($(this)[0]);
$(this).bindFirst(events2, nothing );
});
//Disabled most user pointer events
$(selector).addClass('eventsDisabled');
} else {
$(selector+" *").each(function() {
$(this).off(getAllEvents($(this)[0]), "", nothing );
});
$(selector).removeClass('eventsDisabled');
}
};
});
.eventsDisabled {
-webkit-user-select:none !important;
-moz-user-select:none !important;
-ms-user-select:none !important;
user-select:none !important;
pointer-events:none !important;
}
i have a little problem with vars on event. So i have a plugin whitch called another plugin and i want to get a jquery element from called plugin to main plugin... like this.
(function($) {
$.fn.meRadioCheck = function(options, callback) {
options = $.extend($.fn.meRadioCheck.defaults, options);
var plugin = this;
plugin.init = function() {
return this.each(function() {
var $this = $(this);
var $span = $('<span/>');
var name = $this.attr('name');
/* here some stuff... */
/* check for Events */
if (($._data(this, "events") == null)) {
/* Change Event an Element binden */
$this.bind("xonChange", function() {
options.CheckBox_onChange.call($this)
});
$this.on({
change: function() {
/* here some stuff... */
/* throw Change Event */
$this.trigger("xonChange");
},
});
};
});
}
return this.each(function() {
var $this = $(this);
var name = $this.attr('name');
if (options.checked != $this.prop('checked')) { $this.click(); }
if (options.disabled) { $this.prop('disabled', true) } else { $this.prop('disabled', false) }
});
};
// Standard-Optionen für das Plugin
$.fn.meRadioCheck.defaults = {
'checked': false, /* This Checkbox or Radio Button is checked */
'debug': false, /* Debug Modus für das Plugin ein od. ausschalten */
'disabled': false, /* This Checkbox or Radio Button is disabled */
'CheckBox_onChange': function(el) {},
'RadioButton_onChange': function(el) {}
}
})(jQuery);
(function($) {
$.panel = function(options, callback) {
$('input[type=checkbox], input[type=radio]').meRadioCheck({
CheckBox_onChange: function(el) {
/* some stuff here... */
window.console.debug('panel: ' + typeof(el) + ', onChange: ', [el])
}
});
}
})(jQuery);
i only get this in the console: panel: undefined, onChange: [undefined]
but i want to get the CheckBox or RadioButton. I hope someone can help me...
Thanks... and have a nice Weekend.
How about:
(function($) {
$.fn.meRadioCheck.defaults = {
'debug': false, /* debug-mode for plugin */
'checked': false, /* this checkbox or radio button is checked */
'disabled': false, /* this checkbox or radio button is disabled */
'CheckBox_onChange': null,
'RadioButton_onChange': null
};
$.fn.meRadioCheck = function(overrideOptions, callback) {
var plugin = this,
options = $.extend($.fn.meRadioCheck.defaults, overrideOptions);
return this.each(function() {
var $this = $(this),
name = $this.attr('name');
if ( !$this.data().meRadioCheckInitDone ) {
$this.on("change", function() {
if (typeof options.CheckBox_onChange === "function") {
options.CheckBox_onChange.call(this);
}
}).data("meRadioCheckInitDone", true);
}
$this.prop('checked', !!options.checked);
$this.prop('disabled', !!options.disabled);
});
};
})(jQuery);
Changes
Gotten rid of .init(), it did not seem to serve any purpose.
Used a .data() variable instead of calling an internal API function to check if initialization is through. Seems cleaner.
Gotten rid of the custom xonChange event - listening to change directly will work just as well if all you do is call another function from there.
Added a typeof check for the event callback.
Setting $this.prop() unconditionally seems cleaner than the if-then-else you do.
On a more general note, you seem to implement some sort of data binding. Maybe looking into a data binding framework like knockout.js is worth it.
I'm new to javascript so i'm not exactly sure how I can do this. Basically, in my website I have a kind of tooltip, that displays when hovering over certain input boxes.
This is my javascript:
function showTip () {
firstnameTip.style.display = "inline";
}
function hideTip () {
firstnameTip.style.display = "none";
}
/* link HTML elements to corresponding event function */
function init () {
/* link the variables to the HTML elements */
firstnameTip = document.getElementById("firstnameTip");
firstname = document.getElementById("firstname");
/* assigns functions to corresponding events */
firstname.onmouseover = showTip; /* for mouse */
firstname.onmouseout = hideTip;
firstname.onfocus = showTip; /* for cursor on input field */
firstname.onblur = hideTip; /* for cursor moving out */
}
/* execute the initialisation function once the window*/
window.onload = init;
Basically the functionality i would like is to if i hover over "firstname", it displays the firstnameTip, and so on for other things like lastname (lastnameTip), etc.
Simple question but I've tried many things and can't figure it out. Anyone have any ideas? Thanks.
Here's how I'd set it up:
function showTip (tipElement) {
return function () {
tipElement.style.display = "inline";
};
}
function hideTip (element, tipElement) {
return function () {
if (document.activeElement !== element) {
tipElement.style.display = "none";
}
};
}
function init() {
initTipEvents("firstname", "firstnameTip");
initTipEvents("lastname", "lastnameTip");
}
function initTipEvents(elementId, tipId) {
var el = document.getElementById(elementId),
tip = document.getElementById(tipId),
showHandler = showTip(tip),
hideHandler = hideTip(el, tip);
el.onmouseover = showHandler;
el.onfocus = showHandler;
el.onmouseout = hideHandler;
el.onblur = hideHandler;
}
window.onload = init;
DEMO: http://jsfiddle.net/LX2Cb/
The initTipEvents binds all necessary events, based on an element's id and its tip's id, reusing the modified showTip and hideTip functions. I added an extra check to the hideTip function to make sure that the tip isn't hidden when the mouse leaves the input, yet its still focused.
And whats the problem? Works like a charm:
var firstnameTip;
var firstname;
function showTip () {
firstnameTip.style.display = "inline";
}
function hideTip () {
firstnameTip.style.display = "none";
}
/* link HTML elements to corresponding event function */
function init () {
/* link the variables to the HTML elements */
firstnameTip = document.getElementById("firstnameTip");
firstname = document.getElementById("firstname");
/* assigns functions to corresponding events */
firstname.onmouseover = showTip; /* for mouse */
firstname.onmouseout = hideTip;
firstname.onfocus = showTip; /* for cursor on input field */
firstname.onblur = hideTip; /* for cursor moving out */
}
/* execute the initialisation function once the window*/
init();
http://jsfiddle.net/6QvXT/
ok, to have that more generic, you should use the event parameter passed to the handler and the retrieve the target object out of that like:
var getTarget = function (event)
{
var ttn = null;
if (!event)
event = window.event;
else if (event.target)
ttn = event.target;
else if (event.srcElement)
ttn = event.srcElement;
var tipId = ttn.id + "Tip";
ttn = document.getElementById(tipId);
return ttn;
}
and then:
function showTip (evt) {
var ttn = getTarget(evt);
ttn.style.display = "inline";
}
function hideTip (evt) {
var ttn = getTarget(evt);
ttn.style.display = "none";
}
furthermore:
function init () {
/* for all relevant elements */
for ( .... ) // iterate through a list or the dom
{
var theElement = ....(); // get the element
/* assigns functions to corresponding events */
theElement.onmouseover = showTip; /* for mouse */
theElement.onmouseout = hideTip;
theElement.onfocus = showTip; /* for cursor on input field */
theElement.onblur = hideTip; /* for cursor moving out */
}
}
/* execute the initialisation function once the window*/
init();
hope that helps.