I need to replace some words on an HTML page with links, i.e. "linkify" these words. I have an array of identifier descriptors, like this:
var symbols_desc = [
{
id: 'id_one',
name: 'struct my_struct_one',
},
{
id: 'id_two',
name: 'my_name_two',
},
/* ... */
]
So in certain areas of HTML page I need to transform all occurrences of struct my_struct_one to struct my_struct_one, etc.
I'm not an expert in the Web field, so, I use probably the dumbest way: I update HTML by means of jQuery. Like this:
$(document).ready(function() {
$(".some-class1, .some-class2").each(function() {
var o = $(this);
symbols_desc.forEach(function(desc){
o.html(
o.html().replace(
new RegExp('(\\b' + desc.name + '\\b)', 'g'),
'<a class="symb-link" href="#' + desc.id + '">$1</a>'
)
);
});
});
});
It works, but it is unacceptably slow. There are about 70 identifiers, HTML page is about 200 KB, and it takes about 5 seconds.
Given the complexity and awesomeness of some Web applications that I use from time to time, I'm sure there should be better ways to perform this simple task. I'd be glad to hear your suggestions.
In your case I think all we have do is to change comfortable forEach to simple for and use more variables, so please try:
$(".some-class1, .some-class2").each(function() {
var html = $(this).html();
for (var i = 0; i < symbols_desc.length; i++) {
html.replace(
new RegExp('(\\b' + symbols_desc[i].name + '\\b)', 'g'),
'<a class="symb-link" href="#' + symbols_desc[i].id + '">$1</a>'
);
}
$(this).html(html);
});
First off, no need to use jQuery. It probably contributes to slowing everything down. Get your HTML areas by using
var fooElements = document.querySelectorAll('.someclass1, .someclass2')
This returns a nodelist, and array like object, that can be looped using a normal for.
Also, your dictionary doesn't have to be an array.
var symbols_desc = {
'id_one' : 'struct my_struct_one',
'id_two' : 'my_name_two'
}
Now we can have one regex to replace everything in one go per html element you want to work on, instead of looping n * m times
var fooRegex = new RegExp(Object.keys(symbols_desc).join("|"),"gi");
All that remains is to do the actual work
for(var i = 0; i < fooElements.length; i++){
fooElements[i].innerHTML = fooElements[i].innerHTML.replace(fooRegex,function(matchedString){
return mapObj[matchedString.toLowerCase()];
});
}
Working example, it should be pretty fast:
var dictionary = {
'mouse': 'cat',
'dog': 'mouse',
'horse': 'dog',
'cat': 'horse'
}
var fooElements = document.querySelectorAll('.some-class1, .some-class2');
var fooRegex = new RegExp(Object.keys(dictionary).join("|"), "gi");
for (var i = 0; i < fooElements.length; i++) {
fooElements[i].innerHTML = fooElements[i].innerHTML.replace(fooRegex, function(matchedString) {
return dictionary[matchedString.toLowerCase()];
});
}
<div class="some-class1">
Dog, cat, mouse
</div>
<div class="some-class2">
Horse, cat, dog
</div>
Related
I have a regular expression happening that searching for all the capitals in a document. It gathers them and puts them into an array no problem.
The issue I am having is I want to replace the items in that array to include a span around each item that was captured in the array and then display the updated result. I've tried a variety of things.
I am at a complete loss. Any help is appreciated. Here was my last attempt
var allCaps = new RegExp(/(?:[A-Z]{2,30})/g);
var capsArray = [];
var capsFound;
while (capsFound = allCaps.exec(searchInput)) {
capsArray.push(capsFound[0]);
}
//for(var x = 0; x < capsArray.length; x++){
//var test = ;
capsArray.splice(0, '<span style="color:green">'+ capsArray +'</span>');
//}
}
You can't convert an entire array's elements like that using splice - you can use .map instead:
capsArray = capsArray.map(c => '<span style="color:green">' + c + '</span>');
Do you need the results in an array? If not, you can wrap all caps in a str using a modified regex:
str.replace(/([A-Z])/g, '<span>$1</span>')
example:
'A--B--C' becomes '<span>A</span>---<span>B</span>---<span>C</span>'
if the array is needed for whatever reason:
str.split(/[^A-Z]+/g).map(x => `<span>${x}</span>`)
example:
'A--B--C' becomes ['<span>A</span>', '<span>B</span>', '<span>C</span>']
Thanks to everyone for the help.
Heres my final solution for anyone else that gets lost along the way
var allCaps = new RegExp(/(?:[A-Z]{2,30})/g);
var capsArray = [];
var capsFound;
while (capsFound = allCaps.exec(searchInput)) {
capsArray.push(capsFound[0]);
}
if(capsArray.length > 0){
resultsLog.innerHTML += "<br><span class='warning'>So many capitals</span><br>";
searchInput = document.getElementById('findAllErrors').innerHTML;
searchInput = searchInput.replace(/([A-Z]{3,30})/g, '<span style="background-color:green">$1</span>');
document.getElementById('findAllErrors').innerHTML = searchInput;
}
else {
resultsLog.innerHTML += "";
}
I am trying to find all divs with class "comment-like" that also has "data-id" attributes equals to 118603,1234,1234,118601,118597 and if some div contains one of these data value, then remove that data attribute.
So far I created this, but it is not working currently.
remove_comments = 118603,1234,1234,118601,118597;
$('.comment-like').find('[data-id="' + remove_comments + '"]').removeAttr('data-id');
You can dynamically create a query string to capture all the divs you are looking for. The query string would look like this:
.comment-like[data-id="118603"], .comment-like[data-id="1234"], etc...
var ids = [118603, 1234, 1234, 118601, 118597];
var queryString = ids
.map(function(id) {
return '.comment-like[data-id="' + id + '"]';
})
.join(', ');
$(queryString).each(function(i, el) {
$(el).removeAttr('data-id');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="comment-like" data-id="118603"></div>
<div class="comment-like" data-id="1234"></div>
<div class="comment-like" data-id="0"></div>
Easy solution is just loop through your ids
remove_comments = 118603,1234,1234,118601,118597;
rc = remove_comments.split(",");
for (var i = 0; i < rc.length; i++) {
$('.comment-like').find('[data-id="' + rc[i] + '"]').removeAttr('data-id');
}
If you open the developer console in Chrome and typ this in:
remove_comments = 118603,1234,1234,118601,118597;
remove_comments
You can see what is actually happening.
One approach that should work is to put it in an array, and then loop over it:
var remove_comments = [118603,1234,1234,118601,118597];
for (var i = 0; i < remove_comments.length; i++) {
$('.comment-like').find('[data-id="' + remove_comments[i] + '"]').removeAttr('data-id');
}
I dynamically create this list element and information a user has typed in shows up in it when a button is clicked 'info' is text and shuld show as it is but 'grade' is a number that i want to convert to another sign with the function changeNumber() but I am new to javascript and cant figure out how to make this function, can anyone give a suggestion or point me in the right direction?
var list = $("#filmlista");
var list_array = new Array();
function updateFilmList()
{
document.getElementById("name").value = '';
document.getElementById("star").value = 0;
var listan = list_array[0][0];
var grade = list_array[0][1];
var element = '<li class="lista">' + list + '<span class="grade">'+ changeNumber(grade) +'</span></li>';
list.append(element);
}
should I use innerHTML? not shure I understand how it works? and how do I use the replace method if I have to replace many different numbers to the amount of signs the number is?
for example if the number is 5 it should show up as: *****, if number is 3 show up as: *** and so on
Here's some code that should do the trick:
Add this function into your script.
function changeNumber(number) {
var finalProduct = "";
for (var i = 0; i < number; i++) {
finalProduct += "*";
}
return finalProduct;
}
Replace the updateFilmsList with this code.
document.getElementById("name").value = '';
document.getElementById("star").value = 0;
var listan = list_array[0][0];
var grade = changeNumber(list_array[0][1]);
var element = '<li class="lista">' + list + '<span class="grade">'+ grade +'</span></li>';
list.append(element);
It looks like you're trying to do something like PHP's str_repeat. In that case, take a look at str_repeat from PHPJS
There are options other than a loop:
function charString(n, c) {
n = n? ++n : 0;
return new Array(n).join(c);
}
charString(3, '*'); // ***
You can use innerHTML to set the text content of an element provided none of the text might be mistaken for markup. Otherwise, set the textContent (W3C compliant) or innerText (IE proprietary but widely implemented) property as appropriate.
How can I retrieve an array of ids with only a prefix in common?
E.g.
I've got a list of say 50 divs and they all got and ID looking like: aa_0000. Where 'a' is a prefix and '0' represents random numbers.
You want all elements of which their id starts with something common?
Assuming they are all div elements, this should work....
// Just so we can stay DRY :)
var prefix = 'aa_',
matchElement = 'div';
// Do we have an awesome browser?
if ('querySelectorAll' in document) {
var matchedDivs = document.querySelectorAll(matchElement + '[id^="' + prefix + '"]');
} else {
var allDivs = document.getElementsByTagName(matchElement),
matchedDivs = [],
regex = new RegExp('^' + prefix);
for (var i = 0, allDivsLength = allDivs.length; i < allDivsLength; i++) {
var element = allDivs[i];
if (element.id.match(regex)) {
matchedDivs.push(element);
}
}
}
console.log(matchedDivs.length); // Expect 3
jsFiddle.
If you want to explicitly match ones with numbers, try the regex /^aa_\d+$/.
If you have jQuery floating around, you can use $('div[id^="aa__"]').
For people using jQuery:
$('div[id^="aa_"]')
I have two arrays, one is full of strings, the other is an array of objects. The indexes on each correspond, and I want to replace the text of each of the objects in my object array with the corresponding text in my string array.
For example, I have an array like this:
var textarr = ["value1", "value2", "value3"]
and a Jquery object array that contains a bunch of span elements:
var spans = $("span.myClass");
var spanarr = $.makeArray(spans);
I'm trying to use $.each() to iterate over each of the spans and use the corresponding index of my text array to assign a text value to the current span.
I've tried a couple different ways, and nothing seems to work. I'm missing some logic here, but why wouldn't this work?:
i = 0;
jQuery.each(spanarr, function() {
$(this).text(textarr[i]);
i++;
});
EDIT:
I think maybe the rest of my function might be causing this not to work. Here's the entire script:
$("span input:radio").click(function() {
if (($(this).is(":checked")) == true) {
var parent = $(this).parent();
var aunts = parent.parent().children();
var parentIndex = aunts.index(parent);
var indexToNthChild = parentIndex + 1;
var otherSpans = $(".DropDownMenu span:nth-child(" + indexToNthChild + ")");
var position = parent.position();
var topValue = position.top;
var smallPrice = otherSpans.children("span.dropDownPrice");
var pricearr = jQuery.makeArray(smallPrice);
var textarr = [];
jQuery.each(pricearr, function() {
textarr[i] = $(this).text();
});
alert(textarr); // Returns all the text values expected in array
var changers = $(".bigPriceChanger");
var changerarr = $.makeArray(changers);
$(".DropDownMenu").css({ "top": "-" + topValue + "px" });
$(".DropDownMenu span").css("background-image", "none");
parent.css({ "background": "#f3f1e7 url(assets/images/branding/DropDownArrow.gif) no-repeat right" });
otherSpans.css({ "background": "#f3f1e7 url(assets/images/branding/DropDownArrow.gif) no-repeat right" });
alert(changearr); // Returns all span objects in array
i = 0;
jQuery.each(changearr, function() {
$(this).text(textarr[i]);
i++;
});
}
});
Try
$("span.myClass").each(function (i) {
$(this).text(textarr[i]);
});
I think you don't need the call to makeArray. Just write:
i = 0;
jQuery.each($("span.myClass"), function() {
$(this).text(textarr[i++]);
});
I hate to end the question with a 'it was all a dream afterall' copout, but it turns out my browser was funked.
I've since checked my script (and the million variations of it that everyone suggested) in IE8 and someone else's firefox, and low and behold, it works.
You might want to try something like this:
var spans = $("span.myClass");
for(i=0;i<spans.length;i++){
spans[i].innerHTML = textarr[i];
}
You can think of a jQuery object like an extended version of an array. You can use length and [i] in reference to the number of DOM elements selected and the DOM element at a certain index respectively.
Your code is fine, although the makeArray call is redundant
There must be an error somewhere else,
here is your code running fine in firefox
http://jsbin.com/oxiwu
to edit go to http://jsbin.com/oxiwu/edit
I think your code is not working because the variable i was defined outside its scope.
Probably there is a better solution, but you could try the following:
function createF() {
var i = 0;
function f() {
$(this).text(textarr[i]);
i++;
}
return f;
}
f = createF();
jQuery.each(spanarr, f);
What's the reason for calling $.makeArray? You can iterate through your spans like this...
$("span.myClass").each(function(i) {
alert(textarr[i]);
$(this).text(textarr[i]);
});