Jquery Event onChange for Div - javascript

I have a page with the following two divs:
<div id="searchResults">
</div>
<div class="postSearchOptions" style="display: none;">
</div>
Is there any way that I can make the "postSearchOptions" div appear when the "searchResults" div is updated by an AJAX call? I don't control the AJAX calls and I want to detect any change in the "searchResults" div.
I tried writing the following JQuery code, but then realized that it requires Jquery 1.4 and I only have 1.3:
$("#searchResults").live("change", function() {
$(".postSearchOptions").css("display", "inline");
});
Is there any way to catch the event of the searchResults div changing using either standard JavaScript or Jquery 1.3? Thanks!

If the AJAX calls are made using jQuery, you could call handle the global ajaxComplete event and run your code there.

I don't think the onchange event will fire if you are programatically changing the innerHTML. Why don't you just show the Post Search options upon receiving those change i.e. why don't you include it as the last line in your ajax success method.
HTH

You could use setInterval to watch it, but as others have said it would be nicer to detect the change in the ajax callback. Here's an sketch of what a plugin would look like to "watch" a node, like you're trying to do with live:
jQuery.fn.watch = function() {
this.each(function() {
var original = $(this).html();
setInterval(function() {
var newHtml = $(this).html();
if (newHtml != original) {
$(this).trigger('change');
original = newHtml;
}
}, 500);
} );
}

to working, do....
jQuery.fn.watch = function() {
this.each(function() {
var obj = $(this);
var original = $(this).html();
setInterval(function() {
var newHtml = $(obj).html();
if (newHtml != original) {
$(obj).trigger('change');
original = newHtml;
}
}, 500);
} );
}

Related

How can I observe changes to my DOM and react to them with jQuery?

I have this function where I toggle a class on click, but also append HTML to an element, still based on that click.
The problem is that now, I'm not listening to any DOM changes at all, so, once I do my first click, yup, my content will be added, but if I click once again - the content gets added again, because as far as this instance of jQuery is aware, the element is not there.
Here's my code:
(function($) {
"use strict";
var closePluginsList = $('#go-back-to-setup-all');
var wrapper = $('.dynamic-container');
$('#install-selected-plugins, #go-back-to-setup-all').on('click', function(event) {
$('.setup-theme-container').toggleClass('plugins-list-enabled');
if ( !wrapper.has('.plugins-container') ){
var markup = generate_plugins_list_markup();
wrapper.append(markup);
} else {
$('.plugins-container').hide();
}
});
//Below here, there's a lot of code that gets put into the markup variable. It's just generating the HTML I'm adding.
})(jQuery);
Someone suggested using data attributes, but I've no idea how to make them work in this situation.
Any ideas?
You could just do something like adding a flag and check for it before adding your markup.
var flag = 0;
$('#install-selected-plugins, #go-back-to-setup-all').on('click', function(event) {
$('.setup-theme-container').toggleClass('plugins-list-enabled');
if ( !wrapper.has('.plugins-container') ){
var markup = generate_plugins_list_markup();
if(flag == 0){
wrapper.append(markup);
flag = 1;
}
} else {
$('.plugins-container').hide();
}
});
If you want to add element once only on click then you should make use of .one() and put logic you want to execute once only in that handler.
Example :
$(document).ready(function(){
$("p").one("click", function(){
//this will get execute once only
$(this).animate({fontSize: "+=6px"});
});
$("p").on("click", function(){
//this get execute multiple times
alert('test');
});
});
html
<p>Click any p element to increase its text size. The event will only trigger once for each p element.</p>

how to recall a jquery function after html change

I am trying to figure out why my function stopped working after I changed html code.
I have a div:
<div class="float">
<div class="box" data-speed="3" data-direction="X"><h1>Hola</h1></div>
<div class="box" data-speed="2" data-direction="X"><h1>chau</h1></div>
</div>
And the jquery code :
$(function() {
$('.box').moveIt();
});
//move elements in different speeds
$.fn.moveIt = function () {
var win = $(window);
var it = $(this);
var instances = [];
$(this).each(function (){
instances.push(new moveItItem($(this)));
});
$('.parallax').on('scroll', function() {
instances.forEach(function(inst){
var wrap = inst.el.parents('.float');
var scrol = win.scrollTop()-wrap.offset().top;
inst.update(scrol);
});
});
}
var moveItItem = function(el){
this.el = $(el);
this.speed = parseInt(this.el.attr('data-scroll-speed'));
this.direction = this.el.attr('data-direction');
};
moveItItem.prototype.update = function(scrollTop){
var pos = scrollTop / this.speed;
this.el.css('transform', 'translate'+this.direction+'(' + -pos + 'px)');
};
ok until here everything working, when I scroll the elements .box translate accordingly.
But now I am trying to modify the html in class .float after an ajax call
//after ajax
$.ajax({
url: 'do_content.php'
}).done(function(result) {
//result = <div class="box" data-speed="3" data-direction="X"><h1>Como estas?</h1></div>
$('.float').html(result);
});
After when I fired the scroll again the function appear to look broken and I got this message:
Uncaught TypeError: Cannot read property 'top' of undefined
at http://localhost/ophelia/public/js/control.js?v=1487219951:197:45
at Array.forEach (native)
at HTMLDivElement.<anonymous> (http://localhost/ophelia/public/js/control.js?v=1487219951:195:13)
at HTMLDivElement.dispatch (http://localhost/ophelia/public/utilities/jquery/jquery-3.1.1.min.js:3:10315)
at HTMLDivElement.q.handle (http://localhost/ophelia/public/utilities/jquery/jquery-3.1.1.min.js:3:8342)
I understand that this message appear only if I change the elements with class .box (I tried to change the only the h1 and it doesnt break but I want to change everything to change also the speeds)
How can I re-fire the function?
I tried to call it again with $('.box').moveIt(); but still getting the same error
I know is a long question but didnt find another way to explain my problem
This happens because the html element tied to the listener has been replaced..
Like in this fiddle here.. The alert works but after the html is changed, it doesn't. This is because the old element has been replaced by the new element.
You can use the on function in jQuery to get past this like in this fiddle
As already pointed (but maybe not so clear), the problem is that you attach an event handler using elements existing in the page in a certain moment of time (I think to the instances var). Then you substitute them, but your handler is already set on scroll for element with class .parallax and already registered using that instance of instances and so on.
One way is to rewrite your code using delegate methods.
From http://api.jquery.com/on/
Event handlers are bound only to the currently selected elements; they
must exist at the time your code makes the call to .on().
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time
An event-delegation approach attaches an event handler to only one
element, the tbody, and the event only needs to bubble up one level
(from the clicked tr to tbody):
$( "#dataTable tbody" ).on( "click", "tr", function() {
console.log( $( this ).text() );
});
But It may be complex as you should deeply restructure your code.
Otherwise you could rewrite your function as follows (sorry I can't make fiddles)
$(function() {
$('.parallax').moveIt();
});
//move elements in different speeds
$.fn.moveIt = function () {
var win = $(window);
var it = $(this);
//REMOVED
//var instances = [];
// $(this).each(function (){
// instances.push(new moveItItem($(this)));
// });
$(this).on('scroll', function() {
$('.box').each(function(){
var inst=new moveItItem($(this));
var wrap = inst.el.parents('.float');
var scrol = win.scrollTop()-wrap.offset().top;
inst.update(scrol);
});
});
}
...... and so on
you could bind event on div.float and go through element.children to move every .box

How Store and Disable Event of another element Temporary

I am looking for a way to manage the events. I have a hover function for element A, and click function for element B. I want to disable A`s hover function temporary while the second click of B.
I am looking for a way that not necessary to rewrite the hole function of A inside of B. Something very simply just like "Store and Disable Event, Call Stored Function"
I found some technique like .data('events') and console.log. I tired but failed, or maybe I wrote them in a wrong way.
Please help and advice!
$(A).hover();
$(b).click(
if($.hasData($(A)[0])){ // if A has event,
//STORE all the event A has, and disable
}else{
//ENABLE the stored event for A
}
);
Try this
var hoverme = function() {
alert('Hover Event Fired');
};
$('.A').hover(hoverme);
var i = 0;
$('.B').on('click', function(){
if(i%2 === 0){
// Unbind event
$('.A').off('hover');
}
else{
// Else bind the event
$('.A').hover(hoverme);
}
i++;
});
Check Fiddle
I think that what you want to do is something like this (example for JQuery 1.7.2):
$("#a").hover(function(){alert("test")});
$("#a")[0].active=true;
$("#b").click(function(){
if($("#a")[0].active){
$("#a")[0].storedEvents = [];
var hoverEvents = $("#a").data("events").mouseover;
jQuery.each(hoverEvents , function(key,handlerObj) {
$("#a")[0].storedEvents.push(handlerObj.handler);
});
$("#a").off('hover');
}else{
for(var i=0;i<$("#a")[0].storedEvents.length;i++){
$("#a").hover($("#a")[0].storedEvents[i]);
}
}
$("#a")[0].active = ($("#a")[0].active)==false;
});​
JSFiddle Example
But there are a couple of things that you must have in consideration:
This will only work if you add the events with JQuery, because JQuery keeps an internal track of the event handlers that have been added.
Each version of JQuery handles data("events") differently, that means that this code may not work with other version of JQuery.
I hope that this helps.
EDIT:
data("events") was an internal undocumented data structure used in JQuery 1.6 and JQUery 1.7, but it has been removed in JQuery 1.8. So in JQuery 1.8 the only way to access the events data is through: $._data(element, "events"). But keep in mind the advice from the JQuery documentation: this is not a supported public interface; the actual data structures may change incompatibly from version to version.
You could try having a variable that is outside the scope of functions a and b, and use that variable to trigger the action to take in function b on function a.
var state;
var a = function() {
if(!state) {
state = true;
// Add hover action and other prep. I'd create a third function to handle this.
console.log(state);
};
var b = function() {
if(state) {
state = false;
// Do unbinding of hover code with third function.
} else {
state = true;
// Do whatever else you needed to do
}
}
Without knowing more about what you're trying to do, I'd try something similar to this.
It sounds like you want to disable the click hover event for A if B is clicked.
$("body").on("hover", "#a", function(){
alert("hovering");
});
$("#b").click( function(){
$("body").off("hover", "#a", function() {
alert("removed hovering");
});
});
You can use the jQuery off method, have a look at this fiddle. http://jsfiddle.net/nKLwK/1/
Define a function to assign to hover on A element, so in b click, call unbind('hover') for A element and in second click on b element define again a function to hover, like this:
function aHover(eventObject) {
// Todo when the mouse enter object. You can use $(this) here
}
function aHoverOut(eventObject) {
// Todo when the mouse leave the object. You can use $(this) here
}
$(A).hover(aHover, aHoverOut);
// ...
$(b).click(function(eventObject) {
if($.hasData($(A)[0])){ // if A has event,
$(A).unbind('mouseenter mouseleave'); // This is because not a event hover, jQuery convert the element.hover(hoverIn, hoverOut) in element.bind('mouseenter', hoverIn) and element.bind('mouseleave', hoverOut)
}else{
$(A).hover(aHover, aHoverOut);
}
});
There are provably better ways to do it, but this works fine, on document ready do this:
$("#a")[0].active=false;
$("#b").click(function(){
$("#a")[0].active = ($("#a")[0].active)==false;
if($("#a")[0].active){
$("#a").hover(function(){alert("test")});
}else{
$("#a").off('hover');
}
});
JSFiddle example
You can use .off function from jQuery to unbind the hover on your "a" element.
function hoverA() {
alert('I\'m on hover');
}
$('#a').hover( hoverA );
var active = true;
$('#b').on('click', function(){
if(active){
$('#a').off('hover');
active = false;
} else{
$('#a').hover(hoverA);
active = true;
}
});
Live demo available here : http://codepen.io/joe/pen/wblpC

The relation between .load and .ready

I'm loading a part of a page into another page using the .load function in jQuery
$("#loadingDockShotPg").load("include/shot_comments.php?id="+get['id']);
In my file that's being loaded into the div with the id "loadingDockShotPg" there are elements in there in which I would like to be effected by my jQuery commands.
The HTML that's being placed into another page using .load
<textarea id='newNoteTextarea' class='width100 hidden' placement='Write a comment...'></textarea>
The jQuery that's placed in the parent file that the HTML above is being placed in
$(document).ready(function(){
$("input[placement], textarea[placement]").each(function(){
var orAttr = $(this).attr("placement");
$(this).val(orAttr);
$(this).focus(function(){
if($(this).val() == orAttr)
{
$(this).val("");
}
});
$(this).blur(function(){
if($(this).val() == "")
{
$(this).val(orAttr);
}
});
});
});
The problem is that my textarea isn't being affected by the jQuery that's supposed to put the placement attribute in the textarea's value. What do I have to do in order to have this work?
Your .load() is a "live function". You are adding content to the DOM after it has been loaded. Your .each() function have already been executed before your content is added with the .load(). To fix this you can run your .each() function when .load() is complete as a callback.
This is how I should have done it:
$(function(){
var inputElements = $("input[placement], textarea[placement]");
function setInputValue() {
var self = $(this),
orAttr = self.attr("placement");
self
.val(orAttr)
.focus(function(){
if(self.val() == orAttr)
{
self.val("");
}
})
.blur(function(){
if(self.val() == "")
{
self.val(orAttr);
}
});
}
inputElements.each(setInputValue);
$("#loadingDockShotPg").load("include/shot_comments.php?id="+get['id'], function(){
inputElements = $("input[placement], textarea[placement]");
inputElements.each(setInputValue);
});
});
You may want to look at using .live(), (which is technically depreciated) or .on() to attach/bind to events on selected elements when using .load()
http://api.jquery.com/live/
http://api.jquery.com/on/

Hooking events with .on() with JQUERY

I want to hook events with the .on() method. The problem is I don't know how to get the object reference of the element on which the event take place. Maybe it's a midunderstanding of how the method really works... but I hope you can help.
Here's what I want to do:
When a file is selected, I want the path to be displayed in a div
<div class="wrapper">
<input type="file" class="finput" />
<div class="fpath">No file!</div>
</div>
Here's my script
$(document).ready(function() {
$this = $(this);
$this.on("change", ".finput", {}, function() {
var path = $(this).val()
$(this).parents().children(".fpath").html(path.split("\\").pop());
});
});
Something like that but that way it doesn't work.
Like this
$(document).ready(function() {
$('.finput').on("change", function() {
var path = $(this).val()
$(this).parents().children(".fpath").html(path.split("\\").pop());
});
});
Do you need to use on()? I'm not sure what you are trying to do exactly.
$("#wrapper").on("change", ".finput", function(event){
var path = $(this).val()
$(this).parents().children(".fpath").html(path.split("\\").pop());
});
I haven't tested your code, but you need to attach the on() to the wrapper.
Can you just use change()?
$('.finput').change(function() {
var path = $(this).val()
$(this).parents().children(".fpath").html(path.split("\\").pop());
});
This should help. If you want to see when a file input changes, bind the event to it
$("input[type='file']").on("change", function(e){
var path = $(this).val();
})
Try:
$(document).ready(function() {
$('body').on('change','input.finput', function() {
var path = $(this).val()
$(this).parent().children(".fpath").html(path.split("\\").pop());
});
});
$(document).on("change", ".finput", function() {
$(".fpath").html(this.value.split("\\").pop());
});
This is a delegated event handler, meaning the .finput element has been inserted dynamically so we need to delegate the listening to a parent element.
If the .finput element is not inserted with Ajax and is present on page load, you should use something like this instead:
$(".finput").on("change", function() {
$(".fpath").html(this.value.split("\\").pop());
});

Categories