Pass this value from a list with javascript - javascript

I have the following list:
<ul>
<li onclick="populateComment(..this.)">very good </li>
<li onclick="populateComment(..this.)">not so good</li>
<li onclick="populateComment(..this.)">no t.....</li>
</ul>
and javascript:
function populateComment() {
document.getElementById("COMMENT").value = document.getElementById("COMMENT").value + 'THE_STRING_VALUE_FROM_THE_LIST';
}
So the idea is that I have a textarea, which I fill by clicking on the list.
So if I click on the first list, the text "very good" should be appended to the textarea. But I dont want to retype the text "very good" in my function, can I take it directly with something as an argument like this.value.. so it automatically takes the string between the <li> ...</li>
Thank you for your time.

You're looking for:
this.textContent || this.innerText
this.textContent is supported in all decent browsers, this.innerText is needed for older versions of IE.
Instead of duplicating the onclick handler multiple times, you can also bind a listener to the <ul> element:
// Replace <ul> with <ul id="populatefrom">
document.getElementById("populatefrom").onclick = function(ev) {
ev = ev || window.event; //Backwards compatible with IE
var target = ev.target;
if (target.nodeName.toLowerCase() == "li") {
document.getElementById("COMMENT").value += target.textContent || target.innerText;
}
};

If you don't have anything other than a simple bit of text, you could also use:
this.firstChild.nodeValue;
However if there are any nodes at all (bold, span, or anything else other than text... even an HTML comment) then this won't work and you need the textContent/innerText combo Rob W gave.

Sure you could do this with jQuery like so (didn't test this yet):
<ul>
<li class="populateComment">very good </li>
<li class="populateComment">not so good</li>
<li class="populateComment">no t.....</li>
</ul>
and your jQuery:
$('.populateComment').click(function(){
$('#textboxID').val($(this).html());
});
Working jsfiddle: http://jsfiddle.net/zEaam/

Related

Javascript targeting the first element only with a double click issue

I'm learning JavaScript at the moment (started 3 weeks ago at college) and i'm struggling to create a mobile menu whereby you click and that reveals or hides a hidden menu.
The issue here is that JS only targets the first class and not all of them. And you need to click twice to reveal the element that does work.
I would be very grateful for some guidance, and hopefully an expiation to help me understand the problem.
Thank you
<script>
const btn = document.querySelector('.navigation-main-mobile .menu-item-has-children');
const box = document.querySelector('.navigation-main-mobile .menu-item-has-children .sub-menu');
btn.addEventListener('click', function handleClick() {
if (box.style.display === 'none') {
box.style.display = 'block';
} else {
box.style.display = 'none';
}
});
</script>
<ul id="menu-primary-menu" class="navigation-main-mobile"><li>Text</li>
<li class="menu-item-has-children">Text
<ul class="sub-menu">
<li>Text</li>
<li>Text</li>
<li>Text</li>
</ul>
</li>
<li class="current-menu-item">Text</a></li>
<li class="menu-item-has-children">Text</a></li>
<ul class="sub-menu">
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
</ul>
</li>
</ul>
You have to find all nodes which match the selector. querySelectorAll is used for that. Then you must loop through all the nodes and set the event.
Also, you have to remove the wrong closing <li> tag (which messes up the selector) after </a>Text</a> in the second menu-item-has-children
const btns = document.querySelectorAll('.navigation-main-mobile .menu-item-has-children');
const boxs = document.querySelectorAll('.navigation-main-mobile .menu-item-has-children .sub-menu');
btns.forEach((btn, index) => {
btn.addEventListener('click', function handleClick() {
if (boxs[index].style.display === 'none') {
boxs[index].style.display = 'block';
} else {
boxs[index].style.display = 'none';
}
})});
.querySelector() returns the first element that matches the values passed.
You are getting the double click issue because you have not set a value for the style.display attribute. When you click it for the first time the browser realized that and set the attribute to none and then the second click performs the changes that you coded.
Remember to be somewhat explicit in what you want to code and do not assume that the computer is going to complete anything for you. Good Luck!

I need jQuery to perform a task if two conditions are true

I need some help to put an if statement together using jQuery. I want to change the logo on my site, if two conditions are true.
Here is some pseudo code, hopefully explaining what i want to archive:
if(li hasClass active and data-menuid is equal to 0033){
change logo...
}
Here is a simple example of the menu structure:
<div id="menu">
<ul id="menu-primary">
<li class="menuactive" data-menuid="0011">
Test1
<ul class="menu-dropdown">
<li data-menuid="0022">Test2</li>
<li class="active" data-menuid="0033">Test3</li>
</ul>
</li>
<li data-menuid="0044">Test4</li>
<li data-menuid="0055">Test5</li>
</ul>
</div>
You can check the combination of class and Attribute Equals Selector [name="value"]
if($('li.menuactive[data-menuid="0033"]').length){
//Your code to change the logo
}
You can use $.fn.filter()
Reduce the set of matched elements to those that match the selector or pass the function's test.
var listMeetingCondition = $('li').filter(function(){
return $(this).hasClass('menuactive') && $(this).attr('data-menuid') == "0033"
});
if(listMeetingCondition.length){
//Your code to change the logo
}
if($('li:has(.menuactive[data-menuid="0033"])').length){
change logo...
}
Another workaround:
var $target = $('li', '#menu-primary');
if( $target.hasclass('active') && $target.data('menuid') == '0033' ){
// change logo
}

Is there a better way to map menu click events to it's corresponding code

Okay, basically when I click a menu option a corresponding html is loaded into the content block of the layout page after executing some other set of codes, Now I have mapped each menu options' click event to it's corresponding set of codes to execute as follows;
<li onclick="changeContentTo('home');">About Us</li>
<li onclick="changeContentTo('rules');">Rules</li>
The mapping is done using switch case
case "rules":
/* something here */
$c.load("actsAndRules.htm" ) ;
break;
case "home":
/* something else here*/
$c.load("content.htm" ) ;
break;
I was wondering is there any better/proper method to do this?
I don't want to bind click event to a selector say $('.myLink').click() for example and no HTML5 coding, event handling will be the same as above
Basically what I want is to strip that mapping as much as possible out of the code and place it in a seperate obj ( which maybe resides in a seperate JS file ) something that will imitate a table/reference for mapping i.e. if I were to change a mapping I will only have to update that make-believe table.
Define a dictionary?
var $map = {'rules': 'actsAndRules.html', 'home': 'content.html'};
Now, instead of switch you can directly
$c.load($map[$arg]);
Assuming $arg is your function argument name.
EDIT
To run code only if any of the switch cases were satisfied, you can do something like this:
var $flag = false;
// your switch
...
case default:
$flag = true;
break;
...
// after switch
if (!$flag) {
// common code.
}
Try it like,
HTML
<li onclick="changeContentTo('home','content.htm');">About Us</li>
<li onclick="changeContentTo('rules','actsAndRules.htm');">Rules</li>
<script>
function changeContentTo(type,page){
$elesToHide=something;// let $elesToHide and $c are pre defined
if(!$elesToHide.is(":visible"))
$elesToHide.slideDown()
$c.load(page) ;
}
</script>
Try
<li class="nav-item" data-location="content.htm">About Us</li>
<li class="nav-item" data-location="actsAndRules.htm">Rules</li>
Then
$(function(){
$('.nav-item').click(function(){
if(!$elesToHide.is(":visible")){
$elesToHide.slideDown();
}
$c.load($this.data('location') ) ;
})
})
if(!$elesToHide.is(":visible"))
$elesToHide.slideDown();
this part seems to always be the same.
Just put it before your switch part.
Then, it only boils down to distinguish the url. You could just pass that directly:
<li onclick="changeContentTo('content.htm');">About Us</li>
<li onclick="changeContentTo('actsAndRules.htm');">Rules</li>
$c.load(parameterOfFunction ) ;
<li clickable load-link="content.htm">About Us</li>
<li clickable load-link="actsAndRules.htm">Rules</li>
$(function(){
$('clickable').click(function(e){
e.preventDefault();
$c.load($this.data('location') ) ;
});
});
<li id="l1" class="menuItem" data-item="home.htm" ></li>
<li id="l2" class="menuItem" data-item="actsAndRules.htm" ></li>
<li id="l3" class="menuItem" data-item="content.htm" ></li>
$(document).ready(function(){
$('.menuItem').click(function(e){
$c.load($(this).attr('data-item'));
});
});
Edit:
The HTML5 "data-" attribute will not be a problem even if you are not using HTML5. In ASP.Net the attributes are passed as-is to the client. Just leave the value blank where you don't need processing.
If you don't want to bind click on li, then you can bind it on the parent using event-delegation:
<ul id="list">
<li.....
<li.....
</ul>
$(document).ready(function(){
$('#list').click(function(e){
var $elem = $(e.target);
var content = $elem.attr('data-item');
if ($.trim(content)) {
$c.load(content);
}
});
});
Binding click to a selector is preferable over specifying onclick inline with each element.
You can easily wrap that snippet into a function and store it separately in external js file to be called from here.

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

find an element by style with jquery

How could I find an element in an HTML document using it's style properties?
here is an example:
HTML:
<ul>
<li style='z-index=1;'>e1</li>
<div style='z-index=8;'>div</div>
<li style='z-index=2;'>e2</li>
<li style='z-index=3;'>e3</li>
<li style='z-index=4;'>e4</li>
<li style='z-index=5;'>e5</li>
<ul>
The question is how do i select, for example..: the element <li> with z-index=4.
and how to select all div's with z-index=8 ...
If the style is set inline, you can use an attribute selector:
$('li[style*="z-index:4"]') //returns any li's with z-index = 4
see here. The advantage to this method is that it is very fast.
If the style is set via a stylesheet, you can access it this way:
var elem;
var elems = $("li");
for(var i=0; i<elems.length; i++) {
if($(elems[i]).css('z-index') == '4') {
elem = elems[i]; //assign elem we found
break; //exit loop early
}
}
Note Webkit browsers, (Safari, Chrome, etc), will not return a z-index value unless it is positioned as well. See this example
Also, for loop is still faster than .filter()
There isn't a style selector (how would it work, the style is a combination of inherited and explicitly stated rules), but you can filter (demo):
var things = $("li").filter(function() {
return $(this).css('z-index') == '4';
});
Now if you are using z-index to attach a piece of data to an HTML element you might have more luck using data attributes (cleaner, and searchable by Sizzle). One interpretation might look like this: (demo)
<div data-id='8'>div</div>
<ul>
<li data-id='1'>e1</li>
<li data-id='2'>e2</li>
<li data-id='3'>e3</li>
<li data-id='4'>e4</li>
<li data-id='5'>e5</li>
<ul>
<script>
alert($('[data-id=4]').text())
alert($('[data-id=8]').text())
</script>

Categories

Resources