I am building a simple shopping list. Currently my code will delete an added list item when you click anywhere on the list item itself, I would like it to work where clicking on the UI button next to it will delete the entire item from the list, what I have tried will only delete the UI button itself. Thanks for the help, I am very much a novice
HTML
<div id="list">
<ul class="shopping"></ul>
</div>
jQuery
$(document).ready(function () {
function addItemToList(e) {
var addItem = $('#item').val();
$('.shopping').append('<li>' + '<button class="uibutton"></button>' + addItem + '</li>');
$('.uibutton').button({
icons: {
primary: "ui-icon-heart"
},
text: false
});
$('ul').on('click', 'li', function() {
$(this).remove();
});
$('#item').val('');
}
/*adds list item to list when cart icon is clicked, clears #item input field*/
$('#toadd').click(function (e) {
addItemToList(e);
});
/*adds list item to list when enter key is hit, clears #item input field*/
$('#item').keydown(function (e) {
if (e.which == 13) {
addItemToList(e);
}
});
});
You can make 2 changes like
$(document).ready(function () {
function addItemToList(e) {
var addItem = $('#item').val();
var $li = $('<li>' + '<button class="uibutton"></button>' + addItem + '</li>').appendTo('.shopping');
//target only newly added button
$li.find('.uibutton').button({
icons: {
primary: "ui-icon-heart"
},
text: false
});
$('#item').val('');
}
//use event delegation instead of adding the handler in another event handler...
$('ul.shopping').on('click', '.uibutton', function () {
$(this).closest('li').remove();
});
/*adds list item to list when cart icon is clicked, clears #item input field*/
$('#toadd').click(function (e) {
addItemToList(e);
});
/*adds list item to list when enter key is hit, clears #item input field*/
$('#item').keydown(function (e) {
if (e.which == 13) {
addItemToList(e);
}
});
});
Demo: Fiddle
Related
I have written simple quiz with two cards. After user have clicked on the card, attribute clicked change status and answer is checked.
clicked = false;
$(document).on("click", "#card1", function() {
clicked = true;
check answer........
});
I have got antoher on click event, which should load next question when user click on body element.
This event should only work when the card is clicked and clicked status is true.
$(document).on("click", "body", function() {
if (clicked == true) {
quiz.nextQuestion();
clicked = false;
}
});
But these two onclick events start and execute simultaneously.
How can I prevent this?
stopPropagation(); can be used for this. Otherwise click on elements inside will also trigger the body click functions.
One more thing is that, we have to give click for <html> rather than <body>.
Description: Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
clicked = false;
$(document).on("click", "#card1", function(e) {
e.stopPropagation();
clicked = true;
console.log('click card');
});
$(document).on("click", "html", function(e) {
if (clicked == true) {
console.log('click body');
clicked = false;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="card1">
Card1
</div>
</body>
Simple...
clicked = false;
$(document).on("click", "#card1", function() {
clicked = true;
//check answer........
$(this).on("click", "body", function() {
if (clicked == true) {
quiz.nextQuestion();
clicked = false;
}
});
});
Hope this helps.....
You can do it by changing the status of clicked as true after you have checked the answer.
$(document).on("click", "#card1", function() {
check answer........
clicked = true;
});
This will make sure that clicked is not made true as soon as the click event is fired hence making the if statement in the second part of the code false
OR
You can even do it by
clicked = 0;
$(document).on("click", "#card1", function() {
clicked = 1;
check answer........
});
$(document).on("click", "body", function() {
if (clicked == 2) {
quiz.nextQuestion();
clicked = 0;
}else
{
clicked +=1;
}
});
I am trying to get a close button to close 2 LIs but they're in 2 different ULs - LIs generated by jQuery dynamically.
When someone enters an item / qty and clicks add they are rendered into a new LI but when they include the pricing, it renders in a different LI
So pressing the "X" in the Item/Qty to close the specific LI wont affect the price corresponding to that item.
Also the "Clear" button works fine just the individual LIs
Any suggestions on fixing this issue without having to add the "X" on the price LI as well?
I hope my explanation makes sense, you can see the code here
$(document).ready(function () {
// Adds typed items and qty to the list
$('#add').on('click', function () {
var item = $('#list').val();
var qty = $('#qty').val();
$('#list-a').append('<li>' + '<div class="delete"></div>' + qty + ' ' + item + '</li>');
var price = $('#price').val();
$('#list-b').append('<li>' + '$' + price + '</li>');
// Resets input field to empty and focus
$('#list').val('').focus();
$('#qty, #price').val('');
});
// Fires Add to List button when enter is clicked
$('#list, #qty, #price').keyup(function (event) {
if (event.keyCode === 13) {
$('#add').click();
}
});
// Deletes/fades out 'li' when X is clicked
$('#list-a').on('click', '.delete', function () {
var listItem = $(this).closest('li');
listItem.fadeOut(500, function () {
listItem.remove();
});
});
// Clear all items on the list and focus back on new shopping item
$('#clear').on('click', function () {
var li = $('li');
li.fadeOut(500, function () {
$(li).remove('li');
});
$('#list').val('').focus();
});
});
You would need to remove the li with the same sibling index from the next ul:
$('#list-a').on('click', '.delete', function () {
var listItem = $(this).closest('li'),
index = listItem.index();
listItem.parent().next('ul').find('li:eq(' + index + ')').add(listItem)
.fadeOut(500, function () {
$(this).remove();
});
});
Demo: http://codepen.io/anon/pen/emdyqX
$('#list-a').on('click', '.delete', function() {
var listItem = $(this).closest('li');
var ind = listItem.index();
listItem.fadeOut(500, function() {
listItem.remove();
});
$('#list-b').find('li').eq(ind).fadeOut(500, function() {
$(this).remove();
});
});
http://codepen.io/anon/pen/OPRzKx
Im using jQuery ui button to create divs that look like buttons dynamically. Clicking on these divs should open a dialog and clicking its icon should remove the div(button). Ive tried several different approaches but I cant seem to get the result I want.
Closest thing Ive achieved is by using onclick on both the icon & on the div itself, but the problem is that when clicking the icon I would first call the icon's onclick and then afterwards calling the div's onclick, which will cause the dialog to open after the div has been removed.
Ive also tried to add a disable property and set it to true on the div inside the icon's onclick and check for that inside the div's onclick but that dont work(I kinda get why.)
So my question is then: How can I create a button that will open a dialog when clicked on and with a icon that, when clicked on, removes the button?
Code:
function Add(value) {
var buttonid = "SearchResultBox" + ($("#SearchBoxAddedSearches .SearchResultBox").length + 1);
$("#SearchBoxAddedSearches").append("<div id='" + buttonid + "' class='SearchResultBox' onclick='ButtonClicked(this);'>" + value + "</div>");
$("#SearchBoxTextField").contents().filter(function () { return this.nodeType === 3; }).remove();
$('.SearchResultBox').button({
icons: {
primary: "ui-icon-circle-close"
}
}).delegate("span.ui-icon-circle-close", "click", function () {
var btnId = $(this).closest("div").remove().attr("aria-controls");
$("#" + btnId).remove();
});
$('.ui-icon-circle-close').attr('onclick', 'IconCloseClicked(this);');
}
function IconCloseClicked(value) {
$(value).parent().prop("disable", "true");
//alert($(value).parent().attr("id"));
alert("icon");
Remove($(value).parent());
}
function ButtonClicked(o) {
var test = $(o).prop("disable");
alert("div");
if ($(o).attr("disable") == undefined) {
Opendialog();
}
}
function Remove(value) {
$(value).remove();
}
function Opendialog() {
$("#dialog").dialog("open");
}
Ps. Reason why Ive used the button is because it is the widget that looks the most like what I want in jquery ui.
Updated(What I ended up with):
function Add(value) {
var buttonid = "SearchResultBox" + ($("#SearchBoxAddedSearches .SearchResultBox").length + 1);
$("#SearchBoxAddedSearches").append("<div id='" + buttonid + "' class='SearchResultBox'>" + value + "</div>");
$("#SearchBoxTextField").contents().filter(function () { return this.nodeType === 3; }).remove();
$('.SearchResultBox').button({
icons: {
primary: "ui-icon-circle-close"
}
}).click(function (e) {
Opendialog();
});
$('.ui-icon-circle-close').click(function (e) {
$(this).parent().remove();
e.stopPropagation();
});
}
function Opendialog() {
$("#dialog").dialog("open");
}
I'm assuming the icon is a child element of the button div. When the icon is clicked, you need to stop the click event bubbling to the parent div. You can do this with event.stopPropagation()
$('.icon').click(function(e){
e.stopPropagation();
});
I've broken it again, and no idea how.
I have a CodePen of my recent activities.
What I've been trying to implement is a sortable function that checks first if there's only one #p_scents. If there is, it shouldn't be sortable (ie the .icon-sort shouldn't be activated). However if there is more than one, it should be sortable.
The problem I ran into however is after all but one has been deleted, the sortable functionality is still activated as it doesn't RE-check for how many #p_scents exist.
How can I fix this?
FYI somehow I broke the sortable functionality now o_O
$(function () {
var i = 1;
//ADD ROW
$('body').on('click', '.addPTbutton', function () {
var box = '<table class="manage-pt" id="' + i + '"><tr class="pt-entry"><td class="pt-toggle-group"><input class="pt-button togPTbutton" id="0" type="button" value="▾"><input class="pt-button addPTbutton" id="0" type="button" value="+"><input class="pt-button delPTbutton" id="' + i + '" type="button" value="-"></td><td class="pt-values"><div><input class="vendor" placeholder="*Vendor Name" type="text"><i class="icon-sort"></i><i class="icon-lock"></i></div><div><textarea class="ptCode" name="ptCode" placeholder="*Pixel Tag Code"></textarea></div><div class="page-select"><select><option value="AllPages">All Pages</option><option value="HomePage">HomePage</option><option value="VehicleDetailsPage">VehicleDetailsPage</option><option value="VehicleSearchResults">VehicleSearchResults</option><option value="ContactUsForm">ContactUsForm </option></select></div><div class="area-checkboxes"><p class="wheretosave">*Where?</p><input name="head" type="checkbox"><label for="head">Head</label><input name="body" type="checkbox"><label for="body">Body</label></div><hr/></td></tr></table>';
i++;
$("#p_scents").append(box);
return false;
});
//DELETE ROW
$('body').on('click', '.delPTbutton', function () {
var boxnum = $(".manage-pt").length;
if (boxnum <= '1') {
alert('Cannot Delete Last Remaining Row');
} else {
$(this).parents().eq(3).remove();
}
return false;
});
//TOGGLE BUTTON
$('body').on('click', '.togPTbutton', function () {
var hiddenarea = $(this).parent().next().children().next();
if ($(hiddenarea).is(':hidden')) {
//PT-VALUES OPENED
$(this).val('▾');
$(this).parent().next().children(0).children(0).attr('readonly', false);
} else {
//PT-VALUES HIDDEN
$(this).val('▸');
$(this).parent().next().children(0).children(0).attr('readonly', true);
}
//TOGGLE VISIBILITY OF HIDDEN AREA
hiddenarea.toggle();
});
//CHECKS FOR MORE THAN ONE 1 MANAGE-PT BEFORE ENABLES SORTABLE
$('body').on('click', '.icon-sort', function () {
if ($(".manage-pt").size() > 1) {
$('#p_scents').sortable({
disabled: false,
placeHolder: '.placeHolderHighlight',
handle: '.icon-sort',
});
} else $('#p_scents').sortable({
disabled: true,
});
});
//CHECK TO MAKE SURE ONLY ONE CHECKBOX IS SELECTED
var $onlyOne = $('.onlyOne');
$onlyOne.click(function () {
$onlyOne.filter(':checked').not(this).removeAttr('checked');
});
//LOCK BUTTON ON/OFF LOCKS FORM
$('body').on('click', '.icon-lock', function () {
$(this).toggleClass('locked');
var lockedarea = $(this).parents(0).eq(2);
$(lockedarea).find('input[type=text],input[type=checkbox],textarea,select').prop('disabled', function (_, val) {
return !val;
});
});
});
Your problem is here:
//CHECKS FOR MORE THAN ONE 1 MANAGE-PT BEFORE ENABLES SORTABLE
$('body').on('click', '.icon-sort', function () {...});
When make click on element ".icon-sort" is still sortable. You must use an action that makes the check before sort action begins: like mouseenter.
Here a jsfiddle
I'm experiencing weird behavior with jquery ui autocomplete when using it to create a combobox. Whenever I click on the scrollbar to scroll through the list of results AND then click on my combobox button to close the results the results list closes and then opens again. I expect it to close the menu.
Steps to Repro
open jsfiddle demo
Type 'i' in the autocomplete OR hit the dropdown button.
Click on the vertical scroll to scroll the results
Click on the dropdown button
Script to Create Button
this.button = $("<button type='button'> </button>")
.attr({ "tabIndex": -1, "title": "Show all items" })
.insertAfter(input)
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
.removeClass("ui-corner-all")
.addClass("ui-corner-right ui-button-icon")
.click(function () {
// when i put breakpoint here, and my focus is not on input,
// then this if steatment is false????
if (input.autocomplete("widget").is(":visible")) {
input.autocomplete("close");
return;
}
// work around a bug (likely same cause as #5265)
$(this).blur();
// pass empty string as value to search for, displaying all results
input.autocomplete("search", "");
input.focus();
});
CSS (force long results menu to scroll)
.ui-autocomplete {
max-height: 100px;
overflow-y: auto;
/* prevent horizontal scrollbar */
overflow-x: hidden;
/* add padding to account for vertical scrollbar */
padding-right: 20px;
}
/* IE 6 doesn't support max-height
* we use height instead, but this forces the menu to always be this tall
*/
* html .ui-autocomplete {
height: 100px;
}
My solution could be closing the widget even if focus is transferred to widget itself and not the input element?
Any ideas how to modify this code so it behaves this way?
Based on issues with the various click and mouse events for the automplete widget, I came up with this: jsFiddle example.
jQuery:
var input = $('#txtComplete');
var data = [];
var isOpen = false;
function _init() {
for (var idx = 0; idx <= 100; idx++) {
data.push('item: ' + idx);
};
input.autocomplete({
source: data,
minLength: 0,
open: function(event, ui) {
isOpen = true;
},
select: function(event, ui) {
isOpen = false;
}
});
}
function afterInit() {
var button = $("<button type='button'> </button>").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
}).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon").click(function(event) {
input.focus();
if (isOpen) {
input.autocomplete("close");
isOpen = false;
} else {
input.autocomplete("search", "");
event.stopImmediatePropagation();
}
});
}
$(window).click(function() {
input.autocomplete("close");
isOpen = false;
});
$(function() {
_init();
afterInit();
});
The problem is because of a work around in jquery ui autocomplete. There is a mousedown event setup to close the menu under certain conditions. In one of the conditions it checks to see if the item that raised the mousedown is part of the autocomplete widget. If not, it closes the menu. Since you are tacking on combobox behaviour and your button is not part of the autocomplete widget, a click on the button is closing the menu because of this event.
You can see the offending condition with the reason why it is there starting at line 205 in the autocomplete source on github. It is probably worth raising the issue on the jquery ui forums since their combobox demo has this bug too.
UPDATE
This replacement event is based off of jquery-ui 1.8.18. This event has changed and will very likely change again. You might need to update this code manually with each release if you go this route.
You can patch the mousedown event to not close the menu if it was your combo button that was clicked by running the following after you create your autocomplete (jsfiddle demo).
var input = $('#combotextbox').autocomplete(/*options*/);
input.data('autocomplete').menu.element.unbind('mousedown').mousedown(function(event) {
var self = input.data('autocomplete');
event.preventDefault();
// clicking on the scrollbar causes focus to shift to the body
// but we can't detect a mouseup or a click immediately afterward
// so we have to track the next mousedown and close the menu if
// the user clicks somewhere outside of the autocomplete
var menuElement = self.menu.element[0];
if (!$(event.target).closest(".ui-menu-item").length) {
setTimeout(function() {
$(document).one('mousedown', function(event) {
var t = $(event.target);
if (event.target !== self.element[0] && event.target !== menuElement && !$.ui.contains(menuElement, event.target) && !t.hasClass('ui-combo-trigger') && !t.parent().hasClass('ui-combo-trigger')) {
self.close();
}
});
}, 1);
}
// use another timeout to make sure the blur-event-handler on the input was already triggered
setTimeout(function() {
clearTimeout(self.closing);
}, 13);
});
This removes the current mousedown event and then adds it back in with an added check to see if the element that triggered the event or its parent (button clicked or ui-icon inside the button is clicked) has a class ui-combo-trigger.
The code to create your button is relatively unchanged. We just need to add the new class ui-combo-trigger.
var button = $("<button type='button'> </button>").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
}).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon ui-combo-trigger").click(function(event) {
// when i put breakpoint here, and my focus is not on input,
// then this if steatment is false????
if (input.autocomplete("widget").is(":visible")) {
input.autocomplete("close");
return;
}
// work around a bug (likely same cause as #5265)
$(this).blur();
// pass empty string as value to search for, displaying all results
input.autocomplete("search", "");
input.focus();
event.stopImmediatePropagation();
});
Try this jsfiddle. I think it ll help you.
var input = $('#txtComplete');
var data = [];
var openCheck = false;
function _init() {
for (var idx = 0; idx <= 100; idx++) {
data.push('item: ' + idx);
};
input.autocomplete({
source: data,
minLength: 0,
open: function(event, ui) {
openCheck = true;
},
select: function(event, ui) {
openCheck = false;
}
});
}
function afterInit() {
var button = $("<button type='button'> </button>").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
}).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon").click(function(event) {
if (openCheck) {
input.autocomplete("close");
openCheck = false;
} else {
input.autocomplete("search", "");
}
});
}
$(function() {
_init();
afterInit();
});
Brian explained the problem very good. With jquery ui 11 you can do something like:
wasOpen = false;
$button
.mousedown(function() {
wasOpen = input.autocomplete( "widget" ).is( ":visible" );
})
.click(function() {
input.focus();
// Close if already visible
if ( wasOpen ) {
return;
}
see example at http://jqueryui.com/autocomplete/#combobox