I'm building a glossary page. I have a list of each letter of the alphabet at the top of the page, linking via anchor text to the correct section of content.
I want to remove the link from the letter if the letter has no terms.
I'm not getting any errors, but the code is not removing the link, or having any affect as far as I can tell.
Trying to remove link for B
function removeLink (){
var letternavcontent = document.getElementById("letternav").innerHTML;
var letter = document.getElementsByClassName("letter");
if ( letternavcontent.indexOf('B') > -1) {
letter.removeAttribute("href");
}
}
<p id="letternav">| <a class="letter"
href="/glossary.html#a">A</a> | <a class="letter"
href="/glossary.html#b">B</a></p>
Check this pen.
document.getElementsByClassName returns all the elements with that class name, not just one. So you must loop through this list and check each one.
function removeLink (){
var letter = document.getElementsByClassName("letter");
for (var i = 0; i < letter.length; i++) {
if (letter[i].innerHTML.indexOf('B') > -1) {
letter[i].removeAttribute("href");
}
}
}
How about this?
const removeLinkFromLetter = letter => {
// iterates over every letter element
[...document.querySelectorAll('.letter')].forEach(elt => {
// if the element has the specified letter as its text...
if (elt.innerText.trim()==letter) {
// ...change its content to the letter without the anchor tag
elt.innerHTML = letter;
}
});
}
window.onload = () => {
removeLinkFromLetter('A');
}
<p id="letternav">
|
<span class="letter">
<a href="/glossary.html#a">
A
</a>
</span>
|
<span class="letter">
<a href="/glossary.html#b">
B
</a>
</span>
|
</p>
Related
Here is my code but I can't display the other numbers because I have indexed [0] and I don't know how I can display the other numbers.
Example string: "Hello, you can contact me at 0744224422 or 0192234422."
Result code : "Hello, you can contact me at <span>0744224422</span> or <span>0744224422</span>."
On this example: my code will replace "0192234422" by 0744224422 "which is logical" but I would like it to display 0192234422... How can I do it ?
Thanks
let selector = document.querySelectorAll('.message > div > .chat');
for (let index = 0; index < selector.length; index++) {
if (selector[index].innerText) {
let text = selector[index].innerText;
const regex = /(\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}/gim;
if (text.match(regex).length) {
const newTexte = ` <span>${text.match(regex)[0].trim()}</span> `;
selector[index].innerHTML = text.replace(regex, newTexte);
};
}
}
If you use the $ replacement character of the replace function, it will put the right text in there. Rather than trim just put parentheses around the non-whitespace portion of your regular expression and effectively let the capturing group become the trim operation.
let selector = document.querySelectorAll('.message > div > .chat');
for (let index = 0; index < selector.length; index++) {
if (selector[index].innerText) {
let text = selector[index].innerText;
const regex = /(\d[\s-]?)?([\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4})/gim;
if (text.match(regex).length) {
const newTexte = ` <span class="red">$2</span> `;
selector[index].innerHTML = text.replace(regex, newTexte);
};
}
}
.red {
background: yellow
}
<div class="message">
<div>
<div class="chat">Hello, you can contact me at 0744224422 or 0192234422.</div>
</div>
</div>
I'm going to try to call attention to the difference in the regular expressions below: (because I added one set of parentheses)
/(\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}/gim
( )
/(\d[\s-]?)?([\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4})/gim;
Do you have two separate instances of the selector? If not then the selector.length is only 1 which is why only the first number is shown. You can edit the html to have more than one instance of the selector (and style with display: inline so that it doesn't line break onto a new line) EX:
let selector = document.querySelectorAll('.message > div > .chat');
for (let index = 0; index < selector.length; index++) {
if (selector[index].innerText) {
let text = selector[index].innerText;
const regex = /(\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}/gim;
if (text.match(regex).length) {
const newTexte = ` <span>${text.match(regex)[0].trim()}</span> `;
selector[index].innerHTML = text.replace(regex, newTexte);
};
}
}
<div class="message">
<div>
<p class="chat" style="display:inline">
Hello, you can contact me at 0744224422 or </p>
<p class="chat" style="display:inline">0192234422</p>
<!-- add more numbers as needed in another <p class="chat" style="display:inline" ></p>-->
</div>
</div>
Thank you for your answers, but I would just like to add a <span></span> (or more) when a phone number is written in the string..
I hate manually typing steps numbers. So I was trying to write a small function to find some text and replace it with generated step numbers.
And I can't use the ol/li tags because I have multiple groups on the page. So I need to add an "a", "b", etc after the number.
My HTML:
<span class="grouping" v="a">
----My first step
----This is another
----And another
</span>
<br/>
<span class="grouping" v="b">
----second group
----second group 2
</span>
This is my jquery (but it doesn't replace the ---- to a step number).
$(function(){
$(".grouping").each(function(){
var val=$(this).attr("v");
var counter=1;
$(this).find(":contains('----')").each(function(){
$(this).text("("+counter+val+") ");
counter++;
});
});
});
So eventually, I want the webpage to finish like this:
(1a) My first step
(2a) This is another
(3a) And another
(1b) second group
(2b) second group 2
For each of the groupings, get the inner html and split it by newline
If it starts with '----', replace it with an incrementing line number, and append the v value.
Put the html back into the grouping.
$('.grouping').each(function(index, grouping){
var lines = grouping.innerHTML.trim().split("\n");
var lineNumber = 0;
var v = grouping.getAttribute('v');
lines.forEach(function(line, index){
if (line.startsWith('----')) {
lines[index] = '('+ (++lineNumber) + v +') '+ line.slice(4);
}
});
grouping.innerHTML = lines.join('\n');
});
.grouping { white-space: pre; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="grouping" v="a">
----My first step
----This is another
I should not have a line number.
----And another
</span>
<br/>
<span class="grouping" v="b">
I also should not have a line number.
----second group
----second group 2
</span>
You can use split to split the text at '----' and concat with the values (added brs for lisibility so I used html instead of text):
$(function(){
$(".grouping").each(function(){
var val=$(this).attr("v");
var arr = $(this).html().split('----');
if(arr.length > 1){
var str = arr[0], i, l = arr.length;
for(i = 1; i < l; i++){
str += '(' + i + val + ') ' + arr[i];
}
$(this).html(str);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="grouping" v="a">
----My first step<br>
----This is another<br>
----And another<br>
</span>
<br/>
<span class="grouping" v="b">
----second group<br>
----second group 2<br>
</span>
.find() will not work. You should get text of the element and split() it and then change it using map() and replace() and reset text()
$(function(){
$(".grouping").each(function(){
var val=$(this).attr("v");
var counter=1;
let lines = $(this).text().split('\n');
lines = lines.map(ln => {
if(ln.includes('----')){
ln = ln.replace('----',`(${counter}${val})`)
counter++;
}
return ln;
})
lines = lines.filter(ln => ln !== '');
$(this).text(lines.join('\n'));
});
});
.grouping { white-space: pre; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="grouping" v="a">
----My first step
----This is another
----And another
</span>
<br/>
<span class="grouping" v="b">
----second group
----second group 2
</span>
First, I suggest wraping those groups into some kind of tag. for example, span:
<span class="grouping" v="a">
<span class="grouping-item">My first step</span>
</span>
And so on, it will be easier and faster to target those elements.
Then create one function to search through those new tags
$(function(){
// This will create those numbers
function createNumbers(el) {
const mainGroup = el.attr("v");
const children = el.children(".grouping-item");
let i = 1;
children.each(function(){
const currentText = $(this).text();
$(this).text( '('+i+mainGroup+')' + currentText );
i++;
});
}
$(".grouping").each(function(){
createNumbers($(this));
});
});
I need to search my entire document for a phone number, and compile a list of elements which have this phone number in them.
However I have encountered afew snags.
I can't simply do document.body.innerHTML and replace the numbers, as this messes up third party scripts.
The following will match the elements, but ONLY if they have the number within them, and nothing else:
let elements = document.querySelectorAll("a, div, p, li");
let found = [];
for (let elm in elements) {
if (elements.hasOwnProperty(elm)) {
if (elements[elm].textContent !== undefined && elements[elm].textContent.search("00000 000000") != -1) {
found.push(elements[elm]);
}
}
}
So the following element will not match:
<li class="footer__telephone">
<i class="fa fa-phone" aria-hidden="true"></i>00000 000000
</li>
Due to having the i tag in there.
Using textContent instead of text also does not work as the parent of an element will then match, but I don't want the parent.
Edit:
<div class="row-block hmpg-text">
<div class="wrapper">
<div class="container">
<div class="row">
<div class="twelvecol">
00000 000000
</div>
</div>
</div>
</div>
</div>
Lets say the above is my HTML, if I loop through all the elements and test them with testContent then the first is going to be returned as true, to containing my number, but I need the element with the class of twelvecol on it, not the parent which is 4 levels up.
Managed to find an answer, similar to what Phylogenesis said however couldn't get any of them examples working.
function replaceText(el, regex_display, regex_link) {
// Replace any links
if (el.tagName === "A") {
if (regex_link.test(el.getAttribute("href"))) {
el.setAttribute("href", el.getAttribute("href").replace(regex_link, replacement.replace(/\s/g, '')));
}
}
if (el.nodeType === 3) {
if (regex_display.test(el.data)) el.data = el.data.replace(regex_display, replacement);
if (regex_link.test(el.data)) el.data = el.data.replace(regex_link, replacement);
} else {
let children = el.childNodes;
for (let i = 0; i < children.length; i++) {
replaceText(children[i], regex_display, regex_link);
}
}
}
let bodyChildren = document.body.childNodes;
let search_display = new RegExp(search, "g");
let search_link = new RegExp(search.replace(/\s/g, ''), "g");
for (let i = 0; i < bodyChildren.length; i++) {
replaceText(bodyChildren[i], search_display, search_link);
}
just wants to get the inner html of a nestate span tag..
<span class="select2-selection__rendered" id="select2-SearchByUser-container" title="chowdhury , nayan (nayanchowdhury92#gmail.com)">
<span class="select2-selection__clear">×</span>
mark john
</span>
i need mark john and i try =>
alert($('#select2-SearchByUser-container').html())
i give output/alert something like =>
<span class="select2-selection__clear">×</span>mark john
is there any way that i can get only mark john...help please...
To do what you need you can retrieve the last textNode in the element, like this:
var text = $('#select2-SearchByUser-container').contents().filter(function() {
return this.nodeType == 3 && this.nodeValue.trim();
}).last().text().trim();
console.log(text);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="select2-selection__rendered" id="select2-SearchByUser-container" title="chowdhury , nayan (nayanchowdhury92#gmail.com)">
<span class="select2-selection__clear">×</span> mark john
</span>
Try this :
https://jsfiddle.net/4nwp25Le/
jQuery(document).ready(function() {
var node = $('#select2-SearchByUser-container').contents().filter(function() {
return this.nodeType == 3; // text node
});
alert(node.text());
});
Your html is not good so far, if possible fix that so that you can get different spans for them.
If you don't have control over HTML, can give a try like this
$('#select2-SearchByUser-container').clone().children().remove().end().text()
https://jsfiddle.net/qspoygox/
var el = document.getElementById("select2-SearchByUser-container"),
child = el.firstChild,
texts = [];
while (child) {
if (child.nodeType == 3) {
texts.push(child.data);
}
child = child.nextSibling;
}
var text = texts.join("");
alert(text);
<span class="select2-selection__rendered" id="select2-SearchByUser-container" title="chowdhury , nayan (nayanchowdhury92#gmail.com)">
<span class="select2-selection__clear">×</span>
mark john
</span>
I would like to search by any term (name, user, from, price), and display the div into top and hide the ones who doesn't have the typed value.
Here's the jsfiddle: http://jsfiddle.net/Sc9ys/10/
I would like to have the same result as the jquery mobile table filter http://demos.jquerymobile.com/1.4.0/filterable/
Where you can search for any term.
I know that for search for any term I should use $(list).find("li *:)... but I can't figure out how to display the items properly. If you test my jsfiddle it doesn't work very well.
Edit: As asked by the user below, here's some more info.
<ul id='list'>
<li>
<div class='row'>
<div class='middle'>
<ul>
<li><h3>Stackoverflow</h3></li>
<li><span>User</span></li>
<li><span>London</span></li>
</ul>
</div>
<div style='clear: both'></div>
</div>
</li>
</ul>
$("#search").change( function () {
$(list).find("li *:not(:Contains(" + filter + "))").parent().hide();
});
DEMO
The idea is in
$("#ul_container").find("li").filter(function () {//your comparing logic here });
Here, try this out. Honesty I couldn't read thru your code, so I made this example. I added the sub items (spans that contain data to be searched) in an array datalist by their class name.
Generic Search Function.
HTML
<input type="text" id="search" />
<ul id="ul_container">
<li class="listItem">
<span class="car">Honda</span>
<span class="country">Japan</span>
</li>
<li class="listItem">
<span class="car">BMW</span>
<span class="country">Germany</span>
</li>
</ul>
Script:
//Capture user input
$("#search").on("keyup change", function () {
var str = $.trim($(this).val());
if (str) {
search(str);
} else {
// if no input, then show all
$(".listItem").show();
}
});
//the search part.
var datalist = ["car", "country"];
function search(toFind) {
//select all li and loop thru them one by one
$("#ul_container").find("li").filter(function () {
var $li = $(this);//hold current li in a variable
//loop thru all sub spans by their class and check if the toFind keyword is there
// you modify this step, i use it to specify which sub span to be searched. Sometimes I don't want all field to be searched, only the ones I select.
for (var i = 0; i < datalist.length; i++) {
//hold the span in a var called $item
var $item = $li.children("." + datalist[i]);
var content_str = $item.html();//get the actual string
//the comparing code
if (content_str.toLowerCase().indexOf(toFind.toLowerCase()) >= 0) {
$li.show();
break;
} else {
$li.hide();
}
}
});
}
Solved guys. Thank you all.
You can see the following example working at: http://jsfiddle.net/Sc9ys/29/
$('#search').on('keyup change', function(){
var str = $.trim($(this).val());
if (str) {
search(str, $("#list"));
} else {
$("#list").find('li').show();
/* The <li> are display: none, to show them again if the input type is clear,
we must find those <li> and show them. Showing only the #list isn't enough. */
}
});
function search(toFind, list){
$(list).find('li').filter(function() {
$li = $(this);
$li.find(".middle :contains(" + toFind +")").parent().parent().slideDown();
$li.find(".middle").not(":contains(" + toFind + ")").parent().parent().slideUp();
});
}
/* Function to search with the input lowercase */
$.expr[":"].contains = $.expr.createPseudo(function(arg) {
return function( elem ) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
Edit: Made some adjustments according to the help of user #Joraid.