In jQuery unable to unbind an added function - javascript

I'm trying to add a function to an element. Later I'm trying to remove that function. It's not working in jQuery.
var myFunction=function(element){
$(element).animate({
/* Some Code in here */
});
myFunction(element); // I want in a loop
}
/* No issues with the function */
/* binding this function in another place */
$(otherElement).on('focus', myFunction);
/* In another location I want to off the focus on the element */
$(otherElement).on('focus'); --> This is not working. My expectation is the animation to be stopped.
I have tried with live/die and bind/unbind too, but no luck.

Wow, it's just an argument error.
var myFunction=function(element){ ---> you just expect an dom element as argument. But $(otherElement).on('focus', myFunction);, what is passed to myFunction is a jQuery Event object, not dom element.
So, try this:
$(otherElement).on('focus', function(ev/*this is event, not element*/) {
myFunction(this);
});
And if you want to unbind event, just use $(otherElement).off('focus');

Try
var myFunction = function(element) {
var $element = $(element).animate({
height: 'toggle'
}, {
done: function() {
var flag = $element.data('stopAnimation');
if (flag) {
$element.removeData('stopAnimation');
return;
}
myFunction(element);
}
});
// I want in a loop
}
$('#otherElement').on('focus', function() {
myFunction($('#element'))
});
$('#otherElement').on('blur', function() {
$('#element').stop(true, true).data('stopAnimation', true);
});
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js"></script>
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/redmond/jquery-ui.css">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.js"></script>
<input id="otherElement" />
<div id="element">element</div>
Note: I don't know whether it is the optimal solution

Related

jQuery smooth scroll

I'm in a bit of a bind. I've been searching for a way to scroll smoothly through divs and found this fiddle:
http://jsfiddle.net/Vk7gB/187/
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://trevordavis.net/play/jquery-one-page-nav/jquery.scrollTo.js"></script>
<script type="text/javascript" src="http://trevordavis.net/play/jquery-one-page-nav/jquery.nav.min.js"></script>
<script type="text/javascript" src="http://mottie.github.io/Keyboard/js/jquery.mousewheel.js"></script>
<script type="text/javascript" src="scroll.js"></script>
The problem is that, while it works perfectly on the jsfiddle site, when i copy it exactly the same, without any changes, it stops working for some reason.
I've triple checked all external scripts and yet I can't find out what is the problem.
Here's the exact same code, copied directly from the fiddle and it does not work.
http://www.zero-blade.com/work/test2/
If anyone can point me in the right direction, I would greatly appreciate it.
Because in jsFiddle, the code runs inside the DOMReady event (look at the drop down under the jQuery version in the fiddle).
Wrap all your code inside
$(function(){
// you code here
});
You refer in your code to DOM elements, but they are not ready yet. Put all your <script> tags just before closing </body> tag.
The JavaScript in the fiddle is configured to execute when the DOM is ready. The JavaScript in your site (scroll.js) is being inserted and executed in the HEAD of your document, before the DOM elements exist, so no bindings are occurring.
All of your JavaScript should be at the end of the body, and moving scroll.js to the end of the body will solve the issue.
If you can't move the link to scroll.js, you can use jQuery's document.ready() in scroll.js to trigger the bindings to occur AFTER the DOM is ready, as follows:
scroll.js
var $current, flag = false;
$(function() {
// This code will be executed when the DOM is ready.
// This is a short version of $(document).ready(){...}
$('#nav').onePageNav();
$('body').mousewheel(function(event, delta) {
if (flag) { return false; }
$current = $('div.current');
if (delta > 0) {
$prev = $current.prev();
if ($prev.length) {
flag = true;
$('body').scrollTo($prev, 1000, {
onAfter : function(){
flag = false;
}
});
$current.removeClass('current');
$prev.addClass('current');
}
} else {
$next = $current.next();
if ($next.length) {
flag = true;
$('body').scrollTo($next, 1000, {
onAfter : function(){
flag = false;
}
});
$current.removeClass('current');
$next.addClass('current');
}
}
event.preventDefault();
});
});

defining callback functions in javascript for all event types

Developing page to test how events are fire in a browser. I am trying to create a script that logs event types as the happen on a target div regardless of the event type.
To do this I have written code that first finds all event types supported by the window. This is based on code found here.
It then tries to attach all of these events to the target div. here named 'testbed'
As console.log(i) counts all the way to zero I presume that the handles are all successfully added.
Therefore I assume that I have not worked out the best way to add function callback
When I load this page in Google chrome I see a large red div.
The console correctly displays first a list of events including 'onclick'
The console the counts from 70 to 0 indicating 70 events added.
It finally declares all events added.
When I click on the div nothing further is registered in the console.
So the question is, if the function logType is passed to setEventListeners which in turn hands it to the individual addEventListener and this is applied to every event type why does clicking on the div in question not cause any log to the console?
complete code below
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#testbed {
width: 100%;
height: 200px;
background: red;
}
</style>
</head>
<body>
<div id='testbed'>
</div>
<script>
var myApp = {
init: function () {
this.getSupportedOccurances(window);
var testbed = document.getElementById('testbed');
this.setEventListeners(testbed, this.occurances, this.logType);
},
occurances: [],
getSupportedOccurances: function (target) {
var i = '', occurances = this.occurances;
for (i in target) {
if ( /^on/.test(i)) { occurances[occurances.length] = i; }
}
console.log(occurances);
},
setEventListeners: function(target, eventList, callback) {
var i = eventList.length-1;
if (i > -1) {
console.log('adding');
do {
console.log(i);
target.addEventListener(eventList[i], callback);
}
while (--i >=0);
}
console.log('Event Listeners added');
},
logType: function (event) {
console.log(event.type);
}
}
myApp.init();
</script>
</body>
When using addEventListener you must remove the on prefix from the event name.
You can do this with:
occurances[occurances.length] = i.substring(2);
See http://jsfiddle.net/alnitak/3u6eQ/

Best jQuery plugin implementation for binding JavaScript's oninput event

I know jQuery doesn't support the oninput event, so have myself started to write a plugin to do the job. Although don't understanding very well all the stuff related to events in jQuery or JavaScript I ended up with usable code that currently satisfies my requirements.
Unfortunately I think my current implementation can crash, specially when using it in conjunction with other libraries because am setting directly the oninput member of the DOM elements.
Do you know a better and portable way to solve this problem, maybe using methods such as jQuery's "on" or JavaScript "addEventListener"?
Here is a working example of the code i'm currently using:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script type="text/javascript">
////////////////////////////////////////////////////////////////////////////
// jQuery plugin to bind an event handler to the "oninput" JavaScript event.
(function ($) {
// Add an "input" method to all jQuery objects
$.fn.input = function (handler) {
// iterate over all DOM elements in the jQuery object
this.each( function () {
// set a new method to run when "oninput" is fired
this.oninput = function (prevHandler) {
return function (ev) {
// call previous handler if exists
if( typeof prevHandler === 'function' ) {
prevHandler.call (this, ev);
}
// call new handler
handler.call (this, ev);
};
}(this.oninput); // immediate evaluation, pass current handler as argument
});
};
} (jQuery));
////////////////////////////////////////////////////////////////////////////
</script>
<script type="text/javascript">
// Test the plugin
$(document).ready (function () {
$('#one').input (function () {
alert ('Input on one: ' + $(this).val());
});
$('#three,#four').input (function () {
alert ('Input on three or four: ' + $(this).val());
});
$('#one,#two,#three').input (function () {
alert ('Input on one, two, or three: ' + $(this).val());
});
$('#one,#two,#three,#four').input (function () {
alert ('Input on any: ' + $(this).val());
});
});
</script>
</head>
<body>
<input id='one'/><br/>
<input id='two'/><br/>
<input id='three'/><br/>
<input id='four'/><br/>
</body>
</html>
Thanks in advance!!
jQuery's 'on' can handle any event so you could simply do something like this:
(function() {
var outputElement = document.getElementById('mirror-input');
$('#input-stuff').on('input', function (event) {
outputElement.innerText = event.target.value;
});
}())
http://jsfiddle.net/YCAtZ/

Detaching and AppendingTo on Window Resize

So I am trying to detach and appendTo a div based on window size. The following is what I currently have.
I am creating a function with a variable SOCIALBAR assigning it equal to #SOCIALMEDIA and detaching it. Then based on window size for (document).ready and (window).resize, I call the SOCIALBARPlACEMENT function and #SOCIALMEDIA is either appendeto the #TOP or #LEFT divs.
This works fine and dandy on (document).ready but does not work for (window).resize.
In fact, if I remove document.ready, and leave window.resize, the function still runs on page load, but doesn't work on page resize.
Any thoughts would be appreciated. Thank!
function socialbarplacement() {
var socialbar;
socialbar = $("#socialmedia").detach();
if (jQuery(window).width() < 1384) {
socialbar.appendTo("#top");
} else {
socialbar.appendTo("#left");
}
};
$(document).ready(socialbarplacement());
$(window).resize(socialbarplacement());
You are calling the functions immediately rather than passing them as event handlers, try:
$(document).ready(socialbarplacement);
$(window).resize(socialbarplacement);
/*
someFunction() <-- invokes the function and resolves to the returned value
someFunction <-- resolves to the function reference
*/
I would probably do something along these line (untested code):
$(window).resize( function(){
var wnd = $(window), soc = $('#socialmedia');
return function(){
// might add a check to make sure you are not appending to the current parent.
soc.appendTo( $(window).width() > 1384 ? '#left' : '#top');
}
});
Resize will get fired when the page loads so you don't need to have both on ready and resize.
Also looking at it, you are executing the method when you really should be passing it in by name.
I,ve try like this... Enjoy!
$(function () {
if (matchMedia) {
var mq = window.matchMedia('(max-width: 1384px)');
var socialmedia = $("#socialmedia");
mq.addListener(WidthChange);
WidthChange(mq);
}
function WidthChange(mq) {
if (mq.matches && socialmedia) {
socialmedia.appendTo("#top");
socialmedia = null;
} else {
socialmedia = $("#socialmedia").detach();
socialmedia.appendTo("#left");
}
};
});
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Untitled Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
<div id="top">
<div id="socialmedia">SOCIALMEDIA</div> <br>
**TOP**
</div>
<div id="left">
<br>
**LEFT**
</div>
</body>
</html>

jQuery event to trigger action when a div is made visible

I'm using jQuery in my site and I would like to trigger certain actions when a certain div is made visible.
Is it possible to attach some sort of "isvisible" event handler to arbitrary divs and have certain code run when they the div is made visible?
I would like something like the following pseudocode:
$(function() {
$('#contentDiv').isvisible(function() {
alert("do something");
});
});
The alert("do something") code should not fire until the contentDiv is actually made visible.
Thanks.
You could always add to the original .show() method so you don't have to trigger events every time you show something or if you need it to work with legacy code:
Jquery extension:
jQuery(function($) {
var _oldShow = $.fn.show;
$.fn.show = function(speed, oldCallback) {
return $(this).each(function() {
var obj = $(this),
newCallback = function() {
if ($.isFunction(oldCallback)) {
oldCallback.apply(obj);
}
obj.trigger('afterShow');
};
// you can trigger a before show if you want
obj.trigger('beforeShow');
// now use the old function to show the element passing the new callback
_oldShow.apply(obj, [speed, newCallback]);
});
}
});
Usage example:
jQuery(function($) {
$('#test')
.bind('beforeShow', function() {
alert('beforeShow');
})
.bind('afterShow', function() {
alert('afterShow');
})
.show(1000, function() {
alert('in show callback');
})
.show();
});
This effectively lets you do something beforeShow and afterShow while still executing the normal behavior of the original .show() method.
You could also create another method so you don't have to override the original .show() method.
The problem is being addressed by DOM mutation observers. They allow you to bind an observer (a function) to events of changing content, text or attributes of dom elements.
With the release of IE11, all major browsers support this feature, check http://caniuse.com/mutationobserver
The example code is a follows:
$(function() {
$('#show').click(function() {
$('#testdiv').show();
});
var observer = new MutationObserver(function(mutations) {
alert('Attributes changed!');
});
var target = document.querySelector('#testdiv');
observer.observe(target, {
attributes: true
});
});
<div id="testdiv" style="display:none;">hidden</div>
<button id="show">Show hidden div</button>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
There is no native event you can hook into for this however you can trigger an event from your script after you have made the div visible using the .trigger function
e.g
//declare event to run when div is visible
function isVisible(){
//do something
}
//hookup the event
$('#someDivId').bind('isVisible', isVisible);
//show div and trigger custom event in callback when div is visible
$('#someDivId').show('slow', function(){
$(this).trigger('isVisible');
});
You can use jQuery's Live Query plugin.
And write code as follows:
$('#contentDiv:visible').livequery(function() {
alert("do something");
});
Then everytime the contentDiv is visible, "do something" will be alerted!
redsquare's solution is the right answer.
But as an IN-THEORY solution you can write a function which is selecting the elements classed by .visibilityCheck (not all visible elements) and check their visibility property value; if true then do something.
Afterward, the function should be performed periodically using the setInterval() function. You can stop the timer using the clearInterval() upon successful call-out.
Here's an example:
function foo() {
$('.visibilityCheck').each(function() {
if ($(this).is(':visible')){
// do something
}
});
}
window.setInterval(foo, 100);
You can also perform some performance improvements on it, however, the solution is basically absurd to be used in action. So...
The following code (pulled from http://maximeparmentier.com/2012/11/06/bind-show-hide-events-with-jquery/) will enable you to use $('#someDiv').on('show', someFunc);.
(function ($) {
$.each(['show', 'hide'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
this.trigger(ev);
return el.apply(this, arguments);
};
});
})(jQuery);
If you want to trigger the event on all elements (and child elements) that are actually made visible, by $.show, toggle, toggleClass, addClass, or removeClass:
$.each(["show", "toggle", "toggleClass", "addClass", "removeClass"], function(){
var _oldFn = $.fn[this];
$.fn[this] = function(){
var hidden = this.find(":hidden").add(this.filter(":hidden"));
var result = _oldFn.apply(this, arguments);
hidden.filter(":visible").each(function(){
$(this).triggerHandler("show"); //No bubbling
});
return result;
}
});
And now your element:
$("#myLazyUl").bind("show", function(){
alert(this);
});
You could add overrides to additional jQuery functions by adding them to the array at the top (like "attr")
a hide/show event trigger based on Glenns ideea:
removed toggle because it fires show/hide and we don't want 2fires for one event
$(function(){
$.each(["show","hide", "toggleClass", "addClass", "removeClass"], function(){
var _oldFn = $.fn[this];
$.fn[this] = function(){
var hidden = this.find(":hidden").add(this.filter(":hidden"));
var visible = this.find(":visible").add(this.filter(":visible"));
var result = _oldFn.apply(this, arguments);
hidden.filter(":visible").each(function(){
$(this).triggerHandler("show");
});
visible.filter(":hidden").each(function(){
$(this).triggerHandler("hide");
});
return result;
}
});
});
I had this same problem and created a jQuery plugin to solve it for our site.
https://github.com/shaunbowe/jquery.visibilityChanged
Here is how you would use it based on your example:
$('#contentDiv').visibilityChanged(function(element, visible) {
alert("do something");
});
What helped me here is recent ResizeObserver spec polyfill:
const divEl = $('#section60');
const ro = new ResizeObserver(() => {
if (divEl.is(':visible')) {
console.log("it's visible now!");
}
});
ro.observe(divEl[0]);
Note that it's crossbrowser and performant (no polling).
Just bind a trigger with the selector and put the code into the trigger event:
jQuery(function() {
jQuery("#contentDiv:hidden").show().trigger('show');
jQuery('#contentDiv').on('show', function() {
console.log('#contentDiv is now visible');
// your code here
});
});
Use jQuery Waypoints :
$('#contentDiv').waypoint(function() {
alert('do something');
});
Other examples on the site of jQuery Waypoints.
I did a simple setinterval function to achieve this. If element with class div1 is visible, it sets div2 to be visible. I know not a good method, but a simple fix.
setInterval(function(){
if($('.div1').is(':visible')){
$('.div2').show();
}
else {
$('.div2').hide();
}
}, 100);
You can also try jQuery appear plugin as mentioned in parallel thread https://stackoverflow.com/a/3535028/741782
This support easing and trigger event after animation done! [tested on jQuery 2.2.4]
(function ($) {
$.each(['show', 'hide', 'fadeOut', 'fadeIn'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
var result = el.apply(this, arguments);
var _self=this;
result.promise().done(function () {
_self.triggerHandler(ev, [result]);
//console.log(_self);
});
return result;
};
});
})(jQuery);
Inspired By http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element/
There is a jQuery plugin available for watching change in DOM attributes,
https://github.com/darcyclarke/jQuery-Watch-Plugin
The plugin wraps All you need do is bind MutationObserver
You can then use it to watch the div using:
$("#selector").watch('css', function() {
console.log("Visibility: " + this.style.display == 'none'?'hidden':'shown'));
//or any random events
});
Hope this will do the job in simplest manner:
$("#myID").on('show').trigger('displayShow');
$('#myID').off('displayShow').on('displayShow', function(e) {
console.log('This event will be triggered when myID will be visible');
});
I changed the hide/show event trigger from Catalint based on Glenns idea.
My problem was that I have a modular application. I change between modules showing and hiding divs parents. Then when I hide a module and show another one, with his method I have a visible delay when I change between modules. I only need sometimes to liten this event, and in some special childs. So I decided to notify only the childs with the class "displayObserver"
$.each(["show", "hide", "toggleClass", "addClass", "removeClass"], function () {
var _oldFn = $.fn[this];
$.fn[this] = function () {
var hidden = this.find(".displayObserver:hidden").add(this.filter(":hidden"));
var visible = this.find(".displayObserver:visible").add(this.filter(":visible"));
var result = _oldFn.apply(this, arguments);
hidden.filter(":visible").each(function () {
$(this).triggerHandler("show");
});
visible.filter(":hidden").each(function () {
$(this).triggerHandler("hide");
});
return result;
}
});
Then when a child wants to listen for "show" or "hide" event I have to add him the class "displayObserver", and when It does not want to continue listen it, I remove him the class
bindDisplayEvent: function () {
$("#child1").addClass("displayObserver");
$("#child1").off("show", this.onParentShow);
$("#child1").on("show", this.onParentShow);
},
bindDisplayEvent: function () {
$("#child1").removeClass("displayObserver");
$("#child1").off("show", this.onParentShow);
},
I wish help
One way to do this.
Works only on visibility changes that are made by css class change, but can be extended to watch for attribute changes too.
var observer = new MutationObserver(function(mutations) {
var clone = $(mutations[0].target).clone();
clone.removeClass();
for(var i = 0; i < mutations.length; i++){
clone.addClass(mutations[i].oldValue);
}
$(document.body).append(clone);
var cloneVisibility = $(clone).is(":visible");
$(clone).remove();
if (cloneVisibility != $(mutations[0].target).is(":visible")){
var visibilityChangedEvent = document.createEvent('Event');
visibilityChangedEvent.initEvent('visibilityChanged', true, true);
mutations[0].target.dispatchEvent(visibilityChangedEvent);
}
});
var targets = $('.ui-collapsible-content');
$.each(targets, function(i,target){
target.addEventListener('visibilityChanged',VisbilityChanedEventHandler});
target.addEventListener('DOMNodeRemovedFromDocument',VisbilityChanedEventHandler });
observer.observe(target, { attributes: true, attributeFilter : ['class'], childList: false, attributeOldValue: true });
});
function VisbilityChanedEventHandler(e){console.log('Kaboom babe'); console.log(e.target); }
my solution:
; (function ($) {
$.each([ "toggle", "show", "hide" ], function( i, name ) {
var cssFn = $.fn[ name ];
$.fn[ name ] = function( speed, easing, callback ) {
if(speed == null || typeof speed === "boolean"){
var ret=cssFn.apply( this, arguments )
$.fn.triggerVisibleEvent.apply(this,arguments)
return ret
}else{
var that=this
var new_callback=function(){
callback.call(this)
$.fn.triggerVisibleEvent.apply(that,arguments)
}
var ret=this.animate( genFx( name, true ), speed, easing, new_callback )
return ret
}
};
});
$.fn.triggerVisibleEvent=function(){
this.each(function(){
if($(this).is(':visible')){
$(this).trigger('visible')
$(this).find('[data-trigger-visible-event]').triggerVisibleEvent()
}
})
}
})(jQuery);
example usage:
if(!$info_center.is(':visible')){
$info_center.attr('data-trigger-visible-event','true').one('visible',processMoreLessButton)
}else{
processMoreLessButton()
}
function processMoreLessButton(){
//some logic
}
$( window ).scroll(function(e,i) {
win_top = $( window ).scrollTop();
win_bottom = $( window ).height() + win_top;
//console.log( win_top,win_bottom );
$('.onvisible').each(function()
{
t = $(this).offset().top;
b = t + $(this).height();
if( t > win_top && b < win_bottom )
alert("do something");
});
});
$(function() {
$(document).click(function (){
if ($('#contentDiv').is(':visible')) {
alert("Visible");
} else {
alert("Hidden");
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="contentDiv">Test I'm here</div>
<button onclick="$('#contentDiv').toggle();">Toggle the div</button>
<div id="welcometo">Özhan</div>
<input type="button" name="ooo"
onclick="JavaScript:
if(document.all.welcometo.style.display=='none') {
document.all.welcometo.style.display='';
} else {
document.all.welcometo.style.display='none';
}">
This code auto control not required query visible or unvisible control

Categories

Resources