I have this code:
jQuery.fn.extend({
SelectBox: function(options) {
return this.each(function() {
new jQuery.SelectBox(this, options);
});
}
});
jQuery.SelectBox = function(selectobj, options) {
var opt = options || {};
opt.inputClass = opt.inputClass || "inputClass";
opt.containerClass = opt.containerClass || "containerClass";
var inFocus = false;
var $select = $(selectobj);
var $container = setupContainer(opt);
var $input = setupInput(opt);
$select.hide();
hideMe();
$input
.click(function(){
if (!inFocus) {
showMe();
} else {
hideMe();
}
})
.keydown(function(event) {
switch(event.keyCode) {
case 27:
hideMe();
break;
}
})
.blur(function() {
if ($container.not(':visible')) {
hideMe();
}
});
function showMe() {
$container.show();
inFocus = true;
}
function hideMe() {
$container.hide();
inFocus = false;
}
function setupContainer(options){
$container = $("." + options.containerClass);
$input = $("." + options.inputClass);
var first = false;
var li = "";
$select.find('option').each(function(){
if($(this).is(':selected')){
$input.find('span').text($(this).text());
first = true;
}
//var $li = $container.find('ul').append('<li>' + $(this).text() + '</li>');
var li = document.createElement('li');
li.innerHTML = $(this).text();
$container.find('ul').append(li);
$(li).click(function(event){
$(li).remove();
});
});
return $container;
}
function setupInput(options){
$input = $("." + options.inputClass);
$input.attr('tabindex', '0');
return $input;
}
};
In this code, the "select" i choose hidden, and replaced by a list.
Now, i want click on some "li", and "li" removed.
But, i click on the "li" i have created, and nothing happened.
Why? how can i remove or do anything else when i click on the "li"?
There is no need to add event to each individual element. Use event delegation.
$(document).ready(function() {
$(commonParentSelector).on('click', 'li', function() {
// ^^^^^^^^^^^^^^^^^^^^
$(this).remove();
});
});
Update commonParentSelector according to your needs and it should work.
Docs: https://api.jquery.com/on
use var $li = $("<li>").text($(this).text()).appendTo($container.find('ul'));
Related
I have a 500+ row table and this this being filtered by as per the below code.
When someone clicks on one of the filters, I want something to show how many rows remain in the table. (And if possible for this to update everytime a new checkbox is ticked/clicked)
Can anyone help?
Apologies for the length of the code
$(document).ready(function () {
var buttons = $('#wiFilter li');
var checkboxes = $('#wiFilter input:checkbox');
$(buttons).click(function(){
var inpt = $(this).find('input');
if ($(this).is('.checked')) {
$(this).removeClass('checked');
}
else {
$(this).addClass('checked');
}
if ($(inpt).prop('checked')) {
$(inpt).removeAttr('checked').change();
}
else {
$(inpt).prop("checked", true).change();
}
$(this).blur();
});
$(checkboxes).on("change", function () {
var arrChecked = $(checkboxes).filter(':checked').map(function () {
return $(this).val();
}).get();
$("#wiTable tr:first").nextAll().show(); // reset the table: show all items
if (arrChecked.length > 0) {
$('.WI').each(function(){
var hideRow = true;
var arrCategories = $(this).text().split(', ');
for (i=0; i<arrCategories.length; i++) {
if (arrChecked.indexOf(arrCategories[i]) > -1) {
hideRow = false;
}
}
if (hideRow) {
$(this).parent().hide();
}
});
}
$(this).blur();
});
var $rows = $('#wiTable tr:first').nextAll();
$('#wiSearch').keyup(function() {
// regex looks for all words, in any order, in the text to be matched
var val = '^(?=.*\\b' + $.trim($(this).val()).split(/\s+/).join('\\b)(?=.*\\b') + ').*$',
reg = RegExp(val, 'i'),
str;
$rows.show().filter(function() {
str = $(this).text().replace(/\s+/g, ' '); // replace multiple spaces with one space?
return !reg.test(str);
}).hide();
});
// $('#wiSearch')
// .focus(function () {
// // $(this).val('');
// // $(countriesList).show();
// })
// .keyup(function () {
// var searchval = $(this).val().toLowerCase();
// $(countriesList).each(function () {
// if (!$(this).text().toLowerCase().match(searchval)) {
// $(this).hide();
// }
// else {
// $(this).show();
// }
// });
// })
// .blur(function () {
// var searchval = $(this).val().toLowerCase();
// if (!searchval) {
// $('#RoamingPartners_CountryListSearch').val(RoamingPartners_CountryListSearch_DefaultText);
// $(countriesList).show();
// }
// });
// $('html').bind('keypress', function(e)
// {
// if(e.keyCode == 13)
// {
// return false;
// }
// });
});
{
var x = $('#wiTable tr:visible').length;
document.getElementById("count").innerHTML = "We've got " + x + " processes that match your query";}
Many thanks in advance
I have a open function that once triggered, simply plays video in a dedicated panel.
This function can be triggered in two ways - one with a click and another one with a page load (window load) with url that contains a valid anchor tag.
They all work fine but some codes of the window load handler are repetitive and I'm not too sure how I can keep this DRY.
Please take a look and point me in some directions on how I can write this better.
I commented in open function which is for which.
$.videoWatch.prototype = {
init: function() {
this.$openLinks = this.$element.find(".open");
this.$closeLinks = this.$element.find(".close");
this.open();
this.close();
},
_getContent: function(element) {
var $parent = element.parent(),
id = element.attr('href').substring(1),
title = $parent.data('title'),
desc = $parent.data('desc');
return {
title: title,
desc: desc,
id: id
}
},
open: function() {
var self = this;
//open theatre with window load with #hash id
window.onload = function() {
var hash = location.hash;
var $a = $('a[href="' + hash + '"]'),
content = self._getContent($a),
$li = $a.parents("li"),
$theatreVideo = $(".playing"),
$theatreTitle = $(".theatre-title"),
$theatreText = $(".theatre-text");
$(".theatre").attr('id', content.id);
$theatreTitle.text(content.title);
$theatreText.text(content.desc);
if ($theatreText.text().length >= 90) {
$(".theatre-text").css({
'overflow': 'hidden',
'max-height': '90px',
});
$moreButton.insertAfter($theatreText);
}
$a.parent().addClass("active");
$(".theatre").insertAfter($li);
$(".theatre").slideDown('fast', scrollToTheatre);
oldIndex = $li.index();
}
//open theatre with click event
self.$openLinks.on("click", function(e) {
// e.preventDefault();
if (curID == $(this).parent().attr("id")) {
$("figure").removeClass("active");
$("button.more").remove();
$(".theatre").slideUp('fast');
$('.playing').attr("src", "");
removeHash();
oldIndex = -1;
curID = "";
return false
} else {
curID = $(this).parent().attr("id");
}
var $a = $(this),
content = self._getContent($a),
$li = $a.parents("li"),
$theatreVideo = $(".playing"),
$theatreTitle = $(".theatre-title"),
$theatreText = $(".theatre-text");
$(".theatre").attr('id', content.id);
$theatreTitle.text(content.title);
$theatreText.text(content.desc);
if ($theatreText.text().length >= 90) {
$(".theatre-text").css({
'overflow': 'hidden',
'max-height': '90px',
});
$moreButton.insertAfter($theatreText);
}
if (!($li.index() == oldIndex)) {
$("figure").removeClass("active");
$(".theatre").hide(function(){
$a.parent().addClass("active");
$(".theatre").insertAfter($li);
$(".theatre").slideDown('fast', scrollToTheatre);
oldIndex = $li.index();
});
} else {
$(".theatre").insertAfter($li);
scrollToTheatre();
$("figure").removeClass("active");
$a.parent().addClass("active");
}
});
},
...
Simplified and refactored open method:
open: function() {
var self = this;
var serviceObj = {
theatreVideo : $(".playing"),
theatre: $(".theatre"),
theatreTitle : $(".theatre-title"),
theatreText : $(".theatre-text"),
setTheatreContent: function(content){
this.theatre.attr('id', content.id);
this.theatreTitle.text(content.title);
this.theatreText.text(content.desc);
if (this.theatreText.text().length >= 90) {
this.theatreText.css({
'overflow': 'hidden',
'max-height': '90px',
});
$moreButton.insertAfter(this.theatreText);
}
},
activateTeatre: function(a, li){
a.parent().addClass("active");
this.theatre.insertAfter(li);
this.theatre.slideDown('fast', scrollToTheatre);
oldIndex = li.index();
}
};
//open theatre with window load with #hash id
window.onload = function() {
var hash = location.hash;
var $a = $('a[href="' + hash + '"]'),
content = self._getContent($a),
$li = $a.parents("li");
serviceObj.setTheatreContent(content);
serviceObj.activateTeatre($a, $li);
}
//open theatre with click event
self.$openLinks.on("click", function(e) {
// e.preventDefault();
if (curID == $(this).parent().attr("id")) {
$("figure").removeClass("active");
$("button.more").remove();
$(".theatre").slideUp('fast');
$('.playing').attr("src", "");
removeHash();
oldIndex = -1;
curID = "";
return false
} else {
curID = $(this).parent().attr("id");
}
var $a = $(this),
content = self._getContent($a),
$li = $a.parents("li");
serviceObj.setTheatreContent(content);
if (!($li.index() == oldIndex)) {
$("figure").removeClass("active");
$(".theatre").hide(function(){
serviceObj.activateTeatre($a, $li);
});
} else {
$(".theatre").insertAfter($li);
scrollToTheatre();
$("figure").removeClass("active");
$a.parent().addClass("active");
}
});
},
1st of all there are variables that don't depend on the input, you could pull them to the class (I'll show just one example, as you asked for directions):
init: function() {
this.$theatreVideo = $(".playing");
All the variables that do depend on the input, like $li could be moved to a function:
var $a = $(this),
$dependsOnA = self.dependsOnA($a);
self.actionDependsOnA($dependsOnA); // see below
function dependsOnA($a) {
return {
a: $a,
li: $a.parents("li"),
content: self._getContent($a)
}
}
Also the code that "repeats" can be moved to a function:
function actionDependsOnA($dependsOnA)
$(".theatre").attr('id', $dependsOnA.content.id);
$theatreTitle.text($dependsOnA.content.title);
$theatreText.text($dependsOnA.content.desc);
}
I am trying to use jQuery to submit a form that is loaded through a modal dynamically but i have a problem with multiple submissions. This Code is posting multiple times, can someone explain why? Thank you.
var convArrToObj = function(array){
var thisEleObj = new Object();
if(typeof array == "object"){
for(var i in array){
var thisEle = convArrToObj(array[i]);
thisEleObj[i] = thisEle;
}
}else {
thisEleObj = array;
}
return thisEleObj;
};
var serialize = function(obj) {
var str = [];
for(var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
};
var events = [];
var appointments = [];
var formData = [];
$('#newAppointment').on('click', function(){
$( ".modal-content" ).load( "api/calendar/appointment.php", { personId: $(this).attr('personId')}, function(){
$(".chosen-select").chosen({width:'100%',placeholder_text_multiple:'Select People'});
$(".datepicker").pickadate({format: 'mm/dd/yyyy' });
$(".timepicker").pickatime({format: 'HH:i' });
});
});
$('#page-wrapper').on('mouseenter', '#appointform', function(){
$('#appointSubmit').on('click', function(event){
event.preventDefault();
$('#appointSubmit').prop('disabled',true);
$("#appointform select").each(function() {
var fieldName = $(this).attr("name");
var fieldVal = $(this).val();
if(typeof fieldVal === 'undefined'){
fieldVal = "";
}
if(! fieldVal ){
fieldVal = "";
}
if($(this).val() === "? undefined:undefined ?"){
fieldVal = "";
}
formData[fieldName] = fieldVal;
});
$("#appointform input").each(function() {
formData[this.name] = this.value;
});
$("#appointform textarea").each(function() {
formData[this.name] = this.value;
});
$('#modal').modal('hide');
$.post('api/calendar/post', convArrToObj(formData), function(response){
console.log(response);
});
});
});
Every time the mouse enters your #page-wrapper element, you're re-binding the click event to #appointSubmit, causing the event to fire multiple times when the user clicks the button / link only once.
The mouseenter event is likely firing multiple times. Every time your mouse enters or re-enters the form, it is re-adding the event handler to the form. You should set the onsubmit/onclick handler for your button once in the load callback function instead to prevent this from happening.
Remove mouseenter listener you really don't need it.
var convArrToObj = function(array){
var thisEleObj = new Object();
if(typeof array == "object"){
for(var i in array){
var thisEle = convArrToObj(array[i]);
thisEleObj[i] = thisEle;
}
}else {
thisEleObj = array;
}
return thisEleObj;
};
var serialize = function(obj) {
var str = [];
for(var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
};
var events = [];
var appointments = [];
var formData = [];
$('#newAppointment').on('click', function(){
$( ".modal-content" ).load( "api/calendar/appointment.php", { personId: $(this).attr('personId')}, function(){
$(".chosen-select").chosen({width:'100%',placeholder_text_multiple:'Select People'});
$(".datepicker").pickadate({format: 'mm/dd/yyyy' });
$(".timepicker").pickatime({format: 'HH:i' });
});
});
$('#appointSubmit').on('click', function(event){
event.preventDefault();
$('#appointSubmit').prop('disabled',true);
$("#appointform select").each(function() {
var fieldName = $(this).attr("name");
var fieldVal = $(this).val();
if(typeof fieldVal === 'undefined'){
fieldVal = "";
}
if(! fieldVal ){
fieldVal = "";
}
if($(this).val() === "? undefined:undefined ?"){
fieldVal = "";
}
formData[fieldName] = fieldVal;
});
$("#appointform input").each(function() {
formData[this.name] = this.value;
});
$("#appointform textarea").each(function() {
formData[this.name] = this.value;
});
$('#modal').modal('hide');
$.post('api/calendar/post', convArrToObj(formData), function(response){
console.log(response);
});
});
on my website I have a div .toggle-search that if you click on it it expands to .search-expand where a search form is. This is the code in jQuery
/* Toggle header search
/* ------------------------------------ */
$('.toggle-search').click(function(){
$('.toggle-search').toggleClass('active');
$('.search-expand').fadeToggle(250);
setTimeout(function(){
$('.search-expand input').focus();
}, 300);
});
Now the only way to close the .search-expand is to click once again on the .toggle-search. But I want to change that it closes if you click anywhere else on the site. For an easier example I have the Hueman theme, and I'm talking about the top right corner search option. http://demo.alxmedia.se/hueman/
Thanks!
Add the event on all elements except the search area.
$('body *:not(".search-expand")').click(function(){
$('.toggle-search').removeClass('active');
$('.search-expand').fadeOut(250);
});
or another way,
$('body').click(function(e){
if(e.target.className.indexOf('search-expand') < 0){
$('.toggle-search').removeClass('active');
$('.search-expand').fadeOut(250);
}
});
var isSearchFieldOpen = false;
var $toggleSearch = $('.toggle-search');
var $searchExpand = $('.search-expand');
function toggleSearch() {
// Reverse state
isSearchFieldOpen = !isSearchFieldOpen;
$toggleSearch.toggleClass('active');
// You can use callback function instead of using setTimeout
$searchExpand.fadeToggle(250, function() {
if (isSearchFieldOpen) {
$searchExpand.find('input').focus();
}
});
}
$toggleSearch.on('click', function(e) {
e.stopPropagation();
toggleSearch();
});
$(document.body).on('click', function(e) {
if (isSearchFieldOpen) {
var target = e.target;
// Checking if user clicks outside .search-expand
if (!$searchExpand.is(target) && !$searchExpand.has(target).length) {
toggleSearch();
}
}
});
I have a second search on the site with the same code as before only
with div .toggle-serach2 and .expand-search2, how can i make your code
so it wont overlap. just changing the name to $('toggle-search2')
doesn't cut it
in that case, I would suggest you convert your code into a plugin:
(function($, document) {
var bodyHandlerAttached = false;
var openedForms = [];
var instances = {};
var defaults = {
activeClass: 'active'
};
function ToggleSearch(elem, options) {
this.options = $.extend({}, defaults, options);
this.$elem = $(elem);
this.$btn = $(options.toggleBtn);
this.isOpen = false;
this.id = generateId();
this.bindEvents();
instances[this.id] = this;
if (!bodyHandlerAttached) {
handleOutsideClick();
bodyHandlerAttached = true;
}
}
ToggleSearch.prototype = {
bindEvents: function() {
this.$btn.on('click', $.proxy(toggleHandler, this));
},
open: function() {
if (this.isOpen) { return; }
var _this = this;
this.$btn.addClass(this.options.activeClass);
this.$elem.fadeIn(250, function() {
_this.$elem.find('input').focus();
});
openedForms.push(this.id);
this.isOpen = true;
},
close: function(instantly) {
if (!this.isOpen) { return; }
this.$btn.removeClass(this.options.activeClass);
if (instantly) {
this.$elem.hide();
} else {
this.$elem.fadeOut(250);
}
openedForms.splice(openedForms.indexOf(this.id), 1);
this.isOpen = false;
},
toggle: function() {
if (this.isOpen) {
this.close();
} else {
this.open();
}
}
};
var toggleHandler = function(ev) {
ev.stopPropagation();
this.toggle();
};
var handleOutsideClick = function(e) {
$(document.body).on('click', function(e) {
if (openedForms.length) {
var target = e.target;
var instance;
for (var id in instances) {
instance = instances[id];
if (!instance.$elem.is(target) && !instance.$elem.has(target).length) {
instance.close(true);
}
}
}
});
};
function generateId() {
return Math.random().toString(36).substr(2, 8);
}
$.fn.toggleSearch = function(options) {
return this.each(function() {
if (!$.data(this, 'toggleSearch')) {
$.data(this, 'toggleSearch', new ToggleSearch(this, options));
}
});
};
})(window.jQuery, document);
And then use it like this:
$('.search-expand').toggleSearch({
toggleBtn: '.toggle-search'
});
$('.search-expand2').toggleSearch({
toggleBtn: '.toggle-search2'
});
JSFiddle example
You could add a click handler to the main window that removes the active class:
$(window).click(function(){
$('.toggle-search').removeClass('active');
}
and then prevent the class removal when you click inside of your toggle-search elem
$('.toggle-search').click(function(e){
e.stopPropagation();
// remainder of click code here
)};
Try to add body click listener
$('body').click(function(e){
if ($(e.target).is('.toggle-search')) return;
$('.toggle-search').removeClass('active');
$('.search-expand').fadeOut(250);
});
I have following javascript code to give me drop down menus. I don't want it to drop down the menu. I want it to show all the menu by default what should I remove. Please help.
function DropDown(el) {
this.dd = el;
this.placeholder = this.dd.children('span');
this.opts = this.dd.find('ul.dropdown > li');
this.val = '';
this.index = -1;
this.initEvents();
}
DropDown.prototype = {
initEvents: function () {
var obj = this;
obj.dd.on('click', function (event) {
$(this).toggleClass('active');
return false;
});
obj.opts.on('click', function () {
var opt = $(this);
obj.val = opt.text();
obj.index = opt.index();
obj.placeholder.text(obj.val);
});
},
getValue: function () {
return this.val;
},
getIndex: function () {
return this.index;
}
}
$(function () {
var dd = new DropDown($('#dd'));
$(document).click(function () {
// all dropdowns
$('.wrapper-dropdown-3').removeClass('active');
});
});
remove
obj.dd.on('click', function(event){
$(this).toggleClass('active');
return false;
});
update
and add the class active by changing var dd = new DropDown( $('#dd') ); into var dd = new DropDown( $('#dd').addClass('active') );
also if you don't want it to get hidden onclick of the document, remove the following as well.
$(document).click(function() {
// all dropdowns
$('.wrapper-dropdown-3').removeClass('active');
});