Pure JavaScript alternative to jQuery's .not() - javascript

What would be the JS alternative to .not() from jQuery? I have $(".form :input").not, but need to transfer that to pure JS. Is there a guide that could help me?
var input = $(".form :input").not('button, [type="button"], [type="submit"]').on({
input: return
});
I'm looking to do that in JS

Modern browser do support a NOT clause in querySelectorAll():
document.querySelectorAll(".form :input:not(...)");
Example (jsFiddle):
<div>This should be colored!</div>
<div>This should be colored!</div>
<div id="this-not">This must not colored!</div>
<div>This should be colored!</div>
<div>This should be colored!</div>
var matchedElements = document.querySelectorAll("div:not(#this-not)");
for (var i=0; i<matchedElements.length; i++) {
matchedElements.item(i).style.backgroundColor = "red";
}

The equivalent in plain JS would be something like this
var forms = document.querySelectorAll('.form'),
inputs = [];
for (var i = forms.length; i--;) {
var els = forms[i].querySelectorAll('input, textarea, select');
for (var j = els.length; j--;) {
if (els[j].type != 'button' && els[j].type != 'submit') {
inputs.push(els[j]);
els[j].addEventListener('input', cback, false);
}
}
}
function cback(event) {
var b = [];
for (var i = inputs.length; i--;) {
if (!inputs[i].value.length) b.push(inputs[i]);
}
var l1 = b.length;
var l2 = inputs.length;
var top = document.querySelectorAll('.top');
for (var j = top.length; j--;) {
top[j].style.width = 100 - (l1 / l2) * 100 + "%";
}
}
FIDDLE

You could also use .filter() to exclude items in your array. You would use it like so (example from MDN):
function isBigEnough(element) {
return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
It's supported in all modern browsers and IE9+. See Array.prototype.filter() on MDN for more information.
Unfortunately .filter() only works on Arrays so we have to do some extra manipulating to filter a NodeList.
HTML:
<ul>
<li>1</li>
<li>2</li>
<li class="not-me">3</li>
<li>4</li>
<li>5</li>
</ul>
Javascript:
var filter = Array.prototype.filter;
var excludeByClassName = function(className) {
return function (element) {
return element.className != className;
};
};
var LIs = document.getElementsByTagName('li');
// [li, li, li.not-me, li, li]
var filteredLIs = filter.call(LIs, excludeByClassName('not-me'));
// [li, li, li, li]
See this jsFiddle for a working example.

Related

How to add child element after removing in javascript on page refresh

I have a list of items that dynamically changes based on select tag value. The problem is i have to remove old <li> and add new <li> tag after refresh. I used clearlist function for removal onload in body but it throws null error in x. please help. thanks
var x = document.getElementById("ul1");
for (var i = 0; i < results.length; i++) {
x.innerHTML= x.innerHTML + '<li>'+items+'</li>'
}
function clearlist(){
var elem = document.getElementById('ul1');
elem.parentNode.removeChild(elem);
}
By using removeChild(elem) you are removing <ul id="ul1"> from the DOM. Use innerHTML to clear the contents of the ul instead:
function addResults(results) {
var x = document.getElementById("ul1");
for (var i = 0; i < results.length; i++) {
x.innerHTML= x.innerHTML + '<li>'+results[i]+'</li>'
}
}
function clearlist(){
var elem = document.getElementById('ul1');
elem.innerHTML = "";
}
addResults([1, 2, 3, 4, 5]);
clearlist();
addResults([1, 2, 3]);
<ul id="ul1">
</ul>

How to get javascript for sorting lists with links working in all browsers?

So this is my javascript for sorting a lists (alphabetically) with links:
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]);
}
}
<div id="test"> Sort List
</div>
<ul id="list">
<li>apple</li>
<li>pie</li>
<li>banana</li>
</ul>
now this script works perfectly in safari, but in firefox for instance, it doesn't work.. how to get this work in all browsers?
You have to use textContent instead of innerText. innerText will return undefined in Firefox.
w3.org textContent
Demo
Try before buy
The problem you have in Firefox is probably due to the fact that the Document Object Model (DOM) is not ready and available when the JavaScript is executed. Different browsers handle things differently and when scripts are executed are one of those things.
What you need to do is to:
Wrap your code in a function
Execute that function when the page (DOM) is ready
You can use this to detect when the page is loaded:
var readyStateCheckInterval = setInterval(function() {
if (document.readyState === "complete") {
init(); // This is the function that would contain your code.
clearInterval(readyStateCheckInterval);
}
}, 10);

How to access multiple textbox by getElementsByName

I have written following code in html:
<input type="text" id="id_1" name="text_1">
<input type="text" id="id_2" name="text_2">
<input type="text" id="id_3" name="text_3">
Here I have to get all textBoxes in an array in javascript function whose id starts with "id". So, that I can get above two textBoxes in an array.
How to get all textBoxes whose id start with "id"?
var nodeList = document.querySelector("input[name^='text_'")
A nodeList should be sufficiently like an array for your purposes.
Note that support for querySelector might not be sufficient for your purposes (in which you will need to getElementsByTagName and then filter the results in a loop).
Alternatively you could use a library which provides its own selector engine. In YUI 3 you could:
var listOfYUIObjects = Y.all("input[name^='text_'");
Mootools, Prototype, jQuery and a host of other libraries provide similar functionality.
var ele = document.getElementsByTagName("input");
var matchingEle = [];
var eleName = '';
for (var i = 0; i < ele.length; ++i) {
el = ele[i];
eleName = el.getAttribute("name");
if (eleName && eleName.indexOf("text_") == 0) {
matchingEle.push(el);
}
}
You could use a generic function that filters a list of elements based on a pattern. This is useful if you want to do a similar thing in future but with different criteria on the properties.
http://jsfiddle.net/3ZKkh/
function filter(elements, pattern) {
var i, j, match, e, f = [];
for (i = 0; i < elements.length; i += 1) {
e = elements[i];
match = true;
for (j in pattern) {
if (pattern.hasOwnProperty(j)) {
if (!(j in e && pattern[j](e[j]))) {
match = false;
break;
}
}
}
if (match) {
f.push(e);
}
}
return f;
}
var pattern = {
'type': function (t) {
return t.toLowerCase() === 'text';
},
'name': function (t) {
return t.toLowerCase().search('text') === 0;
}
};
console.log(filter(document.getElementsByTagName("input"), pattern));
var list = document.getElementsByTagName('input'); //Array containing all the input controls
var textBoxArray = []; //target Array
for (var i = 0; i < list.length; i++)
{
var node = list[i];
if (node.getAttribute('type') == 'text' && node.getAttribute("id").substring(0, 1) == "id")
{
/*
insert matching textboxes into target array
*/
textBoxArray.push(node);
}
}

How to sort <ul><li>'s based on class with javascript?

I have a TODO list app with an Unordered list. Within it I have a few list items. The li classes are high,medium,low. I would like li's with the class high to be placed before li's with the class medium and last ones with low.
<ul id="tasks">
<li id="item3" class="priority low"><span></span><span>This is a low priority task</span></li>
<li id="item4" class="priority high"><></span><span>This is a high priority task</span></li>
<li id="item5" class="priority low"><span></span><span>This is another Low</span></li>
<li id="item7" class="priority medium"><span></span><span>And now a Medium</span></li>
</ul>
So the li with id of item4 should be first and then it should be item7 and then the li's with class low after.
Here's a pure JS version of #ŠimeVidas jQuery solution.
var tasks = document.querySelector('#tasks'),
items = document.querySelectorAll('#tasks > li');
for (var i = 0, arr = ['high', 'medium', 'low']; i < arr.length; i++) {
for (var j = 0; j < items.length; j++) {
if (~(" " + items[j].className + " ").indexOf(" " + arr[i] + " "))
tasks.appendChild(items[j]);
}
}
Assuming you can use jQuery, and assuming your list is not very big, and assuming you've only got these three fixed types with no plans on changing this, I'd probably just dump the whole set into memory, clear out the list, then put them back in the list in order. Something like:
jQuery(document).ready(function() {
var i;
var items = jQuery("#tasks li");
var lowItems = [];
var medItems = [];
var highItems = [];
for (i = 0; i < items.length; ++i) {
var jqItem = jQuery(items[i]);
if (jqItem.hasClass("low")) lowItems.push(jqItem);
if (jqItem.hasClass("medium")) medItems.push(jqItem);
if (jqItem.hasClass("high")) highItems.push(jqItem);
}
var tasks = jQuery("#tasks");
tasks.html("");
for (i = 0; i < highItems.length; ++i) {
tasks.append(highItems[i]);
}
for (i = 0; i < medItems.length; ++i) {
tasks.append(medItems[i]);
}
for (i = 0; i < lowItems.length; ++i) {
tasks.append(lowItems[i]);
}
});
Try this:
$(function(){
var sorter = [],
tasks = $('#tasks');
$('li.priority').each(function(){
var $this = $(this),
priority = $this.hasClass('high') ? 3 : ($this.hasClass('medium') ? 2 : 1);
sorter.push({
el : this,
priority : priority
});
}).detach();
sorter.sort(function(a, b){
return a.priority - b.priority;
});
$.each(sorter, function(){
tasks.append(this.el);
});
});
With no jquery:
<ul id="tasks">
<li id="item3" class="priority low"><span></span><span>This is a low priority task</span></li>
<li id="item4" class="priority high"><></span><span>This is a high priority task</span></li>
<li id="item5" class="priority low"><span></span><span>This is another Low</span></li>
<li id="item7" class="priority medium"><span></span><span>And now a Medium</span></li>
</ul>
<script type="text/javascript">
var tasks = document.getElementById("tasks");
var liElements = tasks.getElementsByTagName("li");
var lowPriority = [];
var mediumPriority = [];
var highPriority = [];
var removal = [];
for (var i = 0, len = liElements.length; i < len; i++) {
if (liElements[i].getAttribute("class").indexOf("low") > -1) lowPriority.push(liElements[i].cloneNode(true));
if (liElements[i].getAttribute("class").indexOf("medium") > -1) mediumPriority.push(liElements[i].cloneNode(true));
if (liElements[i].getAttribute("class").indexOf("high") > -1) highPriority.push(liElements[i].cloneNode(true));
removal.push(liElements[i]);
}
for (var i = 0, len = removal.length; i < len; i++ ) {
var liItem = removal[i];
liItem.parentNode.removeChild(liItem);
}
for( var i = 0, len = lowPriority.length; i < len; i++){
tasks.appendChild(lowPriority[i]);
}
for (var i = 0, len = mediumPriority.length; i < len; i++) {
tasks.appendChild(mediumPriority[i]);
}
for (var i = 0, len = highPriority.length; i < len; i++) {
tasks.appendChild(highPriority[i]);
}
</script>
Here's another jQuery–less option:
// Just a helper
function toArray(obj) {
var result = [];
for (var i=0, iLen=obj.length; i<iLen; i++) {
result[i] = obj[i];
}
return result;
}
// Uses querySelectorAll, but could use getElementsByTagName instead
function sortByPriority(id) {
var nodes;
var el = document.getElementById(id);
if (el) {
nodes = toArray(el.querySelectorAll('li.priority'));
nodes.sort(function(a, b) {
function getIndex(el) {
return el.className.indexOf('low') != -1? 1 :
el.className.indexOf('medium') != -1? 2 :
el.className.indexOf('high') != -1? 3 :
0; // default
}
return getIndex(b) - getIndex(a);
});
for (var i=0, iLen=nodes.length; i<iLen; i++) {
el.appendChild(nodes[i]);
}
}
}
It uses a few more lines that a jQuery (or perhaps any library) based solution but you don't have to load several thousand lines of library either.
Also, this runs about 5 times faster in Firefox and IE 9 and 10 times faster in Chrome than a jQuery solution (see http://jsperf.com/sortelementlist).
With pure JavaScript, and simple code!
var tasks = document.getElementById("tasks");
var lis = tasks.getElementsByTagName("li");
var lisarr = Array.prototype.slice.call(lis);
var priority = function(e){
var prio = {low: 0, medium: 1, high: 2};
return prio[e.getAttribute("class").match(/low|high|medium/)[0]];
};
lisarr.sort(function(a,b){
var ap = priority(a), bp = priority(b);
return bp - ap;
});
tasks.innerHTML = lisarr.reduce(function(prev, current){
return prev + current.outerHTML;
}, '');

javascript - shuffle HTML list element order

I have a list:
<ul>
<li>milk</li>
<li>butter</li>
<li>eggs</li>
<li>orange juice</li>
<li>bananas</li>
</ul>
Using javascript how can I reorder the list items randomly?
var ul = document.querySelector('ul');
for (var i = ul.children.length; i >= 0; i--) {
ul.appendChild(ul.children[Math.random() * i | 0]);
}
This is based on Fisher–Yates shuffle, and exploits the fact that when you append a node, it's moved from its old place.
Performance is within 10% of shuffling a detached copy even on huge lists (100 000 elements).
http://jsfiddle.net/qEM8B/
Simply put, like this:
JS:
var list = document.getElementById("something"),
button = document.getElementById("shuffle");
function shuffle(items)
{
var cached = items.slice(0), temp, i = cached.length, rand;
while(--i)
{
rand = Math.floor(i * Math.random());
temp = cached[rand];
cached[rand] = cached[i];
cached[i] = temp;
}
return cached;
}
function shuffleNodes()
{
var nodes = list.children, i = 0;
nodes = Array.prototype.slice.call(nodes);
nodes = shuffle(nodes);
while(i < nodes.length)
{
list.appendChild(nodes[i]);
++i;
}
}
button.onclick = shuffleNodes;
HTML:
<ul id="something">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<button id="shuffle" type="button">Shuffle List Items</button>
Demo: http://jsbin.com/itesir/edit#preview
var list = document.getElementById("something");
function shuffleNodes() {
var nodes = list.children, i = 0;
nodes = Array.prototype.sort.call(nodes);
while(i < nodes.length) {
list.appendChild(nodes[i]);
++i;
}
}
shuffleNodes();
Use this:
function htmlShuffle(elem) {
function shuffle(arr) {
var len = arr.length;
var d = len;
var array = [];
var k, i;
for (i = 0; i < d; i++) {
k = Math.floor(Math.random() * len);
array.push(arr[k]);
arr.splice(k, 1);
len = arr.length;
}
for (i = 0; i < d; i++) {
arr[i] = array[i];
}
return arr;
}
var el = document.querySelectorAll(elem + " *");
document.querySelector(elem).innerHTML = "";
let pos = [];
for (let i = 0; i < el.length; i++) {
pos.push(i);
}
pos = shuffle(pos);
for (let i = 0; i < pos.length; i++) {
document.querySelector(elem).appendChild(el[pos[i]]);
}
}
htmlShuffle("ul");
<ul>
<li>milk</li>
<li>butter</li>
<li>eggs</li>
<li>orange juice</li>
<li>bananas</li>
</ul>
Here is a very simple way to shuffle with JS:
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return 0.5 - Math.random()});
http://www.w3schools.com/js/js_array_sort.asp
I was searching for a prototype function. Maybe this helps someone.
Element.prototype.shuffleChildren = function() {
for (var i = this.children.length; i >= 0; i--) {
this.appendChild(this.children[Math.random() * i | 0]);
}
};
document.querySelector('body').shuffleChildren();
Here's a solution that does not use a loop.
function shuffle_children(element) {
element.append(...Array.from(element.children).sort(function () {
return Math.random() - 0.5;
}));
}
Based no #Alexey Lebedev's answer, if you prefer a jQuery function that shuffles elements, you can use this one:
$.fn.randomize = function(selector){
var $elems = selector ? $(this).find(selector) : $(this).children();
for (var i = $elems.length; i >= 0; i--) {
$(this).append($elems[Math.random() * i | 0]);
}
return this;
}
And then call it like this:
$("ul").randomize(); //shuffle all the ul children
$("ul").randomize(".item"); //shuffle all the .item elements inside the ul
$(".my-list").randomize(".my-element"); //shuffle all the .my-element elements inside the .my-list element.

Categories

Resources