I am using select2 for one of my dropdownlists and I have a jquery event listener for when a selection is made. Basically, once a selection is made, that selection is then populated into an ul element. The text part of the li element in the ul will have a button for removing that option from the ul. If that option is removed from the ul then it is populated back into my select list.
Here is my jQuery for adding selected options to the ul:
$("#My-DDL").on("select2:select",
function (evt) {
console.log(evt.params);
$("#My-UL-Element").append("<li class='list-group-item list-group-item-info text-dark' data-id='" +
evt.params.data.id +
"' ><small>" +
evt.params.data.text +
"</small> <button type='button' class='close remove-button'>×</button></li>");
$("#My-DDL option[value='" + evt.params.data.id + "']").remove();
$("#My-DDL").val("").change();
});
Here is my jQuery for when an option is removed from the ul element and populated back into My-DDL:
function removeCapability() {
$("#My-UL-Element").on("click",
".remove-button",
function () {
console.log($(this).parent().text());
console.log($(this).parent().data("id"));
var elementId = $(this).parent().data("id");
$("#My-DDL").append(new Option($(this).parent()
.text(),
elementId)); // add item back to dropdownlist
/* sort the dropdownlist options back to the original way */
var selectList = $("#My-DDL option");
selectList.sort(function (a, b) {
a = a.value;
b = b.value;
return a - b;
});
$("#My-DDL").html(selectList);
/* End of Sort */
$(this).parent().remove(); // remove item from ul element
});
}
Now, my problem deals with the second part of when an item is removed from the ul and populated back into the select. When an item is removed.. the $(this).parent().text() includes the × from the button.. which I can understand because it is the text of the that element, but how do I ignore the button text?
UPDATE
The question above can be answered by focusing on the text inside the small element. Let me rephrase with a different scenario.. how would I accomplish this if the text didn't have a small element?
$("#My-DDL").on("select2:select",
function (evt) {
console.log(evt.params);
$("#My-UL-Element").append("<li class='list-group-item list-group-item-info text-dark' data-id='" +
evt.params.data.id +
"' >" +
evt.params.data.text +
" <button type='button' class='close remove-button'>×</button></li>");
$("#My-DDL option[value='" + evt.params.data.id + "']").remove();
$("#My-DDL").val("").change();
});
Since you are removing the LI from the list in that case anyway, you could remove the button from the LI first, and then get the LI text content ...
But preferably, you would rather store the info you need in a custom data attribute or using https://api.jquery.com/data/, so that you can retrieve it again from there - so that the “pollution” of the text value by additional buttons etc. doesn’t matter any more.
That way you separate the actual data more from the presentation. Whatever else you might apply/add to that text shown in the LI at a later point won’t affect your script in that regard any more.
A quick vanilla JS function to get the text nodes within a parent, and concatenate them into one string:
function getText(el) {
return Array.from(el.childNodes).filter(e =>
e.nodeType == 3 // text node
).map(e =>
e.nodeValue
).join(" ");
}
console.log(getText(document.getElementById("demo")));
<div id='demo'>
Part 1
<button>Button!</button>
Part 2
</div>
Related
function newFunc(){
excuseDivs = " "
excuseArrayItem = excuse + " : " + "<span class='excuseDivTime'>" + endTime + "</span>";
excuseArray.unshift(excuseArrayItem)
excuseArray.forEach(function(excuse){
excuseDivs +="<div class='excuse-div'>"+excuse+"</div>"
})
I want to add a click listener to the div that this function creates. I want that click listener to get the text content of the span inside the div (class of excuseDivTime). Is there some way to get something like ($(this) > span).textContent ??
You can do this fairly easy in either plain JavaScript or stick with jQuery.
You need to query for the span under the clicked div.
If you are using jQuery, stick with jQuery method calls e.g. .text() instead of .textContent.
// Plain JavaScript
document.getElementById('MyDiv').addEventListener('click', function(e) {
alert(e.currentTarget.querySelector('span').textContent);
});
// jQuery Version
$('#MyDiv').on('click', function(e) {
alert($(this).find('span').text());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="MyDiv">Click me! <span>This text will show in an alert.</span></div>
Use find() or children()
$(document).on('click', '.excuse-div', function() {
console.log( $(this).find('.excuseDivTime').text() );
});
I have a Listbox that I need refreshed after a user selects an option in DropdownList.
Image is self explanatory. If one selects Department -> load list of departmetns in Listbox, if one selects Vat Rate refresh/load list of vat rates into the listbox below. (Default department list is loaded on page load). I am currently attempting this with trigger("chosen:updated") and having no luck refreshing listbox. Here is my code for that functionality.
$(function () {
$("#SelectFilter").change(function () {
if (document.getElementById('SelectFilter').value == 1) //dropdownlist
{
//empty listbox
$('#SelectItems').empty();
//append new list to listbox
$.each(data.Departments, function (index, element) {
$('#SelectItems').append('<option value="' + element.Value + '">'
+ element.Text + '</option>');
});
//refresh
$('#SelectItems').trigger("chosen:updated");
}
if (document.getElementById('SelectFilter').value == 2)
{
$('#SelectItems').empty();
$.each(data.VatRates, function (index, element) {
$('#SelectItems').append('<option value="' + element.Value + '">'
+ element.Text + '</option>');
});
$('#SelectItems').trigger("chosen:updated");
}
});
});
Recognising the selected value from the dropdownlist isnt an issue, that works fine. Listbox is currently not getting updated/refresh with new selection. And I cannot figure out were I am going wrong with this.
Try to put all your code for creating the list into a function, and then bind an event on chosing one of the selected items to call this function which generates a new list instead of using .trigger(). If you provide the HTML part as well, I'll post example code soon.
It's not clear to me if you have a problem with recognizing the selected value, or with populating the secondary select tag, or with the initial loading of the data. So I am providing an example of the three steps.
First, to detect the selected value, you need to provide a .change() handler and extract the selected value with .val(). Something similar to this:
$("#SelectFilter").change( function() {
var v = $(this).val();
if (v=="value1") {
} else if (v=="value2") {
} else {
}
});
then each of the changes detected has to refresh the contents of the secondary select tag, something as simple as this...
$("#SelectItems").empty();
['first item','second item','troisième'].forEach( (v,i) =>
$("#SelectItems").append($("<option>").val("item"+i).text(v))
);
}
And finally triggering the initial load should be as simple as triggering a change event
$("#SelectFilter").change();
I have put all the steps together in this fiddle https://jsfiddle.net/mud9u8yL/6/
For our shops we use the NiceSelect library, but we ran into an issue:
When we try to override a DOM element in the new selection-dropdown for our payment options, our changes get overriden right back. This only happens to the element called 'current', which I will explain down below:
CODE
//Make the generated select into a nice select
$('#payment_type').niceSelect();
//Add additional fees to items, where needed, and bind an event to those items
if(!additionalFeesAdded){
$('.nice-select.small.payment_type ul > li').each(function(i){
var af = additionalFeeArray[i];
if(af != "NaN" && af != "0.00"){
$(this).append("<label class='additional-fee selection'> + € " + af + "</label>");
$(this).on('click', function(){
$('.nice-select.small.payment_type .current').trigger('contentchanged');
});
}
});
//Hocus pocus to make the additional fee float to the right (TEST DATA)
$('.nice-select.small.payment_type .current').bind('contentchanged', function(){
var paymentType = "Method";
var additionalFee = "Fee";
console.log($(this).html()); //Returns DOM before change
$(this).html(paymentType + "<label class='additional-fee'>" + additionalFee + "</label>");
console.log($(this).html()); //Returns DOM after change
});
}
additionalFeesAdded = true;
DOM SETUP
<div class="nice-select small payment_type open" tabindex="0">
<span class="current">SELECTED OPTION APPEARS HERE</span>
<ul class="list">
<li data-value="" class="option selected focus">Select a payment type </li>
<li data-value="3" class="option">OPT.1<label class="additional-fee selection"> + € 0.60</label></li>
<li data-value="4" class="option">OPT.2</li>
<li data-value="6" class="option">OPT.3<label class="additional-fee selection"> + € 0.40</label></li>
<li data-value="27" class="option">OPT.4<label class="additional-fee selection"> + € 0.50</label></li>
</ul>
</div>
This is pretty much what's being done to make an additional fee float to the right. This works in the li items the library makes, but not the DOM element that shows the selected option.
I tried adding a custom event to mimic an onChange(), but the latter DOM printed to the console never makes it to the element itself:
How the element always comes back:
How it should be:
So in short: Something I try to manipulate doesn't want to get manipulated, and I don't know what's going wrong. Is anyone able to help me with/see the issue?
If more information is required, I am happy to oblige.
The nice select library replace .current text after option has been changed.
You need to call your handler after the library did its work.
So remove click binding in cycle and contentchanged handler.
And add click handler like this
$(document).on('click.nice_select', '.nice-select .option:not(.disabled)', function(event) {
$current = $('.nice-select .current');
var paymentType = "Method";
var additionalFee = "Fee";
console.log($current.html()); //Returns DOM before change
$current.html(paymentType + "<label class='additional-fee'>" + additionalFee + "</label>");
console.log($current.html()); //Returns DOM after change
});
I made a plunker with working example
I check the code but the following part does not work for me:
$current = $('.nice-select .current');
Then I change the .current to .selected and it returns the selected li element, maybe this is a change in the new version of nice-select.
I am replicating the functionality of a select/multiselect element and I'm trying to use this function to display the items which have been selected in the relevant container. I need to show all the values that have been selected in a comma-separated list, but it's currently only showing one selection (the last one made). It's also displaying the checkbox, background color, etc. of the list item selected instead of the checkbox value (i.e. value="Black").
I'm using this for a few multiselect form elements where I couldn't use the jQuery UI MultiSelect Widget because they needed to be styled in a very specific way (options displayed with background colors or images and spread out over several columns, etc.).
I've included the relevant code below, and I've posted a working example of the styled 'faux'-multiselect element here: http://jsfiddle.net/chayacooper/GS8dM/2/
JS Snippet
$(document).ready(function () {
$(".dropdown_container ul li a").click(function () {
var text = $(this).html();
$(".dropdown_box span").html(text);
});
function getSelectedValue(id) {
return $("#" + id).find("dropdown_box span.value").html();
}
});
HTML Snippet
<div class="dropdown_box"><span>Colors</span></div>
<div class="dropdown_container">
<ul>
<li><a href="#"><div style="background-color: #000000" class="color" onclick="toggle_colorbox_alt(this);" title="Black"><div class=CheckMark>✓</div>
<input type="checkbox" name="color[]" value="Black" class="cbx"/></div>Black</a>
</li>
<!-- More list items with checkboxes -->
</ul>
</div>
I've tried several other methods (including many of the ones listed here: How to retrieve checkboxes values in jQuery), but none of those worked with hidden checkboxes and/or the other functions I need to incorporate in these particular form elements.
well, to start with change click(..){..} in document.ready to
$(".dropdown_container ul li a").click(function () {
var text = $(this).html();
var currentHtml = $(".dropdown_box span").html();
var numberChecked = $('input[name="color[]"]:checked').length;
$(".dropdown_box span").html(currentHtml.replace('Colors',''));
if (numberChecked > 1) {
$(".dropdown_box span").append(', ' + text);
} else {
$(".dropdown_box span").append(text);
}
});
this will do the appending of text right.
however I couldn't understand the handling of images in the code.
Update, to handle just the value:
replace var text = $(this).html(); with
var text = $(this).find("input").val();
It might be easier to just grab all the values of the check boxes whenever the click event is triggered and then append the values to your span. Like http://jsfiddle.net/9w95b/
I would also suggest not putting the <input> tags inside your <a> tags.
UPDATE: A commenter told me to change some codes, this is the new code and its not working neither.
I'm creating a Facebook-Like chat. It gets the latest messages "Not Read" from a JSON file and it appends the text to an "UL" element vía "LI" into a box. If the box doesn't exist, it creates and attach the text. I want that when I click that div, it hides using margin-bottom negative, and when I click it again it shows by Margin-Bottom:0. Please help me since it's just not working.
function showChat(id){
$(this).animate({marginBottom : "0"}).removeClass("hidden_box").addClass("active_box").removeAttr('onclick').click(function(){
hideChat(Id);
});
}
function hideChat(id){
$(this).animate({marginBottom : "-270px"}).removeClass("active_box").addClass("hidden_box").click(function(){
showChat(Id);
});
}
function getOnJSON(){
//Creating Variables that will be used
var from;var to;var msg_id;var msg_txt;
//Getting the data from the json file
$.getJSON("/ajax/chat.json.php",function(data){
//Repeat for each result
$.each(data.notif, function(i,data){
//Getting a var to info
from = data.from;to = data.to;msg_id = data.id;msg_txt = data.text;
//check if div exists
if ($("#chat_"+from+"_lp").length === 0){
//If not, create the div
$("#boxes").append('<div id="chat_'+from+'_lp" class="chat_box hidden_box clickable_box"></div>');
//Add the senders name
$("#chat_"+from+"_lp").append('<div id="'chat_+from+'_nick" class="chat_name">'+from+'</div>');
//Add the chats UL
$("#chat_"+from+"_lp").append('<ul id="chat_'+from+'_txt" class="chat_txt"></ul>');
//Add the message text
$("#chat_"+from+"_lp").append('<li id="' + msg_id + '">'+ msg_txt+'</li>');
//Add event handler for each div
$('#chat_'+from+'_lp').click(function() {showChat(this);});
//If div exists just add the text
}else{
//Add the message text
$("#chat_"+from+"_txt").append('<li id="' + msg_id + '">'+ msg_txt+'</li>');
//Add event handler for each document
$('#chat_'+from+'_lp').click(function() {showChat(this);});
//Close If
}
//Close data for each item
});
//Close JSON
});
//Close Function
}
UPDATE 2: in order to stop making and appending things, I made an unique HTML string that is going to be appended.
new_chat_string = '<div id="chat_'+from+'_lp" class="chat_box hidden_box clickable_box"><div id="'chat_+from+'_nick" class="chat_name">'+from+'</div><ul id="chat_'+from+'_txt" class="chat_txt"><li id="' + msg_id + '">'+ msg_txt+'</li></ul></div>';
$("#boxes").append(new_chat_string);
use class instead of id
<div id="chat_sender_lp" class="chat_box hidden_box clickable_box sender-click"
then
$('.hidden_box.sender-click').live('click', function(){
$(this).slideToggle(500);
});
After:
$("#boxes").append('<div id="chat_'+from+'_lp" class="chat_box hidden_box clickable_box" ><div id="name">'+from+'</div><ul id="chat_'+from+'_txt" class="chat_txt"><li id="' + msg_id + '">'+ msg_txt+'</li></ul></div>');
Add the event handler for the inserted element:
$('#chat_'+from+'_lp').click(function() { showChat(this) })
"this" passes a DOM reference to itself.
Keep in mind that you're adding: <div id="name"> every time. IDs must be unique. Use a class name instead.
EDIT:
Appending to the DOM is really quite slow. It's actually more efficient to build up your HTML as a string and just insert it in one go. Also, you only really need to stick and ID on the wrapping element. Everything else can be derived from that using a jQuery selector. It helps you write much cleaner code.
Here's the string you need to append:
'<div id="chat_'+msg_id+'" class="chat_box hidden_box clickable_box">
<div class="chat_name">'+from+'</div><ul class="chat_txt"><li>
'+msg_txt+'</li></ul></div>'
If you wanted to select chat name later, you'd use: $('chat_1 .chat_name').html()
It also makes more semantic sense to hook up your click handler to an A tag. So you'd use:
$('#chat_'+msg_id).find('a').click(function() {showChat(this);});
The code is a lot cleaner and easier to follow this way. I hope this helps.