How to find a not strong element inside of a paragraph - javascript

I have a paragraph like so:
<p>
<strong>Cost:</strong>
$1,500 - $10,000 (see below for details)
</p>
where I want to select first the strong text and then the not strong text.
I was trying the following:
$('p').not('strong').html()
and
$('p:not("strong")')
but it doesn't seem to be working.

If you need p elements that do not has strong in them, then you need to combine :has selector as well
$('p:not(:has(strong))')
for getting the text node text without strong contents:
$('p').clone().children().remove().end().text();//returns $1,500 - $10,000 (see below for details)
for getting the strong element text:
$('p strong').text();//return Cost:
Working Demo

Try this:
$("p").clone().children().remove().end().text();

Try
var elems = $.parseHTML($("p").html()).filter(function(elem, i) {
return elem.tagName === "STRONG"
|| elem.previousSibling !== null
&& elem.previousSibling.tagName === "STRONG"
});
// `elems[0]`:`STRONG` element , `elems[1]`:`#text` node;
// `$(elems).eq(0)`:jQuery object `$("strong")`,
// `$(elems).eq(1)`:jQuery object `$("text")`
console.log(
elems[0], elems[1],
$(elems).eq(0).text(), $(elems).eq(1).text()
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>
<strong>Cost:</strong>
$1,500 - $10,000 (see below for details)
</p>

Related

wrap text with div excluding all children

I have got a problem which I have been trying to solve for past 2 days, but couldn't solve it.
Problem:
I have a HTML as
<div class="string-box">
Text 1 wrap me
<span class="inner-span">Don't search me</span>
<span class="inner-span">Identical text</span>
Identical text
substring match
<span class="inner-span">Don't search substring match</span>
<br>
Finally wrap me
</div>
I want to wrap the content has below
<div class="string-box">
<span> Text 1 wrap me </span>
<span class="inner-span">Don't search me</span>
<span class="inner-span">Identical text</span>
<span>Identical text</span>
<span>substring match</span>
<span class="inner-span">Don't search substring match</span>
<br>
<span>Finally wrap me</span>
</div>
What I have tried
a) I firstly tried to search for string in the html and used string replace to replace the string with wrapped string.
The problem with this approach is that it replaces things in child too..
b) I tried cloning the node and removing all child , but then I am lost with the position of the string.
c) I tried the following code to replace textNode, but I ended up getting HTML
$('.string-box').contents().filter(function(){
return this.nodeType == 3;
}).each(function(){
this.nodeValue = '<span>'+this.nodeValue+'</span>';
})
Thanks in advance for you time & help..
Your code is close, however the nodeValue cannot contain HTML - hence why it gets encoded in your attempt. Instead you can wrap() the textNode in HTML, like this:
$('.string-box').contents().filter(function() {
return this.nodeType == 3;
}).each(function() {
$(this).wrap('<span />');
})
Working example
Update
Here's a fix for occasions where the nodeValue contains a line break, and you want to wrap each line of the node in its own span:
$('.string-box').contents().filter(function() {
return this.nodeType == 3 && this.nodeValue.trim();
}).each(function() {
var $spans = this.nodeValue.trim().split(/\r?\n/).map(function(i, v) {
return $('<span />', { text: i + ' ' });
});
$(this).replaceWith($spans);
})
Working example
Just do it only in an each and you're fine. No need for filter the elements first. And you can use jQuery to wrap the content in a span.
$('.string-box').contents().each(function() {
if( this.nodeType == 3 )
$(this).wrap('<span />');
});
Working example.
As you already have a jQuery answer, allow me to offer a plain JavaScript alternative:
var stringBoxes = document.querySelectorAll('.string-box'),
stringBoxArray = Array.from(stringBoxes),
newElement = document.createElement('span'),
clone,
children;
stringBoxArray.forEach(function(box){
children = Array.from( box.childNodes ).filter(function(child){
return child.nodeType === 3;
}).forEach(function (text) {
clone = newElement.cloneNode();
text.parentNode.insertBefore(clone, text);
clone.appendChild(text);
});
});

How to replace contents of parent element, ignoring children using jQuery

I have some HTML like this:
<div id="demo">
<p>
<span class="myClass">Word test should not be marked</span>
Word test should be marked<br />
</p>
</div>
How can I find a word ('test') inside the div excluding the span and mark it using jQuery? I have seen a lot of solutions in SO, etc. but none of them worked for me. FYI the code I'm trying to use is something like this :
var regex = XRegExp('test', 'i');
$('#demo').markRegExp(regex);
Get all child nodes using contents() and then iterate and update the text nodes.
$('#demo p')
.contents() // get all child nodes including text and comment nodes
.each(function() { // iterate over nodes
if (this.nodeType == 3) // check node is text node
$(this).replaceWith(this.textContent.replace(/test/g, '<span class="test">$&</span>')) // update the content and replace node with html content
});
.test {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="demo">
<p>
<span class="myClass">Word test should not be marked</span>
Word test should be marked
<br />
</p>
</div>
Here's a fiddly regex solution:
var html=$("#demo").html();
var elements=html.split(/(<[^>]+>)/); // split into tags and text
$.each(elements,function(i,e){
if(!e.match(/<[^>]+>/)){
if(elements[i-1]!==undefined){
if(!$(elements[i-1]).hasClass('myClass')){
elements[i]=elements[i].replace(/test/g,"<span class='highlight'>test</span>");
}
}
}
});
$("#demo").html(elements.join(''));
It would be much cleaner, though, to mark the text you do want to replace with a class, then you could just do:
$("#demo").find("span[class='myClass']").each(function(){
$(this).html($(this).text().replace(/test/g,"<span class='highlight'>test</span>"));
});
Working JSFiddle for both solutions.

How to replace text in multiple divs according conditional?

I need to replace the text of many divs, where according to the text of each div, put a text or another.
Example: If the text is 0, replace it with "no quota" and if it is different from 0, put "Yes it has".
Html code:
<div><p id="text">1</p></div>
<div><p id="text">0</p></div>
<div><p id="text">1</p></div>
JS code:
$('#text').text(function(){
if($(this).text() == '0')
{
$(this).text('No quota');
}
else
{
$(this).text('"Yes it has');
}
});
But only changes the first element and the others left with the same text.
As I can change the text for each item? Greetings from Chile.
you have multiple instances of the same id. each id needs to be unique - which is why its only affecting the first item. Change the id to a class and you will be able to change each p to the new text. Also spotted a typo in the last else text (correctedin the code below).
<div><p class="text">1</p></div>
<div><p class="text">0</p></div>
<div><p class="text">1</p></div>
$('.text').each(function(){
if($(this).text() == '0')
{
$(this).text('No quota');
}
else
{
$(this).text('Yes it has');
}
});
ID is to be used as unique identification number hence only first item changed. Change ID to CLASS should solve the issue.
There are two problems.
First, as others have noted, you should be using a class instead of ID if you want to match multiple elements.
Second, when you give a function argument to .text(), it receives the old text as an argument, and should return the new text rather than calling .html() within it. So it should be:
$('.text').text(function(i, oldtext) {
return oldtext == '0' ? 'No quota' : 'Yes it has';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div><p class="text">1</p></div>
<div><p class="text">0</p></div>
<div><p class="text">1</p></div>

jquery: separate tag and text

I have:
// $(this): <span class="class1"><span class="class2"></span> Some text</span>
$(this).children().each(function () {
console.log(this);
});
from the console I got only the span with class2, How I can get also the text? something like:
['<span class="class2"></span>', 'Some text']
$(this).children() will only return child nodes that are elements.
You'll want to use $(this).contents() to get all the nodes, including text nodes. :)
You can then filter these nodes to just get elements and text (see node types):
$(this).contents().filter(function() {
return (this.nodeType === 1) || (this.nodeType === 3);
})
notice the diference between .contents() and .children(). You require the former
While .children() return all available elements, .contents also return text and comments
you can get your output like this
jQuery(".class1").contents()

Iterate over every element and get only the content that is directly in the node

let's assume I have this code
<p>FirstLevelP
<span>SecondLevelSpan</span>
</p>
<p>FirstLevelP
<span>SecondLevelSpan
<p>ThirdLevelP</p>
</span>
</p>
Is it possible to iterate through every element that I have right now, but only get the content, that's in the direct node of it, modify the text and then have it in the original content?
Example, If I go through every $('p').each and would extract the text I would also get the text inside the span.
Basically this:
FirstelElement: FirstLevelPSecondLevelSpan
SecondElement: SecondLevelSpanSecondLevelSpanThirdLevelP
But I want to have it like this
FirstelElement: FirstLevelP
SecondElement: SecondLevelSpan
ThirdElement: FirstLevelP
FourthElement: SecondLevelSpan
FifthElement: ThirdLevelP
Is this possible?
In my research I already found this answer here
$("#foo")
.clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text();
But this would only solve half of my problems. I would still need to modify the text in the original content! Thanks in advance guys.
EDIT FOR CLARIFICATION
So basically, want I want to achieve is something like this:
For every element, I want to check if there is a dot at the end. If not I want to add one. I already managed to do this for headlines, like this:
foreach (pq($content)->filter(':header') as $headline) {
if (substr(pq($headline)->text(), 0, -1) != '.') {
$content = preg_replace('#(' . pq($headline) . ')#', pq($headline) . '.', pq($content));
}
}
The problem, as I stated, is, that when I have nested elements it would add the dot after the whole element, and not after each sub element if neccessary.
To work with my "assumed" code, it should look like this
<p>FirstLevelP.
<span>SecondLevelSpan.</span>
</p>
<p>FirstLevelP.
<span>SecondLevelSpan.
<p>ThirdLevelP.</p>
</span>
</p>
But unfortunatley, it currently looks like this
<p>FirstLevelP
<span>SecondLevelSpan</span>.
</p>
<p>FirstLevelP
<span>SecondLevelSpan
<p>ThirdLevelP</p>
</span>.
</p>
Note the dots.
finding and changing text without child elements works this ways:
// search every element
$("body *").each(function(index, el) {
// find first text node
var node = $(el).contents().filter(function() {
return this.nodeType === 3;
})[0];
// change text
node.textContent = "new text";
});
Edit, Updated
Try
$("body *").each(function (i, el) {
if ($(el).is("p, span")) {
$(el).text(function (idx, text) {
var t = text.split("\n")[0];
// if `text` string's last character is not `.`
// concat `.` to `text` string ,
// return `text` original string's with `.` added
return t.slice(-1) !== "." ? t + "." : t
})
}
})
$("body *").each(function (i, el) {
if ($(el).is("p, span")) {
$(el).text(function (idx, text) {
var t = text.split("\n")[0];
return t.slice(-1) !== "." ? t + "." : t
})
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>FirstLevelP
<span>SecondLevelSpan</span>
</p>
<p>FirstLevelP
<span>SecondLevelSpan
<p>ThirdLevelP</p>
</span>
</p>

Categories

Resources