jQuery hover() and delegation - javascript

I'm creating an incremental search using jQuery, the rest of my code works fine, but when I'm trying to highlight only the element being hovered inside the search doesn't work, it starts highlighting all the others. Because the "p" tags are generated AFTER the HTML file is loaded in the browser, they need to be delegated like i wrote on the code.
How could i fix that?
$(document).on("mouseover", "p", function (e) {
e.target.classList.add("highlight");
});

You need to remove the highlight class from all other <p> elements before adding it to the element hovered on:
$(document).on("mouseover", "p", function(e) {
$("p").removeClass("highlight");
e.target.classList.add("highlight");
});
.highlight {
background: #FF0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>This is a paragraph with some text</p>
<p>This is a paragraph with some text</p>
<p>This is a paragraph with some text</p>
<p>This is a paragraph with some text</p>
<p>This is a paragraph with some text</p>

Related

Detect a word and addClass to body

The jQuery below detects the word first and third in any <p> text and adds a yellow or red background to it.
$(document).ready(function(){
$("p:contains(first)").css("background-color", "yellow");
$("p:contains(third)").css("background-color", "red");
});
<p>I'm the first sentence.</p>
<p>I'm the second sentence.</p>
<p>I'm the third sentence.</p>
<p>I'm the fourth sentence.</p>
JSFiddle: https://jsfiddle.net/3p0nmw4f/1/
However, instead of highlighting the text, I want to addClass to the body of the html document like this :
<body class="first">
or
<body class="third">
I know we can achieve this using $(document.body).addClass('first'); but I'm unable to put it together.
Please help.
You could search for the closest body HTML element.
You can do this by doing the following:
$(document).ready(function(){
$("p:contains(first)").closest('body').addClass('first');
$("p:contains(third)").closest('body').addClass('third');
});
Another possibility would be to simply search for the body element as follows:
$(document).ready(function(){
if ($("p:contains(first)"))
$("body").addClass("first")
if ($("p:contains(third)"))
$("body").addClass("third")
});
Source: https://jsfiddle.net/fk05dabw/

Optimal way to retrieve HTML nodes having text using JavaScript/JQuery

How to get all the HTML nodes having text in an optimal way without having to loop through every node?
In other words, grab all HTML nodes having visible text.
For example, if I have a dom as below
<div>
<span>Hello This is a Text Span</span>
<div>
<p> This is a text Paragraph</p>
<button> This is Button Label</button>
</div>
<div> This is also a visible text</div>
</div>
I should select
span having text Hello This is a Text Span
p having text This is a text Paragraph
button having text This is Button Label
div having text This is also a visible text
The outermost div in the above example doesn't have text of its own so should not be part of the result.
Edit: What problem am I trying to solve?
The framework I use escapes HTML characters in labels of fields, buttons, headings etc.
For example: < is converted to & lt;'
So I am trying to write a client side code which triggers after the page is completely rendered which will unescape all the HTML texts to a readable format.
Any help will be appreciated.
Thanks in advance
The DOM property holds a numeric code indicating the node's type; text nodes use the code 3, So you can find those text nodes by filtering them having nodeType 3.
Wrap your all nodes in a div by giving a class.
Select your content by it's class like this: $(".getTextNodes").contents();.
Filter contents having nodeType 3.
selectedElement = $(".getTextNodes").contents();
textNodes = selectedElement.filter(function() {
return this.nodeType === 3;
});
console.log(textNodes);
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<div class="getTextNodes">
<span>Hello This is a Text Span</span>
<div>
<p> This is a text Paragraph</p>
<button> This is Button Label</button>
</div>
<div> This is also a visible text</div>
</div>
Check this link out to read more.
I'm using just only vanilla js
My algorithm is just select all element that has no element inside it
It means select all element that has directly Text Node
let el = document.querySelectorAll('div,span,p,button');
var arr = [];
el.forEach(function(m){
if (m.querySelectorAll('div,span,p,button').length == 0){
arr.push(m)
console.log(m)
}
})
// console.log(arr)
<div>
<span>Hello This is a Text Span</span>
<div>
<p>This is a text Paragraph</p>
<button> This is Button Label</button>
</div>
<div>This is also a visible text</div>
</div>
Jsfidle link click here
There's no css selector to get your needs and looping is only the solution.

Is there a way to check an element's attribute when using Event Delegation?

Using Event Delegation, is there a way to check the element that was fired if it has a particular attribute or specifically a class or an ID?
<ul>
<li><button>Make the first paragraph appear</button></li>
<li><button>Make the second paragraph appear</button></li>
<li><button>Make the third paragraph appear</button></li>
</ul>
<div>
<p class="first">First paragraph</p>
<p class="second">Second paragraph</p>
<p class="third">Third paragraph</p>
</div>
Let's say all the paragraphs are hidden initially and clicking on the first button, the first paragraph appears and clicking on the second button, the first paragraph is hidden and the second paragraph is displayed and when the third button is clicked, the second paragraph is hidden while keeping the first paragraph hidden as well.
My solution so far was to make a event handler for each specific button and hide the other two paragraphs while only showing one. It works but if the number of elements increased, the event handlers needed for each one would increase too. Is there a better way to do this?
If the index of buttons and paragraphs are the same then you can make use of .index():
$('button').click(function() {
var idx = $(this).index('ul li button');
$('div p').eq(idx).show().siblings('p').hide();
});
Fiddle Demo
or you can use data-* attribute if the index are different:
<ul>
<li><button data-parapgraph="first">Make the first paragraph appear</button></li>
<li><button data-parapgraph="second">Make the second paragraph appear</button></li>
<li><button data-parapgraph="third">Make the third paragraph appear</button></li>
</ul>
<div>
<p class="first">First paragraph</p>
<p class="second">Second paragraph</p>
<p class="third">Third paragraph</p>
</div>
then apply .data() to retrieve the data-* attribute:
$('button').click(function() {
var parapgraph = $(this).data('parapgraph');
$('p.' + parapgraph).show().siblings('p').hide();
});
Fiddle Demo
I think if you can make sure the position of the button and the p to be displayed are the same then you can use an index based solution like
jQuery(function ($) {
var $ts = $('div > p');
$('ul button').click(function (e) {
$ts.hide().eq($(this).parent().index()).show()
})
})
Demo: Fiddle
I would rather use <a> instead of buttons and then use the href attribute for the identifying, and use id's for paragraphs
<ul class="link-list">
<li>Make the first paragraph appear</li>
<li>Make the second paragraph appear</li>
<li>Make the third paragraph appear</li>
</ul>
<div>
<p id="first">First paragraph</p>
<p id="second">Second paragraph</p>
<p id="third">Third paragraph</p>
</div>
$('.link-list').on('click','li > a',function(){
//id would be something like #first
var id = $(this).attr('href');
//we use it as a selector (you can also use $('div.classname').find(id);
var $paragraph = $(id);
// we show our desired paragraph and hide its siblings
$paragraph.show().siblings().hide();
// make sure the browser does not follow the link/anchor
return false;
});
Fiddler

Curious about hide().after("") in jQuery

I have some code at here:
html:
<body>
<p>This is a paragraph.</p>
<button>click me</button>
</body>
Javascript:
$(document).ready(function(){
$("button").click(function(){
$("p").hide().after('<p>hello world</p>');
});
});
Actually, I've using JQuery 2.0.2 also.
In my understanding, When I click the button click me, "<p>This is paragraph<p>" will be replaced by <p>hello world</p>.
The first click is successful. However, many hello world with the growth rate of progression show after the first hello world shown. For example:
I've checked the source code by firebug, and find it is:
<p style="display: none;">This is a paragraph.</p>
<p>hello world</p>
<p style="display: none;">hello world</p>
<p>hello world</p>
<button>click me</button>
Why the first <p>hello world</p> wasn't be replaced by the new one?
Doesn't it suppose to show one p tag only?
That's cause you're creating paragraphs
<p>hello world</p>
and on every click the $('p') is a collection of all p elements on your page.
The more paragraphs you have... more appends. live demo - issue example
An element, even if set to display:none using .hide(), is still present in your document..
What you're up to is probably one of the following:
$("button").click(function(){
$("p").html('hello world');
});
$("button").click(function(){
$("p").text('hello world');
});
$("button").click(function(){
$("p").replaceWith('<p>hello world</p>');
});
$("button").click(function(){
$("p").after('<p>Hello world</p>').remove();
});
If only you want to change the text you an do like this
$(document).ready(function(){
$("button").click(function(){
$("p").html('hello world');
});
});
JS FIDDLE
after('<element/>') means generate an element and insert it after the selected element(s), you are generating and inserting an element after all the selected p element(s), on the first click you are adding 1 element, on the second click 2 elements and so on, because after each click there are more than one p elements. after doesn't replace anything.
Well, there is nothing surprising that is happening here. Actaully that is what should happen, since you are adding <p> tag after hiding the first <p> <p>This is paragraph<p>.
So your first click ends up having two <p> tag in the DOM and further clicks, adding more <p> tags. hide() does not removes the elements form the DOM; it just changes its display property. You can use replaceWith() or remove() to remove the first <p>, if you want this to work, as you needed.
$("p").after('<p>hello world</p>').remove(); //remove the selected `<p>` tag after `<p>is appended.</p>`
or
$("p").replaceWith('<p>hello world</p>');
It happens because you adding new p element after each p tag in document (even after hidden).

Select different elements with wrapAll — jQuery

I am trying to wrap both a h1 tag and multiple p tags into one div using jQuery wrapAll.
Here is my HTML:
<h1>Title</h1>
<p>This is a paragraph</p>
<p>This is another paragraph</p>
<div class="img"></div>
And my jQuery:
$('h1').wrapAll('<div class="first-col" />');
$('.img').wrapAll('<div class="second-col" />');
And a JSFIDDLE.
At the moment, I can only wrap around the h1 tag, or both the h1 and p tags separately. I want them both in the one first-col div.
Does anyone know how to do this?
Try
$('h1').nextUntil('div.img').addBack().wrapAll('<div class="first-col" />');
Demo: Fiddle
Have you tried to just add p inside the selector:
$('.postwrap').each(function(){
$(this).find('h1, p').wrapAll('<div class="first-col" />');
$(this).find('.img').wrapAll('<div class="second-col" />');
});

Categories