niceselect JS: How to manipulate 'current' element on change? - javascript

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.

Related

Attach different functions to dynamically created card

I have a card list that is being created by looping through some JSON data which is stored on Firebase. Each card is split in two parts: "overviewCardInfo" and "overviewCardOptions".
I would like to make it so that when the options part is clicked, a function is called (in this case a .toggleClass()) and when the info part is clicked, the title of that card is displayed somewhere else.
So far I have been unable to achieve either effect: The title of the card is nowhere to be seen and the toggleClass() either affects the div with class ".overviewCardOptions" or affects all cards rather than just the one clicked.
This is what the JSON array I am taking from Firebase to generate the cards looks like:
[{"name":"Push Ups", "duration":3, "break":3},{"name":"Squats", "duration":3, "break":3},{"name":"Running in Place", "duration":3, "break":3}]
JavaScript (some jQuery):
// Compile Routine Overview List.
var obj = JSON.parse(localStorage.exercise); // The JSON shown above
obj.forEach(function(exercise)
{
$("#overviewList").append("<li><div class='overviewCard'><div class='overviewCardInfo'>\n\
<h3>" + exercise.name + "</h3><p>" + exercise.duration + " sec.</p><p id='right'>Break: " + exercise.break + " sec.</p>\n\
</div><div class='overviewCardOptions'><img src='images/thrash.png' width='23' alt='' /></div></div></li>");
});
$(document).on("click", ".overviewCardInfo", function() // Attach event handler to document, as cards are generated after other elements on page.
{
$("#overviewSpecifier").css("display", "block"); // Works fine.
$("#infoP").text($(this).text()); // Shows all text contained in card, of course, how do I target the h3 tag specifically? jQuery API docs not helping me understand atm.
});
$(document).on("click", ".overviewCardOptions", function()
{
$(".overviewCard", this).toggleClass("toDelete"); // Fails.
});
HTML:
<ul id="overviewList"></ul>
<div id="overviewSpecifier">
<p id="infoP"></p>
</div>
Attach the click() event to the document instead to make it global.
$(document).on("click", ".overviewCardOptions", handleThrashClick);
Also, your object (in fact it's an array) shouldn't have quotation marks
var obj = "[ ... ]" should be var obj = [ ... ]
See demo here >> https://fiddle.jshell.net/9a457qzv/3/

How to retrieve id from selected item using "this"

I am new at jQuery/javascript. I tried some suggestions I found on this forum but so far it did not help.
THis is what I am trying:
When loading categories from a database ( using ajax) this HTML statement is added for each category:
$("#Links ul").append('<li id=\"cat' + i + '" data-catid=' + i + '>' + categorie_tekst[1] + '</li>');
Using F12 I see that the lines are correctly added.
E.g. <li id="cat3" data-catid="3">Seafood </li>
Next step is selecting a category in the screen and retrieve the products of this category using the value set for data-catid.
I have been told that I could "this.id" but so far no luck. Displaying the value of this.id with alert returns the correct value but for some reason I can't use it.
When I add (#cat3).attr(“data-catid”) in the code it works. But different options like these did not work:
("#cat"+ this.id).attr(“data-catid”)
(this).attr(“data-catid”)
var x = $(this).id();
var rest = x.substr(4, 1);
Everything with "this" creates error : Uncaught TypeError: ("#cat" + this.id).attr is not a function...
Trying to display any of these options does not give any output (not even a popup when I set an alert)
Any help would be appreciated!
You are loading dynamic values. Please use Event Delegation. And the $.one() binds the event once.
You need to add this in your ready function.
$(document).ready(function () {
$("#Links ul").one("click", ".cat", function(){
alert($(this).data('catid'))
});
});
To get the IDs of the elements, use $(this).attr("id") or $(this).prop("id") (latest jQuery) instead of this.id, as sometimes, it might return the jQuery object.
As you are creating elements like
$("#Links ul").append('<li class="cat" id=\"cat' + i + '" data-catid=' + i + '>' + categorie_tekst[1] + '</li>');
create elements using jQuery
$("#Links ul").append( $('<li></li>', {
class: "cat",
id: "cat" + i,
data-catid: i,
text: categorie_tekst[1]
});
As you are creating elements dynamically use Event Delegation. You have to use .on() using delegated-events approach.
$(document).ready(function () {
$("#Links ul").on(event, ".cat", function(){
alert($(this).data('catid'))
});
});

Accessing a specific li within a ul

After looking at past examples and source code I have made, I can't seem to work out accessing a specific <li><a>the value in this</a></li> based on a parameter sent in.
Mockup:
<ul class="selectBox-dropdown-menu selectBox-options size-dropdown mediumSelect footwear" style="top: 309px; left: 34px; display: none;">
<li class="" style="display: none;"><a rel=""></a></li>
<li class="size-not-in-stock"><a rel="3096786:6"> 6</a></li>
<li class="size-not-in-stock"><a rel="3096787:6.5"> 6.5</a></li>
<li class=""><a rel="3096788:7"> 7</a></li>
<li class="selectBox-selected"><a rel="3096789:7.5"> 7.5</a></li>
<li class=""><a rel="3096790:8"> 8</a></li>
<li class=""><a rel="3096791:8.5"> 8.5</a></li><li><a rel="3096792:9"> 9</a></li>
<li><a rel="3096793:9.5"> 9.5</a></li><li><a rel="3096794:10"> 10</a></li>
<li><a rel="3096795:10.5"> 10.5</a></li><li><a rel="3096796:11"> 11</a></li>
<li><a rel="3096797:11.5"> 11.5</a></li><li><a rel="3096798:12"> 12</a></li>
<li><a rel="3096799:12.5"> 12.5</a></li><li><a rel="3096800:13"> 13</a></li>
<li><a rel="3096801:14"> 14</a></li><li><a rel="3096802:15"> 15</a></li></ul>
</ul>
Here is what I am trying to get. Let us say that a user puts in a value of 7, well than it should find the corresponding <li><a></a></li> that contains the number 7 and click it.
My troubles are with finding that value inside this, I know I need to use find within the <ul> but what stumps me is based on a value.
UPDATE:
I just want to make clear that, this is something that is going to be an auto process so I am trying to make it so I don't have to do anything except load the page.
You need something like
var test = "the content to seek";
$('ul.footwear').find('a').filter(function(idx, el){
return $.trim($(this).text()) == $.trim(test);
}).closest('li').trigger('click')
Demo: Fiddle
There is no need to loop through and read the innerHTML of every element like all of the other solutions appear to be doing. You can just do it with a selector.
Since the rel attribute seems to have the data you are after at the end :size, you can use use :has() and ends with $= selectors to get the lis you are after.
var num = 7;
var elems = $(".footwear li:has(a[rel$=':" + num + "'])");
console.log(elems.length);
And if you want to click it, than you call .click() or .trigger("click")
function findAndClick (size) {
var elem = $(".footwear li:has(a[rel$=':" + size + "'])");
elem.trigger("click");
}
And to trigger it on the page load it would be something like
$(window).on("load", function() { findAndClick(7); } );
or document ready
$( function() { findAndClick(7); } );
Sad thing is, this solution appears to be great with a simple selector, but the performance can be subpar. If there is only going to be one element with the size, the best performance would be an each() loop and breaking out of it when you find the one element. No need to look at the other elements.
The best performing would be an each()
function findAndClick (size) {
var elem;
size = size.toString();
$('.footwear').find('a').each(function () {
if ($.trim($(this).text()) == size) { //compare the text
elem = $(this).parent(); //set the element that contains the link
return false; //exit each loop
}
});
if (elem) {
elem.trigger("click"); //fire click
}
}
For even better performance, eliminate the need to read the text of the element or use a ends with selector. Add a data attribute to the element.
<li data-size="7">
and than you would just use a selector
function findAndClick (size) {
$('.footwear li[data-size="' + size + '"]').trigger("click");
}
I would optimize this by making your structure better suited for these types of queries
<li id="10"><a rel="3096793:9.5"> 9.5</a></li><li><a rel="3096794:10"> 10</a></li>
Put an id on the li that corresponds to the value of the a tags.
Then you can do a simple $("#10") selector
While it's possible to make complex selectors based on filters etc, keep in mind that performance will not be great in general for non browser backed selectors (pseudo selectors)
Since you have an attribute rel that finish with the content, you can use this:
$('a[rel$="\:'+valueToMatch+'"]').parent()

How to edit one item sortable without use tablecontente

I have a sortable that it was loaded from JSON files.
This is a sortable's jquery http://jqueryui.com/demos/sortable
But I want to edit one item. The item before is inserted from the user. Looking the http://jqueryui.com/demos/sortable for example I want Item 3. How?
Now I want to edit one item for example Little birds, with JavaScript or jQuery, with one variable's string. This variable is inserted from a user in a textarea.(this i know).
How to edit the item's sortable using the variable???
I receive from a textarea the element name that I have to cancel.
<textarea></textarea>
I know how you analyze the list but edit (change) the name's item's sortable?
The HTML code of the sortable:
<div id="sortparam">
<ul style="" class="ui-sortable" id="sortable">
<li style="" id="1" class="ui-state-default"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Singular sensation</li>
<li style="" id="2" class="ui-state-default"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Beady little eyes</li>
<li style="" id="3" class="ui-state-default"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Little birds </li>
</ul>
</div>
Please, I don't want contenteditable
You either need to target text nodes or replace the full html of the element. We have no way to know how you intend to target which sortable gets edited.
Following solution stores the icon html, and updates full html of the element.
DEMO: http://jsfiddle.net/WZeMH/
/* no relationship given on how to determine which sortable to edit use second one*/
var whichSortable= 2;
/* define sortable element to edit */
var $sortableEl=$('#'+whichSortable);
/* store icon span html string*/
var iconSpan=$('<div>').append( $sortableEl.find('.ui-icon').clone() ).html();
$('textarea').keyup(function(){
var val=$(this).val();
$sortableEl.html( iconSpan + val);
})
Just an example:
Suppose, you've a textbox like following:
<input type="text" id="your_text">
Now you can bind keyup event to that textbox and using the text update sortable li's content.
var li = $('#sortable li#3'), // reference of li
originalVal = li.text(), // keep reference of original
// text(e.g Little birds)
iconSpan = li.find('span.ui-icon'); // take the span icon
$('#your_text').keyup(function() { // bind a keyup event
var val = $.trim( this.value ); // take new value on each keyup
if( val ) { // if new value entered
li.html( iconSpan + val ); // set new value to little birds
} else { // if text box is empty
li.html( iconSpan + originalVal ); // set original value
}
});
But I think you should have equal number of textbox to number of sortable elements and you may catch the value of textbox through other process.

click() for ClassName

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.

Categories

Resources