JQuery contains not working multiple li - javascript

I´m trying to detect if an element it´s already appended into the DOM using $contains
var isAlreadyAppended = function (key) {
return ($.contains($('#allBellMessageId'), $("#" + key)));
};
var test= function(){
if(!isRepeated('a')){
//Append into DOM
};
if(!isRepeated('b')){
//Append into DOM
};
if(!isRepeated('c')){
//Append into DOM
};
if(!isRepeated('a')){
//Append into DOM
};
}
And adding the keys, a,b,c,a still is returning false, false, false, false.
And the html code generated is this one
<li id="bellMessagesId" class="dropdown notifications">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<ul id="allBellMessageId" class="dropdown-menu bellMessage-dropdown-menu">
<div class="col-xs-12">
<li id="a" class="col-xs-12">
<li id="b" class="col-xs-12">
<li id="c" class="col-xs-12">
<li id="a" class="col-xs-12">
</ul>
</li>
<li>
And the render is 4 messages, a,b,c,a.
What I´m doing wrong?.
Regards.

isRepeated()does not return anything, it just executes. Because its not returning anything, it will return undefined, so when you check it will say undefined and evaluate to false. So try this:
var isRepeated(key) = function(key){
return $.contains($('#fooElements'), $("#" + key))
};
Apart from that, I'm not very familiar with $.contains, so you could try the following:
var isRepeated(key) = function(key){
return $('#fooElements').find("#" + key).length ? true : false;
};
I use this all the time to check if something exists and it works like a charm.

From jQuery documentation
The first argument of .contains() must be a DOM element, not a jQuery object or plain JavaScript object. Try running a loop and using
$.contains($('#fooElements')[i], $("#" + key)[0])
or something like that.

I think your issue is one related to Event Delegation if you're looking for elements that have been appended to the DOM.
Anything after the DOM is loaded is not registered. So if you're appending an element to something, you'll have to check its parent element first.
From the docs:
$( "#list" ).on( "click", "a", function( event ) {
event.preventDefault();
console.log( $( this ).text() );
});
If the <a> tag was appended to the #list element, you first need to check the #list element and then check for the a tag.

Related

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

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.

call function with parameter unobstrusively

I have a functional code, but would like to improve it for the sake of learning.
I did quite a lot of research and only found a solution using jQuery, but as i'm still a beginer I would like to make in in plain js first.
[How do I get HTML button value to pass as a parameter to my javascript?
Basically, I have a list, and I want each entry of this list to call a function with a given parameter, being a natural number.
Among the classic / obstrusive techniques we have:
<li><a href="#" id="0" class="myClass" onclick="return myFunction(0);" >clickMe</a></li>
<li><a href="#" id="1" class="myClass" onclick="return myFunction(1);" >clickMe</a></li>
...
or
<li>ClickMe</li>
<li>ClickMe</li>
...
and
<li><button class="myClass" onClick="return myFunction(0);">ClickMe</button></li>
...
wich indeed call myFunction() with the parameter set to 0, 1 and so on.
But I've read that it wasn't recomended to do so as
I'm using the <a> tag while I'm not intending to link anywhere.
it mixes HTML and Javascript and that separation of concern is the way to go whenever possible
Then there is the unobstrusive way
<li><button id="0" class="myClass">clickMe</button></li>
completed by
document.getElementById("0").onclick = function (){myFunction()}
This works, but I can't find a way to set my parametter.
If, for instance, I add a value="0" attribute to my button, or myVar="0", I can't use value as a variable as it isn't declared, and it doesn't set the new value of myVar, thus myFunction is called with the wrong parameter being myVar="myVarPreviousValue"
Using GetElementsByClassName : EDIT: updated
Previously we used document.getElementById, however this may be very inconvinient if the list is long as we would have to create an event listner for every button. In such context, the use of document.getElementsByClassName seems appropriate.
As pointed by epascarello there's a nice explaination for the use of this method here Document.getElementsByClassName not working.
However this thread can be completed by precising how to get a variable value that is set in the elements of a given class in order to call a function with a given parameter
Bottom line question
How to, unobstrusivelly, call a function with a given parameter when the user click on some html content that have a given class (could be a <li>, <button>, <span>, <div> as you think is best)
Thank's in advance
J.
Edit : updated the question related to the use of getElementsByClassName
Then there is the unobstrusive way
<li><button id="0" class="myClass">clickMe</a></li>
completed by
document.getElementById("0").onclick = function (){myFunction()}
(Side note: You have <button ...></a> there, probably meant </button> at the end.)
In that specific case, just
document.getElementById("0").onclick = function (){ myFunction(0); };
// ------------------------------------------------------------^
...but I'd always advocate addEventListener instead, so the code plays nicely with others:
document.getElementById("0").addEventListener("click", function (){ myFunction(0); }, false);
(If you have to support obsolete browsers like IE8, this answer has a cross-platform hookEvent you can use instead of addEventListener.)
If you want to use the same handler and put the argument on the element, you can use the id or a data-* attribute:
<li><button id="0" data-value="0" class="myClass">clickMe</button></li>
completed by
document.getElementById("0").addEventListener("click", myFunction, false);
then
function myFunction() {
var parameter = this.getAttribute("data-value");
// or var parameter = this.id;
// ...
}
Here's an example using querySelectorAll to handle all button elements with a data-value attribute, and showing the data-value attribute when clicked:
var buttons = document.querySelectorAll("button[data-value]");
Array.prototype.forEach.call(buttons, function(btn) {
btn.addEventListener("click", handler, false);
});
function handler() {
console.log("Value: " + this.getAttribute("data-value"));
}
<button type="button" data-value="one">I'm 'one'</button>
<button type="button" data-value="two">I'm 'two'</button>
<button type="button" data-value="three">I'm 'three'</button>
<button type="button" data-value="four">I'm 'four'</button>
Side note: While it's valid HTML, I would generally avoid starting an id value with a digit, because although they work with getElementById, they're awkward to use in CSS selectors (#0 is invalid, for instance).
Since it got reopened, I will answer.
There is no getElementByClassName there is a getElementsByClassName. You can not just bind to the collection directly. You would need to loop over the live html collection to add the events.
var anchors = document.getElementsByClassName("myClass");
for (var i = 0; i < anchors.length; i++) {
anchors[i].addEventListener("click", function(e) {
console.log(this.getAttribute("data-id"));
});
}
<ul id="myList">
<li>ClickMe</li>
<li>ClickMe</li>
</ul>
The easy answer is event delegation, one click event on the parent element, look at the event object for what was clicked and you have the element. Read the data attribute or id and you have the number.
var list = document.getElementById("myList");
list.addEventListener("click", function(e) {
console.log(e.target.getAttribute("data-id"));
});
<ul id="myList">
<li>ClickMe</li>
<li>ClickMe</li>
</ul>
If you have a predefined function, you can do
var elements = document.querySelectorAll(".myClass");
for (var i=0;i< elements.length;i++) {
elements[i].onclick = myFunction;
}
and use a data-attribute to pass the data or this.id if that is enough
function myFunction(e) {
e.preventDefault(); // cancel click
e.stopPropagation(); // cancel event bubbling
console.log(this.id, this.getAttribute("data-val")||this.value);
}
window.onload = function() {
var elements = document.querySelectorAll(".myClass");
for (var i = 0; i < elements.length; i++) {
elements[i].onclick = myFunction;
}
}
<ul>
<li>clickMe</li>
<li>clickMe</li>
</ul>
<ul>
<li><button type="button" id="but0" value="value 0" class="myClass">clickMe</button></li>
<li><button type="button" id="but1" value="value 1" class="myClass">clickMe</button></li>
</ul>
<ul>
<li id="link0" data-val="value 0" class="myClass">clickMe</li>
<li id="link1" data-val="value 1" class="myClass">clickMe</li>
</ul>

RactiveJS Should Target The Element Triggering Proxy Event, Not It's Children

I'm trying to add an active classname to the li that is clicked on. Showing that it's selected.
My template:
var legCatagoryTemplate = "<ul>{{#legs:i}}<li><a href='#' on-click='selectCategory:{{this}},{{i}}' data-id='{{i}}'><figure><div class='imgWrapper'><img src='{{preview}}'></div><figcaption><h4>{{name}}</h4><p>W: {{width}}" H:<span></span>: {{material}}</p></figcaption></figure></a></li>{{/legs}}</ul>";
How its called:
var legCategoryView = new Ractive({
el: "#catalog",
template: legCatagoryTemplate,
data: response_from_ajax
});
How I'm handling the event:
legCategoryView.on('selectCategory', function ( event, self, index ){
console.log(event.target, self, index);
}
What I've found:
event.target is the element inside of the a that was clicked (eg div.imgwrapper, figcaption)
Non Ractive behaves similarly: click event on a div should not be triggered by it's children
What is a good solution to targeting the element with the on-click proxy object?
You might just traverse the DOM and find the li element but that can cause troubles in certain situations. If you call ractive.set('legs', new_data), Ractive will reuse the existing nodes, so your class will remain there. There are several solutions for this problem (the third is probably the best):
Use ractive.merge() instead of ractive.set().
Use splice() and push() instead of ractive.set().
Change your template and let Ractive manage the class:
<ul>
{{#legs:i}}
<li class="{{#.active }}active{{/}}">
<a href='#' on-click='selectCategory:{{this}},{{i}}' data-id='{{i}}'>
<figure>
<div class='imgWrapper'><img src='{{preview}}'></div>
<figcaption>
<h4>{{name}}</h4>
<p>W: {{width}}" H:<span></span>: {{material}}</p>
</figcaption>
</figure>
</a>
</li>
{{/legs}}
</ul>
ractive.on('selectCategory', function ( e ) {
ractive.set(e.keypath + '.active', true);
});
I just had the idea of using jQuery to traverse up the dom with $.closest() like this
legCategoryView.on('selectCategory', function ( event, self, index ){
$(event.original.target).closest('li').addClass("active");
}
That works actually.

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()

jQuery save context onclick

Is there anyway to bind an click listener on a child of an element, while still pointing the $(this) context to a fixed parent of that child?
For example so lets just say I had a page -
HTML:
<p><div data-important="idthatisneeded1" class="fixedClass">
<div id="dynamicallygeneratedfirstchild">
<div id="dynamicallygeneratedsecondchild">
<a class="clickabblelinkfromtheparent" href="#">Link1</a>
</div>
</div>
</div></p>
<p><div data-important="idthatisneeded2" class="fixedClass">
<div id="dynamicallygeneratedfirstchild">
<a class="clickabblelinkfromtheparent" href="#">Link2</a>
</div>
</div></p>
I want to grab the values of data-important from .fixedClass whenever .clickabblelinkfromtheparent is clicked, without using .parent().parent() or .parent() since they're both unreliable -
JS:
$(".fixedClass .clickabblelinkfromtheparent").on("click",function(){alert($(this).parent().parent().data("important"));return false;});
http://jsfiddle.net/zcdSw/
I've also tried:
$(".fixedClass .clickabblelinkfromtheparent").on("click",function(){alert($(this).context(".fixedClass").data("important"));return false;});
http://jsfiddle.net/zcdSw/1/
$(".clickabblelinkfromtheparent", ".fixedClass").on("click",function(){alert($(this).data("important"));return false;});
http://jsfiddle.net/Q8a67/
and
$(".clickabblelinkfromtheparent", ".fixedClass").on("click",function(){alert($(this).context);return false;});
http://jsfiddle.net/Q8a67/1/
None of which seems to work.. So how exactly is this achievable with jQuery?
are you trying something like this? jsfiddle: http://jsfiddle.net/zKp3P/
$(function(){
$('.clickabblelinkfromtheparent').on('click', function(){
//$(this).closest('.fixedClass').data('important');
alert($(this).closest('.fixedClass').data('important'));
});
});
$('.clickabblelinkfromtheparent').on('click', function(){
alert($(this).closest('.fixedClass').data('important'));
});
To retrieve the first data-important attribute value of an ancestor in the DOM tree, you can tree something based on this snippet :
function searchDataInParentAxe($child, key) {
var parent = $child.parent();
return parent.data(key) || searchDataInParentAxe(parent, key);
}
$(".clickabblelinkfromtheparent").on("click", function () {
alert(searchDataInParentAxe($(this), 'important'));
return false;
});
http://jsfiddle.net/zoom/2mhSQ/
Note that with this method you don't need the fixedClass anymore.

Categories

Resources