im trying to remove all text except one in javascript
the idea is do something like
//retrieve something like "cnode_72 cnode_1 layout_1 ui-datepicker-week-end "
// "ui-datepicker-week-end" is not necessary always present
var classes= jQuery("someelement").attr("class");
classes = classes.replace(/(?!ui-datepicker-week-end)/,'');
the expected ouput is :
ui-datepicker-week-end
Javascript (as per question)
Erm... might be missing something here, but how about:
classes = "ui-datepicker-week-end";
If that text isn't in the original string, and thus you don't want to add it if it isn't already there then try this:
if(classes.indexOf("ui-datepicker-week-end") == -1)
classes = "";
else
classes = "ui-datepicker-week-end";
JQuery (as per request in comments)
If by some bizarre reason you are using the jQuery("...").attr("class") but didn't bother mentioning that, then try this:
jQuery("...").removeAttr("class").addClass("ui-datepicker-week-end");
or with the condition:
if(jQuery("...").hasClass("ui-datepicker-week-end"))
jQuery("...").removeAttr("class").addClass("ui-datepicker-week-end");
else
jQuery("...").removeAttr("class");
Here is a working example
Related
I'm making a simple step-by-step wizard for my website which asked viewers questions about their custom order. I've been using JavaScript to replace the content of each "page" with the document.getElementById('element-id').innerHTML command; however, it seems really slow and awkward to add entire divs as a string. For example, some of the code looks something like this:
function loadNextStep() {
document.getElementById('content').innerHTML = 'This is some content.<br>It seems like I need to write everything in one line to make the command work properly.<br><input type="date" id="date-picker" value=""></input>'
}
I'd love to be able to write some multi-line html code, and say "replace everything with this new html."
Is there a faster way of doing the same thing?
Thank you again!
I don't think getElementById or querySelector will make any difference, since the heavier stuff is done when you add a bunch of html elements as a string despite the fact that innerHTML can be vulnerable to cross site scripting if the output of that string has user input commands in it.
But if you still want to do this way you can do by using `` backticks to add as many lines as you'd like.
However, the way I would do is to create those elements on a different function and then output them to your loadNextStep function, then adding to your #content element using the appendChild method.
Here's a quick example of I would do:
function loadNextStep() {
var content = document.getElementById('content');
var step = step1();
step.forEach( stepContent => {
content.appendChild( stepContent );
})
}
function step1() {
var someContent = document.createElement('span');
someContent.innerText = `This is some content. It seems like I need to write everything in one line to make the command work properly.
Yes, but if you use backticks you can have multiple lines.`;
var input = document.createElement('input');
input.type = 'date';
input.id = 'date-picker';
return [ someContent, input ]
}
loadNextStep();
<div id="content">
</div>
Please, do not laugh, too much. I know jQuery ans JS for a short a while.
1) How can I make this code more efficient? First line is how do I "select" elements, the second, line is how do I prep to "select", next or previous element.
jQuery('code:lt('+((aktywneZdanie+1).toString())+'):gt('+((aktywneZdanie-1).toString())+')').removeClass('class2');}
aktywneZdanie=aktywneZdanie-1
2) I can not create a function which is working as a method. What I meant is how to change:
jQuery('#something').addClass('class1')
.removeClass('class2');
to something like this:
jQuery('#something').changeClasses();
function changeClasses(){
.addclass('class1');
.removeClass('class2');}
For the first one, why do you need a selector like that? couldn't you find something less specific to hook onto? If you must keep it when joining an number and a string, JavaScript will convert the number to string behind the scenes so you don't really need the .toString() and could do the "maths" +/-1 outside of your selector making it more readable.
Edit
In regards to your comment I am not really sure what you mean, you could assign a class to the "post" items and then add the unique id to a data-attribute ID. To make it simpler you could do something like this:
var codeLt = aktywneZdanie + 1,
codeGt = aktywneZdanie - 1;
$('code:lt(' + codeLt + '):gt(' + codeGt +')').removeClass('class2');
End Edit
And the second solution should work, all your doing is passing the dom elements found from your selector into a function as a jQuery "array" in which manipulate to your needs
And for your second question why not just toggle the class on and off? having a default state which reflects class one?
jQuery('#something').toggleClass('uberClass');
Or you can pass your selector to the function
changeClasses(jQuery('#something'));
Then inside you function work on the return elements.
Edit
Your code should work fine, but id suggest checking to make sure you have got and element to work on:
changeClasses(jQuery('#something'));
function changeClasses($element){
if($element.length > 0) {
$element.addClass('class1');
}
}
End Edit
Hope it helps,
1) How can I make this code more efficient? First line is how do I "select" elements, the second, line is how do I prep to "select", next or previous element.
jQuery('code:lt('+((aktywneZdanie+1).toString())+'):gt('+((aktywneZdanie-1).toString())+')').removeClass('class2');}
aktywneZdanie=aktywneZdanie-1
I stoped creating this wierd code like this one above, instead I start using .slice() (do not forget to use .index() for arguments here), .prev(), .next(). Just those three and everything is faster and clearer. Just an example of it below. No it does not do anything logical.
var activeElem = jQuery('code:first');
var old Elem;
jQuery('code').slice('0',activeElem.index()).addClass('class1');
oldElem=activeElem;
activeElem=activeElem.next();
jQuery('code').slice(oldElem.index(),activeElem.index()).addClass('class1');
oldElem.toggleClass('class1');
activeElem.prev().toggleClass('class1');
and the second part
2) I can not create a function which is working as a method. What I meant is how to change:
jQuery('#something').addClass('class1')
.removeClass('class2');
to something like this:
jQuery('#something').changeClasses();
function changeClasses(){
.addclass('class1');
.removeClass('class2');}
This one is still unsolved by me.
How can I select nodes that begin with a "x-" tag name, here is an hierarchy DOM tree example:
<div>
<x-tab>
<div></div>
<div>
<x-map></x-map>
</div>
</x-tab>
</div>
<x-footer></x-footer>
jQuery does not allow me to query $('x-*'), is there any way that I could achieve this?
The below is just working fine. Though I am not sure about performance as I am using regex.
$('body *').filter(function(){
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
Working fiddle
PS: In above sample, I am considering body tag as parent element.
UPDATE :
After checking Mohamed Meligy's post, It seems regex is faster than string manipulation in this condition. and It could become more faster (or same) if we use find. Something like this:
$('body').find('*').filter(function(){
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
jsperf test
UPDATE 2:
If you want to search in document then you can do the below which is fastest:
$(Array.prototype.slice.call(document.all)).filter(function () {
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
jsperf test
There is no native way to do this, it has worst performance, so, just do it yourself.
Example:
var results = $("div").find("*").filter(function(){
return /^x\-/i.test(this.nodeName);
});
Full example:
http://jsfiddle.net/6b8YY/3/
Notes: (Updated, see comments)
If you are wondering why I use this way for checking tag name, see:
JavaScript: case-insensitive search
and see comments as well.
Also, if you are wondering about the find method instead of adding to selector, since selectors are matched from right not from left, it may be better to separate the selector. I could also do this:
$("*", $("div")). Preferably though instead of just div add an ID or something to it so that parent match is quick.
In the comments you'll find a proof that it's not faster. This applies to very simple documents though I believe, where the cost of creating a jQuery object is higher than the cost of searching all DOM elements. In realistic page sizes though this will not be the case.
Update:
I also really like Teifi's answer. You can do it in one place and then reuse it everywhere. For example, let me mix my way with his:
// In some shared libraries location:
$.extend($.expr[':'], {
x : function(e) {
return /^x\-/i.test(this.nodeName);
}
});
// Then you can use it like:
$(function(){
// One way
var results = $("div").find(":x");
// But even nicer, you can mix with other selectors
// Say you want to get <a> tags directly inside x-* tags inside <section>
var anchors = $("section :x > a");
// Another example to show the power, say using a class name with it:
var highlightedResults = $(":x.highlight");
// Note I made the CSS class right most to be matched first for speed
});
It's the same performance hit, but more convenient API.
It might not be efficient, but consider it as a last option if you do not get any answer.
Try adding a custom attribute to these tags. What i mean is when you add a tag for eg. <x-tag>, add a custom attribute with it and assign it the same value as the tag, so the html looks like <x-tag CustAttr="x-tag">.
Now to get tags starting with x-, you can use the following jQuery code:
$("[CustAttr^=x-]")
and you will get all the tags that start with x-
custom jquery selector
jQuery(function($) {
$.extend($.expr[':'], {
X : function(e) {
return /^x-/i.test(e.tagName);
}
});
});
than, use $(":X") or $("*:X") to select your nodes.
Although this does not answer the question directly it could provide a solution, by "defining" the tags in the selector you can get all of that type?
$('x-tab, x-map, x-footer')
Workaround: if you want this thing more than once, it might be a lot more efficient to add a class based on the tag - which you only do once at the beginning, and then you filter for the tag the trivial way.
What I mean is,
function addTagMarks() {
// call when the document is ready, or when you have new tags
var prefix = "tag--"; // choose a prefix that avoids collision
var newbies = $("*").not("[class^='"+prefix+"']"); // skip what's done already
newbies.each(function() {
var tagName = $(this).prop("tagName").toLowerCase();
$(this).addClass(prefix + tagName);
});
}
After this, you can do a $("[class^='tag--x-']") or the same thing with querySelectorAll and it will be reasonably fast.
See if this works!
function getXNodes() {
var regex = /x-/, i = 0, totalnodes = [];
while (i !== document.all.length) {
if (regex.test(document.all[i].nodeName)) {
totalnodes.push(document.all[i]);
}
i++;
}
return totalnodes;
}
Demo Fiddle
var i=0;
for(i=0; i< document.all.length; i++){
if(document.all[i].nodeName.toLowerCase().indexOf('x-') !== -1){
$(document.all[i].nodeName.toLowerCase()).addClass('test');
}
}
Try this
var test = $('[x-]');
if(test)
alert('eureka!');
Basically jQuery selector works like CSS selector.
Read jQuery selector API here.
If i had a string:
hey user, what are you doing?
How, with regex could I say: look for user, but not inside of < or > characters? So the match would grab the user between the <a></a> but not the one inside of the href
I'd like this to work for any tag, so it wont matter what tags.
== Update ==
Why i can't use .text() or innerText is because this is being used to highlight results much like the native cmd/ctrl+f functionality in browsers and I dont want to lose formatting. For example, if i search for strong here:
Some <strong>strong</strong> text.
If i use .text() itll return "Some strong text" and then I'll wrap strong with a <span> which has a class for styling, but now when I go back and try to insert this into the DOM it'll be missing the <strong> tags.
If you plan to replace the HTML using html() again then you will loose all event handlers that might be bound to inner elements and their data (as I said in my comment).
Whenever you set the content of an element as HTML string, you are creating new elements.
It might be better to recursively apply this function to every text node only. Something like:
$.fn.highlight = function(word) {
var pattern = new RegExp(word, 'g'),
repl = '<span class="high">' + word + '</span>';
this.each(function() {
$(this).contents().each(function() {
if(this.nodeType === 3 && pattern.test(this.nodeValue)) {
$(this).replaceWith(this.nodeValue.replace(pattern, repl));
}
else if(!$(this).hasClass('high')) {
$(this).highlight(word);
}
});
});
return this;
};
DEMO
It could very well be that this is not very efficient though.
To emulate Ctrl-F (which I assume is what you're doing), you can use window.find for Firefox, Chrome, and Safari and TextRange.findText for IE.
You should use a feature detect to choose which method you use:
function highlightText(str) {
if (window.find)
window.find(str);
else if (window.TextRange && window.TextRange.prototype.findText) {
var bodyRange = document.body.createTextRange();
bodyRange.findText(str);
bodyRange.select();
}
}
Then, after you the text is selected, you can style the selection with CSS using the ::selection selector.
Edit: To search within a certain DOM object, you could use a roundabout method: use window.find and see whether the selection is in a certain element. (Perhaps say s = window.getSelection().anchorNode and compare s.parentNode == obj, s.parentNode.parentNode == obj, etc.). If it's not in the correct element, repeat the process. IE is a lot easier: instead of document.body.createTextRange(), you can use obj.createTextRange().
$("body > *").each(function (index, element) {
var parts = $(element).text().split("needle");
if (parts.length > 1)
$(element).html(parts.join('<span class="highlight">needle</span>'));
});
jsbin demo
at this point it's evolving to be more and more like Felix's, so I think he's got the winner
original:
If you're doing this in javascript, you already have a handy parsed version of the web page in the DOM.
// gives "user"
alert(document.getElementById('user').innerHTML);
or with jQuery you can do lots of nice shortcuts:
alert($('#user').html()); // same as above
$("a").each(function (index, element) {
alert(element.innerHTML); // shows label text of every link in page
});
I like regexes, but because tags can be nested, you will have to use a parser. I recommend http://simplehtmldom.sourceforge.net/ it is really powerful and easy to use. If you have wellformed xhtml you can also use SimpleXML from php.
edit: Didn't see the javascript tag.
Try this:
/[(<.+>)(^<)]*user[(^>)(<.*>)]/
It means:
Before the keyword, you can have as many <...> or non-<.
Samewise after it.
EDIT:
The correct one would be:
/((<.+>)|(^<))*user((^>)|(<.*>))*/
Here is what works, I tried it on your JS Bin:
var s = 'hey user, what are you doing?';
s = s.replace(/(<[^>]*)user([^<]>)/g,'$1NEVER_WRITE_THAT_ANYWHERE_ELSE$2');
s = s.replace(/user/g,'Mr Smith');
s = s.replace(/NEVER_WRITE_THAT_ANYWHERE_ELSE/g,'user');
document.body.innerHTML = s;
It may be a tiny little bit complicated, but it works!
Explanation:
You replace "user" that is in the tag (which is easy to find) with a random string of your choice that you must never use again... ever. A good use would be to replace it with its hashcode (md5, sha-1, ...)
Replace every remaining occurence of "user" with the text you want.
Replace back your unique string with "user".
this code will strip all tags from sting
var s = 'hey user, what are you doing?';
s = s.replace(/<[^<>]+>/g,'');
So I am trying to make a string out of a string and a passed variable(which is a number).
How do I do that?
I have something like this:
function AddBorder(id){
document.getElementById('horseThumb_'+id).className='hand positionLeft'
}
So how do I get that 'horseThumb' and an id into one string?
I tried all the various options, I also googled and besides learning that I can insert a variable in string like this getElementById("horseThumb_{$id}") <-- (didn't work for me, I don't know why) I found nothing useful. So any help would be very appreciated.
Your code is correct. Perhaps your problem is that you are not passing an ID to the AddBorder function, or that an element with that ID does not exist. Or you might be running your function before the element in question is accessible through the browser's DOM.
Since ECMAScript 2015, you can also use template literals (aka template strings):
document.getElementById(`horseThumb_${id}`).className = "hand positionLeft";
To identify the first case or determine the cause of the second case, add these as the first lines inside the function:
alert('ID number: ' + id);
alert('Return value of gEBI: ' + document.getElementById('horseThumb_' + id));
That will open pop-up windows each time the function is called, with the value of id and the return value of document.getElementById. If you get undefined for the ID number pop-up, you are not passing an argument to the function. If the ID does not exist, you would get your (incorrect?) ID number in the first pop-up but get null in the second.
The third case would happen if your web page looks like this, trying to run AddBorder while the page is still loading:
<head>
<title>My Web Page</title>
<script>
function AddBorder(id) {
...
}
AddBorder(42); // Won't work; the page hasn't completely loaded yet!
</script>
</head>
To fix this, put all the code that uses AddBorder inside an onload event handler:
// Can only have one of these per page
window.onload = function() {
...
AddBorder(42);
...
}
// Or can have any number of these on a page
function doWhatever() {
...
AddBorder(42);
...
}
if(window.addEventListener) window.addEventListener('load', doWhatever, false);
else window.attachEvent('onload', doWhatever);
In javascript the "+" operator is used to add numbers or to concatenate strings.
if one of the operands is a string "+" concatenates, and if it is only numbers it adds them.
example:
1+2+3 == 6
"1"+2+3 == "123"
This can happen because java script allows white spaces sometimes if a string is concatenated with a number. try removing the spaces and create a string and then pass it into getElementById.
example:
var str = 'horseThumb_'+id;
str = str.replace(/^\s+|\s+$/g,"");
function AddBorder(id){
document.getElementById(str).className='hand positionLeft'
}
It's just like you did. And I'll give you a small tip for these kind of silly things: just use the browser url box to try js syntax. for example, write this: javascript:alert("test"+5) and you have your answer.
The problem in your code is probably that this element does not exist in your document... maybe it's inside a form or something. You can test this too by writing in the url: javascript:alert(document.horseThumb_5) to check where your mistake is.
Another way to do it simpler using jquery.
sample:
function add(product_id){
// the code to add the product
//updating the div, here I just change the text inside the div.
//You can do anything with jquery, like change style, border etc.
$("#added_"+product_id).html('the product was added to list');
}
Where product_id is the javascript var and$("#added_"+product_id) is a div id concatenated with product_id, the var from function add.
Best Regards!