.on("DOMNodeInserted", function(e){, e.currentTarget is always #document - javascript

I'm in the process of updating a 2-year old application and part of that application has the following:
function setupListener(currentXmlHttpRequests){
debugger;
$(document).unbind("DOMNodeInserted");
$(document).bind("DOMNodeInserted", function(e){
debugger;
console.log(e.currentTarget.id);
if(e.target.id=="page-bottom"){
refreshFilterList("Last 6 Months Of Launches");
refreshQuickJump(filtered);
$("#mySelect").on('change', function() {
var val = this.value;
if(val == "")
return;
document.getElementById(val).scrollIntoView();
var element = document.getElementById('mySelect');
element.value = "";
});
$("#datacenter").SumoSelect({placeholder: "All Datacenters"});
$("#year").SumoSelect({placeholder: "All Years"});
$("#platform").SumoSelect({placeholder: "All Platforms"});
$("#tech").SumoSelect({placeholder: "No Technologies"});
$("#tech")[0].sumo.selectItem(1);
$("#tech")[0].sumo.selectItem(2);
$("#tech")[0].sumo.selectItem(3);
$("#version").SumoSelect({placeholder: "All Versions"});
$("#query").keyup(function(e) {
if(e.keyCode == 13) {
setFilters();
changeURL(scriptName);
if(checkFiltersDefault())
loadDefault();
else
filter(filteredServiceNames[env], true);
refresh(currentXmlHttpRequests);
}
});
$("#search").on("click", function(){
setFilters();
changeURL(scriptName);
if(checkFiltersDefault())
loadDefault();
else
filter(filteredServiceNames[env], true);
refresh(currentXmlHttpRequests);
});
$("#clear").on("click", function(){
clearFilters();
changeURL(scriptName);
loadDefault();
refresh(currentXmlHttpRequests);
});
}
});
}
But when this is entered, e.currentTarget is always #document and e.target.id is always blank. This results in the listeners never being applied.
page-bottom is setup in another method before this one:
function setupLast(dashboard) {
dashboard.rows.push({
title: 'Chart',
height: 25,
editable: false,
panels: [{
title: ' ',
type: 'text',
span: 0,
mode: 'html',
content: "<!DOCTYPE html><html><body><div id=\"page-bottom\" style=clear:both></div></body></html>",
height: 25,
transparent: true,
id: -1
}]
});
}
The guy who wrote this originally inserted this div as a way for us to watch for when the page has finished loading. His old docs have:
Most dashboards have an invisible panel that is added at the end of
the dashboard for the purpose of knowing when it is safe to perform
jquery event binding, among other things. This works by using jquery's
'DOMNodeInsert' event to wait for the div inside the panel to be added
to the page.
I'm not exactly sure what the issue is - if maybe when the base application was upgraded (2 years worth of upgrades) it upgraded the jquery version, or if I'm just missing something. I can see that page-bottom does actually end up in the page. When the page loads though, these listener setups never get executed.

I would just do away with that div detection mechanism and use the jQuery api method:
$(document).ready(function() {
refreshFilterList("Last 6 Months Of Launches");
refreshQuickJump(filtered);
$("#mySelect").on('change', function() {
var val = this.value;
if(val == "")
return;
document.getElementById(val).scrollIntoView();
var element = document.getElementById('mySelect');
element.value = "";
});
$("#datacenter").SumoSelect({placeholder: "All Datacenters"});
$("#year").SumoSelect({placeholder: "All Years"});
$("#platform").SumoSelect({placeholder: "All Platforms"});
$("#tech").SumoSelect({placeholder: "No Technologies"});
$("#tech")[0].sumo.selectItem(1);
$("#tech")[0].sumo.selectItem(2);
$("#tech")[0].sumo.selectItem(3);
$("#version").SumoSelect({placeholder: "All Versions"});
$("#query").keyup(function(e) {
if(e.keyCode == 13) {
setFilters();
changeURL(scriptName);
if(checkFiltersDefault())
loadDefault();
else
filter(filteredServiceNames[env], true);
refresh(currentXmlHttpRequests);
}
});
$("#search").on("click", function(){
setFilters();
changeURL(scriptName);
if(checkFiltersDefault())
loadDefault();
else
filter(filteredServiceNames[env], true);
refresh(currentXmlHttpRequests);
});
$("#clear").on("click", function(){
clearFilters();
changeURL(scriptName);
loadDefault();
refresh(currentXmlHttpRequests);
});
});

Try using e.target instead of currentTarget

Related

Cannot seem to add Node to Kendo UI TreeView

I was trying to add Node from textbox to the existing treeview
Input
<input id="appendNodeText" value="Node" class="k-textbox">
Button
<button type="button" class="btn btn-blue" id="addTopLevel">Add Top Level Menu</button>
javascript
<script>
// button handler
$("#addTopLevel").click(append);
handleTextBox = function (callback) {
return function (e) {
if (e.type != "keypress" || kendo.keys.ENTER == e.keyCode) {
callback(e);
}
};
};
var append = handleTextBox(function (e) {
var selectedNode = treeview.select();
console.log(selectedNode);
// passing a falsy value as the second append() parameter
// will append the new node to the root group
if (selectedNode.length == 0) {
selectedNode = null;
}
treeview.append({
text: $("#appendNodeText").val()
}, selectedNode);
});
So I end up having this click event in which it passes in "append"
To be honest I don't understand the handleTextBox , nor the append
The treeview does "work" but I wonder if it is part of the issue
var treeview = $("#treeview").kendoTreeView({
expanded: true,
dragAndDrop: true,
dataSource: homogeneous,
dataTextField: "ReportGroupName" //"name" //"id" // "FullName"
,
change: function(e) {
console.log("Change", this.select());
}
});
PER an Answer:
I tried this
$("#addTopLevel").click(function () {
console.log('in this');
if (treeview.select().length) {
console.log('1');
treeview.append({
text: $("#appendNodeText").val()
}, treeview.select());
} else {
//alert("please select tree node");
console.log('2');
}
});
console.log writes out 'in this' then '1'
So i'm not even selecting any node .... something must be wrong
here is my json
[{"Id":1,"ReportGroupName":"Standard Reports","ReportGroupNameResID":null,"SortOrder":1},{"Id":2,"ReportGroupName":"Custom Reports","ReportGroupNameResID":null,"SortOrder":2},{"Id":3,"ReportGroupName":"Retail Reports","ReportGroupNameResID":null,"SortOrder":3},{"Id":4,"ReportGroupName":"Admin Reports","ReportGroupNameResID":null,"SortOrder":5},{"Id":5,"ReportGroupName":"QA Reports","ReportGroupNameResID":null,"SortOrder":4}]
As i understood you want to append the textbox value as a node to selected node in the treeview. i have created a jsfiddle for the same with working functionality:-
http://jsfiddle.net/GHdwR/468/
click event for button:-
$("#addTopLevel").click(function() {
if (treeview.select().length) {
treeview.append({
text: $("#appendNodeText").val()
}, treeview.select());
} else {
alert("please select tree node");
}
});

Placeholder code used for IE8 causing dropdown login field to lose focus

I am using the below placeholder code for IE8, however about 70% of the time when you move your mouse around in the dropdown login field it loses focus (the whole dropdown login field vanishes); through debugging - when I remove this code the problem goes away - I have found the cause of the problem is this code:
Edit: I have found it isn't caused by any particular placeholder code, but it IS caused by some part of the process as I have tried 3 separate placeholder plugins and it happens on all 3 of them; take them away and no problems.
$(document).ready(function() {
if ( !("placeholder" in document.createElement("input")) ) {
$("input[placeholder], textarea[placeholder]").each(function() {
var val = $(this).attr("placeholder");
if ( this.value == "" ) {
this.value = val;
}
$(this).focus(function() {
if ( this.value == val ) {
this.value = "";
}
}).blur(function() {
if ( $.trim(this.value) == "" ) {
this.value = val;
}
})
});
// Clear default placeholder values on form submit
$('form').submit(function() {
$(this).find("input[placeholder], textarea[placeholder]").each(function() {
if ( this.value == $(this).attr("placeholder") ) {
this.value = "";
}
});
});
}
});
You can view an example here: http://condorstudios.com/stuff/temp/so/header-sample.php
Edit: Not sure if it will help as jsfiddle doesn't work on IE8 and I can't test if the fiddle behaves badly in IE8 too, but here is the fiddle: http://jsfiddle.net/m8arw/7/
Any way to fix this?
Have you tried switching your event to show/hide dropdown to 'mouseenter' and 'mouseleave'?
It's a lot more reliable on old IE than 'focus' and 'blur' event. Also, bind the event directly on the 'dropdown' div is more preferable than on the 'input' element.
In short, please try change this part of your code like this.
$(function() {
var dropdown = $('div.login div.dropdown')
.on('mouseenter', function() {
dropdown.css('display', 'block');
})
.on('mouseleave', function() {
dropdown.removeAttr('style');
});
});
demo: http://so.devilmaycode.it/placeholder-code-used-for-ie8-causing-dropdown-login-field-to-lose-focus
$(function(){
$('#main_header .login li').hover(function(){
$(this).find('.dropdown').show();
},function(){
$(this).find('.dropdown').hide();
});
});
NOTE: i have also cleaned up and fixed some coding horror in your js code...
I use this code to implement placeholder on all browsers (it uses Modernizr to detect it):
Demo: http://jsfiddle.net/S3zQ9/
var placeholder_OnBlur = function () {
var input = $(this);
if (input.val() == '' || input.val() == input.attr('placeholder')) {
input.addClass('placeholder');
input.val(input.attr('placeholder'));
}
};
var placeholder_OnFocus = function () {
var input = $(this);
if (input.val() == input.attr('placeholder')) {
input.val('');
input.removeClass('placeholder');
}
};
var placeholder_OnSubmit = function () {
$(this).find('[placeholder]').each(function () {
var input = $(this);
if (input.val() == input.attr('placeholder')) {
input.val('');
}
});
};
var placeholder_OnLoad = function () {
if (!!$(this).attr('placeholder')) {
$(this).on('focus', placeholder_OnFocus);
$(this).on('blur', placeholder_OnBlur);
$(this).parents('form').on('submit', placeholder_OnSubmit);
$(this).blur();
}
};
if (!Modernizr.input.placeholder) {
$('[placeholder]').each(placeholder_OnLoad);
}
Don't have IE8 to test it, but it should work.

how to detect if a link was clicked when window.onbeforeunload is triggered?

I have window.onbeforeunload triggering properly. It's displaying a confirmation box to ensure the user knows they are navigating (closing) the window and that any unsaved work will be erased.
I have a unique situation where I don't want this to trigger if a user navigates away from the page by clicking a link, but I can't figure out how to detect if a link has been clicked inside the function to halt the function. This is what I have for code:
window.onbeforeunload = function() {
var message = 'You are leaving the page.';
/* If this is Firefox */
if(/Firefox[\/\s](\d+)/.test(navigator.userAgent) && new Number(RegExp.$1) >= 4) {
if(confirm(message)) {
history.go();
}
else {
window.setTimeout(function() {
window.stop();
}, 1);
}
}
/* Everything else */
else {
return message;
}
}
You're looking for deferred event handling. I'll explain using jQuery, as it is less code:
window._link_was_clicked = false;
window.onbeforeunload = function(event) {
if (window._link_was_clicked) {
return; // abort beforeunload
}
// your event handling
};
jQuery(document).on('click', 'a', function(event) {
window._link_was_clicked = true;
});
a (very) poor man's implementation without jQuery's convenient delegation handling could look like:
document.addEventListener("click", function(event) {
if (this.nodeName.toLowerCase() === 'a') {
window._link_was_clicked = true;
}
}, true);
this allows all links on your page to leave without invoking the beforeunload handler. I'm sure you can figure out how to customize this, should you only want to allow this for a specific set of links (your question wasn't particularly clear on that).
var link_was_clicked = false;
document.addEventListener("click", function(e) {
if (e.target.nodeName.toLowerCase() === 'a') {
link_was_clicked = true;
}
}, true);
window.onbeforeunload = function() {
if(link_was_clicked) {
link_was_clicked = false;
return;
}
//other code here
}
You can differ between a link unload or a reload/user entering a different address unload s by using a timer. This way you know the beforeunload was triggered directly after the link click.
Example using jQuery:
$('a').on('click', function(){
window.last_clicked_time = new Date().getTime();
window.last_clicked = $(this);
});
$(window).bind('beforeunload', function() {
var time_now = new Date().getTime();
var link_clicked = window.last_clicked != undefined;
var within_click_offset = (time_now - window.last_clicked_time) < 100;
if (link_clicked && within_click_offset) {
return 'You clicked a link to '+window.last_clicked[0].href+'!';
} else {
return 'You are leaving or reloading the page!';
}
});
(tested in Chrome)

Click event only works on refresh

TL;DR - Anyone know why a click handler would only work on refresh?
If I have a function like so:
function selectState() {
$('#state-select').change(function(event) {
var state = $(this).val();
$("#vmap").find(("#jqvmap1_") + (state.toLowerCase(''))).click();
});
}
and I have that function run like so:
function setClickHandlers() {
$(document).on('click','a#reset_tracker',function(event) {
event.preventDefault();
$.get('decisiontree/reset_tracker/', function(data) {
window.location.reload();
});
});
if ($('#vmap').length !== 0) {
setTimeout(function(){
$('#vmap').bind('regionClick.jqvmap', function(event, code, region) {
$('#state-select').val(code.toUpperCase());
});
selectState(); //once the map loads, we should be able to select things, right
}, 500);
}
}
Which is then called by:
function setupSlide() {
setClickHandlers();
if ((typeof $.fn.vectorMap !== "undefined" && $.fn.vectorMap !== null) &&
$('#vmap').length !== 0) {
$('#vmap').vectorMap({
map: 'usa_en',
backgroundColor: null,
color: '#6a1912',
hoverColor: '#fdb33f',
selectedColor: '#fdb33f',
enableZoom: true,
showTooltip: true,
onRegionClick: function(event, code, region) {
event.preventDefault();
$('#state-select').val(code.toUpperCase());
}
});
}
}
Which is called by:
$(document).ready(function() {
setupSlide();
$(document).on('click','.prev', function(event) {
event.preventDefault();
loadSlide(prev_slide_url,{});
});
$(document).on('click','.next', function(event) {
event.preventDefault();
var answer;
if ($(this).hasClass('button') || $(this).hasClass('button-small')) {
answer = $(this).val();
} else if ($(this).hasClass('arrow')) {
answer = $('input[type=checkbox].answer:checked').val();
if (!answer && $('input[type=checkbox]').length > 0) {
$("p.inactive").addClass("error");
return false;
}
if ($("#vmap").length > 0) {
//for the map, the value is in the select
answer = $('#state-select').val();
if ($("#state-select").val().length === 0) {
$("p.inactive").addClass("error");
return false;
}
}
} else if ($(this).hasClass('navbutton')) {
answer = $(this).data('val');
}
loadSlide(next_slide_url,{answer: answer});
});
});
Why would the click method in SelectState only be invoked when the page that contains that function (namely, the page that has #vmap on it) is refreshed, rather than when the next or prev buttons (which have functionality defined in the document.ready block of code) are clicked? Is there something special about click handlers in this sort of context? I'm really unsure as to what is going on incorrectly.
One thing that I will add is that #jqvmap1_ refers to a path element in an SVG map, namely a map of the United States. But since it works on refresh, I don't think that it has to do with the fact that it is a path element.
Let me know if you need additional clarification for this problem. Apologies for the messy code.

Filtering html fields with jQuery

I have read about filtering table plugins. What I'm searching for is like this popup window.
(source: staticflickr.com)
When the user starts typing in the search-box, the relevant channel/category (as selected on previous dropdown box) should filter up. Also some animated loading action should happen while the filter process is going on.
I am looking for jQuery plugins which will make my filter-job easier to implement.
I think it is to ambigous to have a plugin for it. Just do something like this:
function filter($rows, category, search) {
$rows.each(function() {
if (category == ($("td:eq(2)", this).text() || category == "all") && (search. === "" || $("td:eq(1)", this).text().indexOf(search) !== -1) {
$(":checkbox", this).removeAttr("disabled");
$(this).show();
}
else
$(this).hide(function(){
$(":checkbox", this).attr("disabled", "disabled");
});
});
}
$("select.category").change(function() {
filter ($(this).closest("form").find("tr"), $(this).val(), $(this).closest("form").find("input.search").val());
});
$("input.search").keyUp(function() {
filter ($(this).closest("form").find("tr"), $(this).closest("form").find("select.catagory").val(), $(this).val());
});
You may need to make a few adjustments in order to make it work with the exact format of html.
Update to make it into a PLUGIN
$.fn.filter_table = function(options) {
options = $.extend(options, {
show: $.noop(), //Callback when a row get shown
hide: $.noop(), // Callback when a row gets hidden
entries: "table tr", // Selector of items to filter.
map: {} //Required parameter
//TODO Add default ajustment parameters here to remove ambiguity and assumptions.
});
return this.each(function() {
var form = this;
function each(callback) {
for (var selector in options.map) {
var check = options.map[selector];
$(selector, form).each(function(){
callback.call(this, check);
});
}
}
function show(row) {
if (!$(row).is(":visible")) {
options.show.apply(row);
$(row).show();
}
}
function hide(row) {
if ($(row).is(":visible"))
$(row).hide(options.hide);
}
function run_filter() {
$(options.entries, form).each(function() {
var row = this, matched = true;
each(function(check) {
matched &= check.call(this, row);
});
matched ? show(this) : hide(this);
})
}
//Bind event handlers:
each(function() {
$(this).bind($(this).is(":text") ? "keyup" : "change", run_filter);
});
});
};
You can use this plugin as follows:
$("form").filter_table({
map: {
//These callback define if a row was matched:
"select.category": function(row) {
//this refers to the field, row refers to the row being checked.
return $(this).val() == "all" || $(this).val() == $("td:eq(2)", row).text();
},
"input.search": function(row) {
return $(this).val() == "" || $(this).val() == $("td:eq(1)", row).text();
}
},
entries: "tr:has(:checkbox)", //Filter all rows that contain a checkbox.
show: function() {
$(":checkbox", this).removeAttr("disabled");
},
hide: function() {
$(":checkbox", this).attr("disabled", "disabled");
}
});
Okay it should work once it was debugged. I haven't tested it. I think that part is up to you.
If your HTML looks like this:
<form id="filterForm">
<input type="text" id="filterBox">
<input type="submit" value="Filter">
</form>
<div id="checkboxContainer">
<label><input type="checkbox" id="checkbox123"> Checkbox 123</label>
</div>
You could do something like...
//Set variables so we only have to find each element once
var filterForm = $('#filterForm');
var filterBox = $('#filterBox');
var checkboxContainer = $('#checkboxContainer');
//Override the form submission
filterForm.submit(function() {
//Filter by what the label contains
checkboxContainer.find('label').each(function() {
//If the value of filterBox is NOT in the label
if ($(this).indexOf(filterBox.val()) == -1) {
//Hide the label (and the checkbox since it's inside the label)
$(this).hide();
} else {
//Show it in case it was hidden before
$(this).show();
}
});
//Prevent the form from submitting
return false;
});
You can use this tablesorterfilter plugin to achieve what you need
Working Fiddle
And also please have a look at http://datatables.net/
There are many options out there. Here is a good place to start: http://www.wokay.com/technology/32-useful-jquery-filter-and-sort-data-plugins-62033.html
Filtering like this isn't incredibly complicated. It may be worth looking at the source of a couple plugins that come close to what you want and then try to write your own. You'll learn a lot more if you do it yourself!

Categories