This function organize list, not organized in alphabetical order: ascending/descending in Firefox and Internet Explorer.
In google chrome and Edge is working.
Here is code:
<script type="text/javascript">
window.onload = function () {
var desc = false;
document.getElementById("Order").onclick = function () {
sortUnorderedList("PostList", desc);
desc = !desc;
return false;
}
}
function compareText(a1, a2) {
var t1 = a1.innerText,
t2 = a2.innerText;
return t1 > t2 ? 1 : (t1 < t2 ? -1 : 0);
}
function sortUnorderedList(ul, sortDescending) {
if (typeof ul == "string") {
ul = document.getElementById(ul);
}
var lis = ul.getElementsByTagName("li");
var vals = [];
for (var i = 0, l = lis.length; i < l; i++) {
vals.push(lis[i]);
}
vals.sort(compareText);
if (sortDescending) {
vals.reverse();
}
ul.innerHTML = '';
for (var i = 0, l = vals.length; i < l; i++) {
ul.appendChild(vals[i]);
}
}
</script>
Try this:
document.getElementById("hello").onclick = talk;
function talk()
{
alert('It works!');
}
<a id="hello">Click me!</a>
It seems to be right. Is your element ID right? Check if you have more then one element using the same ID also. If you can, post you HTML code.
It's bad if you use code of unknown source, you might even get in trouble with copyrights! Here is a simplified version (No, I won't apologize for the use of Bubble-sort!) that should be easy to follow.
Edited on request of OP to add an example of deep copying
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript">
// as shown in http://stackoverflow.com/questions/3066427/copy-all-childnodes-to-an-other-element-in-javascript-native-way
function copyElements (dst,src){
while (src.hasChildNodes()) {
dst.appendChild(src.removeChild(src.firstChild))
}
}
function sortUnorderedList(element_id, direction){
var table = document.getElementById(element_id);
var rows,i,tmp;
// get the rows in the order as they are
rows = table.rows;
i = rows.length - 1;
// tmp must be a node for this highly simplified stuff to work
tmp = document.createElement("getoffmylawn");
// do a simple Bubble sort (sorts lexically, maybe not what you want!)
// Assumes things to sort are in the first cell, adjust if necessary
for(; i > 0; i--){
for(j = 0;j < i; j++){
if(direction === false){
if(rows[j].firstChild.firstChild.textContent < rows[j+1].firstChild.firstChild.textContent){
copyElements (tmp , rows[j]);
copyElements (rows[j] , rows[j+1]);
copyElements (rows[j+1] , tmp);
}
}
else{
if(rows[j].firstChild.firstChild.textContent > rows[j+1].firstChild.firstChild.textContent){
copyElements ( tmp , rows[j]);
copyElements (rows[j] , rows[j+1]);
copyElements (rows[j+1] , tmp);
}
}
}
}
}
window.onload = function () {
var desc = false;
document.getElementById("Order").onclick = function () {
sortUnorderedList("FileList", desc);
desc = !desc;
return false;
};
};
</script>
</head>
<body>
<table id="FileList">
<tr><td>Foo</td></tr>
<tr><td>Bar</td></tr>
<tr><td>Foobar</td></tr>
<tr><td>Something</td></tr>
<tr><td>Anything</td></tr>
<tr><td>Somehwere</td></tr>
<tr><td>elsewhere</td></tr>
<tr><td>completely lost</td></tr>
</table>
<button id="Order">Sort</button>
</body>
</html>
If you think the order is wrong you have found out what "lexical order" actually means.
To work in Internet Explorer and Firefox, I replaced:
innerText to textContent
Related
I'm using the w3schools.com w3.js search engine
It works fine, but I need it to display a <div> for when the search engine cannot match any search.
Here's my code:
<input type="text" id="myInput" oninput="w3.filterHTML('#myTable', 'p', this.value)" placeholder="Search for names..">
<div id="myTable">
<div>
<p>Adele</p>
</div>
<div>
<p>Agnes</p>
</div>
<div>
<p>Billy</p>
</div>
<div>
<p>Bob</p>
</div>
</div>
<div id="no-data-div" style="display:none">
<p>No Results Found :(</p>
</div>
and the Script:
<script>
var w3 = {};
w3.getElements = function (id) {
if (typeof id == "object") {
return [id];
} else {
return document.querySelectorAll(id);
}
};
w3.filterHTML = function(id, sel, filter) {
var a, b, c, i, ii, iii, hit;
a = w3.getElements(id);
for (i = 0; i < a.length; i++) {
b = w3.getElements(sel);
for (ii = 0; ii < b.length; ii++) {
hit = 0;
if (b[ii].innerHTML.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
hit = 1;
}
c = b[ii].getElementsByTagName("*");
for (iii = 0; iii < c.length; iii++) {
if (c[iii].innerHTML.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
hit = 1;
}
}
if (hit == 1) {
b[ii].parentElement.style.display = "";
} else {
b[ii].parentElement.style.display = "none";
}
}
}
};
</script>
I want "#no-data-div" to be visible when all the others divs are hidden. How can I achieve this?
I spent some time adjusting your code. I believe this should work for you. I commented your code so you know which each part is doing (as far as I can tell), and adjust as needed... The main addition is just the counter (totalHits++) which runs through the script so it can be analyzed at the end to decide if the no results div should be shown or not.
w3.filterHTML = function(id, sel, filter) {
// w3 search filter function, adjusted by Nerdi.org (username on StackOverflow/my website)
// https://stackoverflow.com/questions/49742504/show-a-hidden-div-when-no-results-were-found-in-a-search-input
var a, b, c, i, ii, iii, hit;
a = w3.getElements(id);
// a.length will tell you # of tables (should be = to 1, as in 1 table being searched)
var totalHits = 0; // let's get a total count.
for (i = 0; i < a.length; i++) {
b = w3.getElements(sel);
// b.length will tell you # of valid selections (by tag, in this case you are searching the <p> tags)
for (ii = 0; ii < b.length; ii++) {
hit = 0;
if (b[ii].innerHTML.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
hit = 1;
totalHits++;
}
c = b[ii].getElementsByTagName("*");
// c.length will tell us how many children this elem has so we can cycle through any child elements within the first selection (in this case, <p>)
var cLength = c.length;
for (iii = 0; iii < cLength; iii++) {
if (c[iii].innerHTML.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
hit = 1;
totalHits++;
}
}
if (hit == 1) {
b[ii].parentElement.style.display = "";
} else {
b[ii].parentElement.style.display = "none";
}
}
}
// now that we've looped through all results, let's see if we found anything using our totalHits var that we set earlier :)
if(totalHits == 0){
document.getElementById('no-data-div').style.display = 'block'; // show the no results found
} else {
document.getElementById('no-data-div').style.display = 'none'; // hide the no results found
}
};
I have this line
<td><xsl:value-of select="product_name"/></td>
When i try to get the return value of the function getTableRow() and display it to href link i take key=undefined.Why happen that?
This is my script on the head of html
<script type="text/javascript">
function getTableRow() {
var rowIdx;
var rowData= [];
var selectedRow;
var rowCellValue;
if (!document.getElementsByTagName || !document.createTextNode) return;
var rows = document.getElementById('products_table').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
for (i = 0; i < rows.length; i++) {
rows[i].onclick = function() {
rowIdx = this.rowIndex;
selectedRow= this.cells;
for(j= 0;j<selectedRow.length;j++){
rowCellValue= selectedRow[j].textContent ||
selectedRow[j].innerText;
rowData.push('cell '+j+': '+rowCellValue);
}
}
}
return "Row #" +rowIdx+'. '+ rowData[i];
}
</script>
I try many solution but nothing work..Please help..
In the beginning the only thing i want is to return the rowIndex.Even in that i get undefined.Why happend that?My first code before i try to get the content from row that user select.
<script type="text/javascript">
var userSelect;
function getTableRow() {
if (!document.getElementsByTagName || !document.createTextNode) return;
var rows = document.getElementById('products_table').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
for (i = 0; i < rows.length; i++) {
rows[i].onclick = function() {
userSelect = this.rowIndex;
}
}
return userSelect;
}
</script>
It's probably being caused
if (!document.getElementsByTagName || !document.createTextNode) return;
If you are getting undefined.
Best thing I can suggest is throw a load of debugging in e.g. :
<script type="text/javascript">
function getTableRow() {
console.log( "getTableRow function called" );
var rowIdx;
var rowData= [];
var selectedRow;
var rowCellValue;
if (!document.getElementsByTagName || !document.createTextNode) {
console.log( document.getElementsByTagName, document.createTextNode, "Returning early" );
return;
}
var rows = document.getElementById('products_table').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
for (i = 0; i < rows.length; i++) {
rows[i].onclick = function() {
rowIdx = this.rowIndex;
selectedRow= this.cells;
for(j= 0;j<selectedRow.length;j++){
rowCellValue= selectedRow[j].textContent ||
selectedRow[j].innerText;
rowData.push('cell '+j+': '+rowCellValue);
}
}
}
console.log( "Returning correctly" );
return "Row #" +rowIdx+'. '+ rowData[i];
}
</script>
If you're using firefox get yourself http://getfirebug.com/ and see what the console outputs
If you're using chrome press F12 and click on console and see what that says
If you're unsure about what's available in the document element try :
https://developer.mozilla.org/en/docs/Web/API/Element
http://msdn.microsoft.com/en-us/library/ie/ms535862(v=vs.85).aspx
http://www.w3schools.com/jsref/dom_obj_document.asp
Hey All I have this javascript function that actively searches a table I have on my web page. The function working in Mozilla and Chrome but not in IE. Can anyone help me tweak this so it will work in all browsers? here is the code:
function playerSearch(phrase, _name){
var words = phrase.value.toLowerCase().split(" ");
var table = document.getElementsByName(_name)[0];
var ele;
for (var r = 1; r < table.rows.length; r++){
ele = table.rows[r].innerHTML.replace(/<[^>]+>/g,"");
var displayStyle = 'none';
for (var i = 0; i < words.length; i++) {
if (ele.toLowerCase().indexOf(words[i])>=0)
displayStyle = '';
else {
displayStyle = 'none';
break;
}
}
table.rows[r].style.display = displayStyle;
}
}
Here is the function call from the html page:
<span id="filter" class="filter">Player Search:<input onkeyup="playerSearch(this, 'currentTable')" type="text"></span>
It sounds like IE is insisting on inserting a tBody dom element. try altering var table = document.getElementsByName(_name)[0]; to var table = document.getElementsByName(_name)[0].tBodies[0];
EDIT
After reading the comments below and doing a bit of googling it turns out that name is not a global attribute and not a valid attribute on tables according to the HTML4.01 specification (this is unchanged in the current draft of the HTML5 specification) this is unfortunatly one of the times when IEs javascript engine is being a stickler for the rules returning an array of 0 length when you do document.getElementsByName(_name) , and the other browser manufacturers are actually breaking the specification.
Here is my answer which works in all browsers. Separate function are given for IE, NetScape and all other browsers.
<script type="text/javascript" language="JavaScript">
var OtherBrowser = (document.getElementById);
var IE4 = (document.all);
var NS4 = (document.layers);
var win = window;
var n = 0;
function findInPage(str) {
var txt, i, found;
if (str == "") {
alert("Enter some thing to search");
return false;
}
else if (IE4) {
txt = win.document.body.createTextRange();
for (i = 0; i <= n && (found = txt.findText(str)) != false; i++) {
txt.moveStart("character", 1);
txt.moveEnd("textedit");
}
if (found) {
txt.moveStart("character", -1);
txt.findText(str);
txt.select();
txt.scrollIntoView();
n++;
}
else {
if (n > 0) {
n = 0;
findInPage(str);
}
else
alert("Sorry, we couldn't find.Try again");
}
}
else if (OtherBrowser) {
if (!win.find(str)) {
while (win.find(str, false, true, false, false, false, true))
n++;
}
else if (win.find(str)) {
n++;
}
}
if (NS4) {
if (!win.find(str)) {
while (win.find(str, false, true, false, false, false, true))
n++;
}
else if (win.find(str)) {
n++;
}
}
return false;
}
</script>
If you want to save yourself some trouble while applying some slick table functionality (including filters, which I think you're trying to achieve here), I suggest DataTables.
http://datatables.net/
I have a list of question in my javascript file. Each question has a question number and question description and options. A question can be added anywhere in the list of questions. So if a question is added into the top of all questions, then i need to change the question numbers of all the below ones. How can achieve this. Can i use javascript for this?
I would suggest using an <ol> for each question, and let the page handle reflowing the numbers.
Otherwise you'll need to set a target number before inserting, and for each element in the list you'll check to see if it's number is greater than the target, and then if so increment the number by one.
var Target = //new number that I want the inserted question to be
foreach (element in list) {
if (element.Number > Target) element.Number += 1;
}
list.add( //new question with # set to Target );
This works.
<ol id="questions_list"></ol>
var questions = ["A foo walks into a bar. What happens?", "Why did foo cross the road?"];
addQuestion("foo", 1);
function addQuestion(question, position)
{
if(position > 0 && position < questions.length)
{
var firstHalf = questions.slice(0, position);
var secondHalf = questions.slice(position, questions.length);
firstHalf.push(question);
questions = firstHalf.concat(secondHalf);
console.log("slice");
}else if(position <= 0)
{
questions.unshift(question);
console.log("beginning");
}else if(position >= questions.length)
{
questions.push(question);
console.log("end");
}
updateQuestionList();
}
function updateQuestionList()
{
var questions_list = document.getElementById("questions_list");
questions_list.innerHTML = "";
for(var i=0;i<questions.length;i++)
{
var question = document.createElement("LI");
question.innerHTML = questions[i];
questions_list.appendChild(question);
}
}
http://jsfiddle.net/jPxwW/1/
Array prototype ( fun! =) ):
// zero-based insert
Array.prototype.insert = function(index, item) {
var i = 0, list = [];
if (this.length == index) {
list = this;
list.push(item);
return list;
}
for(; i < this.length; i++) {
if (index == list.length) {
list.push(item);
i--;
} else {
list.push(this[i]);
}
}
return list;
};
Array.prototype.print = function (base) {
base = base || 1;
for (var i = 0, out = []; i < this.length; i++) {
out.push((base + i) + '. ' + this[i]);
}
return out.join("\n");
};
list = ['when?', 'where?', 'why?'];
list = list.insert(0, 'who?'); // first: ["who?", "when?", "where?", "why?"]
list = list.insert(3, 'how?'); // 4th: ["who?", "when?", "where?", "how?", "why?"]
list = list.insert(list.length, 'last?'); // last: ["who?", "when?", "where?", "how?", "why?", "last?"];
list.print();
/**
"1. who?
2. when?
3. where?
4. how?
5. why?
6. last?"
**/
You could do something like this using ordered lists (ol) and jQuery:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.4.4.min.js" type="text/javascript"></script>
<script type ="text/javascript">
$(function(){
var n = 2;
$('button').delegate('click', function(){
$(this).parents('li').after('<li><p><span>Question'+n+'</span><button>Create new question</button></p></li>');
n += 1;
})
})
</script>
</head>
<body>
<ol>
<li>
<p><span>Question 1</span><button>Create new question</button></p>
</li>
</ol>
</body>
</html>
I am having issues figuring out how to resolve the getElementsByClassName issue in IE. How would I best implement the robert nyman (can't post the link to it since my rep is only 1) resolution into my code? Or would a jquery resolution be better? my code is
function showDesc(name) {
var e = document.getElementById(name);
//Get a list of elements that have a class name of service selected
var list = document.getElementsByClassName("description show");
//Loop through those items
for (var i = 0; i < list.length; ++i) {
//Reset all class names to description
list[i].className = "description";
}
if (e.className == "description"){
//Set the css class for the clicked element
e.className += " show";
}
else{
if (e.className == "description show"){
return;
}
}}
and I am using it on this page dev.msmnet.com/services/practice-management to show/hide the description for each service (works in Chrome and FF). Any tips would be greatly appreciated.
I was curious to see what a jQuery version of your function would look like, so I came up with this:
function showDesc(name) {
var e = $("#" + name);
$(".description.show").removeClass("show");
if(e.attr("class") == "description") {
e.addClass("show");
} else if(e.hasClass("description") && e.hasClass("show")) {
return;
}
}
This should support multiple classes.
function getElementsByClassName(findClass, parent) {
parent = parent || document;
var elements = parent.getElementsByTagName('*');
var matching = [];
for(var i = 0, elementsLength = elements.length; i < elementsLength; i++){
if ((' ' + elements[i].className + ' ').indexOf(findClass) > -1) {
matching.push(elements[i]);
}
}
return matching;
}
You can pass in a parent too, to make its searching the DOM a bit faster.
If you want getElementsByClassName('a c') to match HTML <div class="a b c" /> then try changing it like so...
var elementClasses = elements[i].className.split(/\s+/),
matchClasses = findClass.split(/\s+/), // Do this out of the loop :)
found = 0;
for (var j = 0, elementClassesLength = elementClasses.length; j < elementClassesLength; j++) {
if (matchClasses.indexOf(elementClasses[j]) > -1) {
found++;
}
}
if (found == matchClasses.length) {
// Push onto matching array
}
If you want this function to only be available if it doesn't already exist, wrap its definition with
if (typeof document.getElementsByClassName != 'function') { }
Even easier jQuery solution:
$('.service').click( function() {
var id = "#" + $(this).attr('id') + 'rt';
$('.description').not(id).hide();
$( id ).show();
}
Why bother with a show class if you are using jQuery?
Heres one I put together, reliable and possibly the fastest. Should work in any situation.
function $class(className) {
var children = document.getElementsByTagName('*') || document.all;
var i = children.length, e = [];
while (i--) {
var classNames = children[i].className.split(' ');
var j = classNames.length;
while (j--) {
if (classNames[j] == className) {
e.push(children[i]);
break;
}
}
}
return e;
}
I used to implement HTMLElement.getElementByClassName(), but at least Firefox and Chrome, only find the half of the elements when those elements are a lot, instead I use something like (actually it is a larger function):
getElmByClass(clm, parent){
// clm: Array of classes
if(typeof clm == "string"){ clm = [clm] }
var i, m = [], bcl, re, rm;
if (document.evaluate) { // Non MSIE browsers
v = "";
for(i=0; i < clm.length; i++){
v += "[contains(concat(' ', #"+clc+", ' '), ' " + base[i] + " ')]";
}
c = document.evaluate("./"+"/"+"*" + v, parent, null, 5, null);
while ((node = c.iterateNext())) {
m.push(node);
}
}else{ // MSIE which doesn't understand XPATH
v = elm.getElementsByTagName('*');
bcl = "";
for(i=0; i < clm.length; i++){
bcl += (i)? "|":"";
bcl += "\\b"+clm[i]+"\\b";
}
re = new RegExp(bcl, "gi");
for(i = 0; i < v.length; i++){
if(v.className){
rm = v[i].className.match(bcl);
if(rm && rm.length){ // sometimes .match returns an empty array so you cannot use just 'if(rm)'
m.push(v[i])
}
}
}
}
return m;
}
I think there would be a faster way to iterate without XPATH, because RegExp are slow (perhaps a function with .indexOf, it shuld be tested), but it is working well
You can replace getElementsByClassName() with the following:
function getbyclass(n){
var elements = document.getElementsByTagName("*");
var result = [];
for(z=0;z<elements.length;z++){
if(elements[z].getAttribute("class") == n){
result.push(elements[z]);
}
}
return result;
}
Then you can use it like this:
getbyclass("description") // Instead of document.getElementsByClassName("description")