Here is a simple example of a group of divs that can be sorted either by their HTML content or by custom attribute values:
Sort alphabetically by HTML content
Sort low to high by the value of the attribute "sortweight"HTML:
I have tried following code and got error
ReferenceError: $$ is not defined
HTML
<div id="sortexample">
<div class="sortitem" sortweight="5">Pears [sortweight: 5]</div>
<div class="sortitem" sortweight="3">Apples [sortweight: 3]</div>
<div class="sortitem" sortweight="1">Cherries [sortweight: 1]</div>
<div class="sortitem" sortweight="4">Oranges [sortweight: 4]</div>
<div class="sortitem" sortweight="2">Strawberries [sortweight: 2]</div>
</div>
JavaScript:
// sort all divs with classname 'sortitem' by html content
function sort_div_content() {
// copy all divs into array and destroy them in the page
divsbucket = new Array();
divslist = $$('div.sortitem');
for (a=0;a<divslist.length;a++) {
divsbucket[a] = divslist[a].dispose();
}
// sort array by HTML content of divs
divsbucket.sort(function(a, b) {
if (a.innerHTML.toLowerCase() === b.innerHTML.toLowerCase()) {
return 0;
}
if (a.innerHTML.toLowerCase() > b.innerHTML.toLowerCase()) {
return 1;
} else {
return -1;
}
});
// re-inject sorted divs into page
for (a=0;a<divslist.length;a++) {
divsbucket[a].inject($('sortexample'));
}
}
// sort by attributes - usage for our example: sort_div_attribute('sortweight');
function sort_div_attribute(attname) {
// copy all divs into array and destroy them in the page
divsbucket = new Array();
divslist = $$('div.sortitem');
for (a=0;a<divslist.length;a++) {
divsbucket[a] = new Array();
// we'vev passed in the name of the attribute to sort by
divsbucket[a][0] = divslist[a].get(attname);
divsbucket[a][1] = divslist[a].dispose();
}
// sort array by sort attribute content
divsbucket.sort(function(a, b) {
if (a[0].toLowerCase() === b[0].toLowerCase()) {
return 0;
}
if (a[0].toLowerCase() > b[0].toLowerCase()) {
return 1;
} else {
return -1;
}
});
// re-inject sorted divs into page
for (a=0;a<divslist.length;a++) {
divsbucket[a][1].inject($('sortexample'));
}
}
I dont know why i got this error
On the fifth line, it says divslist = $$('div.sortitem');, but $$ is not defined. You have to use $ instead of $$.
divslist = $('div.sortitem'); This would be better
Related
Is there a way with JS/JQuery to create an array with a different variable for each of the following specific elements in my page?
<div id#1-hello></div>
<div id#2-hello></div>
...etc
and give them a value depending on the class name attached to that element? (for instance if the class name is count-2 value will be 2)
Right what I'm doing is not really efficient as I'm repeating a lot of my functions, and have to manually add more whenever I want to add new html elements:
var pets = ["Error", "Fish", "Wolf", "Whale", "Zebra", "Ferret"];
var petClass = $('#1-fish').hasClass('petClass')
switch(petClass) {
case 'count-0':
pets[1] = 0;
break;
case 'count-1':
pets[1] = 1;
break;
case 'count-2':
pets[1] = 2;
break;
case 'count-3':
pets[1] = 3;
break;
default:
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="1-fish" class="map-marker count-0"></div>
<div id="2-wolf" class="map-marker count-2"></div>
<div id="3-whale" class="map-marker count-3"></div>
<div id="4-zebra" class="map-marker count-1"></div>
<div id="5-ferret" class="map-marker count-1"></div>
You question is a bit vague. Are you looking for something like this?
var pets = ["Error", "Fish", "Wolf", "Whale", "Zebra", "Ferret"];
var petCounts = {};
pets.each(function (pet) {
var petCountDivs = $('[id$="'+pet+'"]').find('petClass');
petCountDivs.each(function () {
var countClass = $(this).attr("class").split(/\s+/).find(function(maybeCountClass) {
return maybeCountClass.startsWith("count");
}
var petCount = countClass.substring(countClass.lastIndexOf('-'));
if (petCounts[pet]) {
petCounts[pet] += petCount;
} else{
petCounts[pet] = petCount;
}
});
});
This first uses the $= selector to find elements whose 'id' attribute "ends with" the specified petname from the pets array, then uses .find('petClass') on those elements, so that var petCountDivs is a collection of all the elements that are inside pet-named divs that have the petClass class.
Then looping through each of those petCountDivs, it grabs the name of the class that starts with the word "count", and parses the value that comes after the dash ('-'), then either creates a new count object or aggregates to the existing counter that parsed value.
I'm building my little lib js.
my intent is to have both possibilities in this way:
//this:
core.find(".myclass").myAction (actor);
var target = core.target (".myclassname");
core.myAction (target, actor);
//or:
core.find(".myclass").myAction (actor);
var target = core.find(".myclassname");
core.myAction (target, actor);
//so, return the finded for core and gearcore, but
//I can not and I do not think it's feasible (is it?)
//this isn't a good solution... thanks.
//var target = core.find(".myclassname");
//target .myAction (target, actor);
anyway... the first is chained, the second part from the first class and generates the action through a parameter.
yes, I already know that I can create a copy of the functions, but it's disgusting ... and copy the target how can I solve it?
here it's about joining the two "find" or putting the two return or joining the two return or something else or maybe something similar.
for convenience: lib in jsfiddle else...
LIB:
note 1:the two eval functions are just a demo to get an answer. the complete lib contains more and I need to assign the target in both ways
class coregears {
constructor(gear) {
this.gear = gear;
}
actor(target, fname) {
alert("inside actor");
let t_, f_;
(1 == arguments.length) ? (t_ = this.gear, f_ = target) : (t_ = target, f_ = fname);
t_.forEach((looped) => { eval(f_)(looped); return this.gear});
}
}
class Core {
// return for core.function(target,actor);
target(subject)
{
let name;
var finded;
if (subject.startsWith(".")) {
name = subject.split(".")[1];
finded = [...document.getElementsByClassName(name)];
}
if (subject.match(/\B\#\w\w+\b/g)) {
name = subject.replace(/#(\S*)/g, 'ID_$1').split("ID_")[1];
finded = [...document.querySelectorAll("#" + name)];
}
if (subject.startsWith("[")) {
finded = [...document.querySelectorAll(subject)];
}
return finded;
}
// return for core.find(target).function(actor);
find(subject){
let name;
if (subject.startsWith(".")) {
name = subject.split(".")[1];
find = [...document.getElementsByClassName(name)];
}
if (subject.match(/\B\#\w\w+\b/g)) {
name = subject.replace(/#(\S*)/g, 'ID_$1').split("ID_")[1];
find = [...document.querySelectorAll("#" + name)];
}
if (subject.startsWith("[")) {
find = [...document.querySelectorAll(subject)];
}
return new coregears(find);
}
}
const core = new Core();
SCRIPT:
//chain
core.find(".test_Y").actor(myactor_1);
function myactor_1(looped) {
alert("actor_1");
looped.style = "font-weight: bold; color: magenta;";
};
//direct
var mytarget = core.target(".test_X");
core.actor(mytarget,myactor_2);
function myactor_2(looped) {
alert("actor_2");
looped.style = "font-weight: bold; color: green;";
};
HTML:
<div class="test_X">SIMPLE TEST CLASS</div>
<div class="test_X">SIMPLE TEST CLASS</div>
<div class="test_X">SIMPLE TEST CLASS</div>
<div class="test_Y">SIMPLE TEST CLASS</div>
<div class="test_Y">SIMPLE TEST CLASS</div>
<div class="test_Y">SIMPLE TEST CLASS</div>
Idea?
update: I replaced the eval with f_.call(this,looped); thank you #Shilly.
I'm trying to order the different products from a website but can't do it correctly.
Basically I need to get the price of each one and order them from the most expensive one to the least one.
I tried the following code but it disappears everything and keeps not ordering them in the correct way:
var divList = $(".block-level.h2");
divList.sort(function(a, b){
return $(a).data(".block-level.h2")-$(b).data(".block-level.h2")
});
$(".grid").html(divList);
I don't have access to modify the HTML so it has to be done with the code I have now, only can add things through jQuery.
Can someone give me a tip or help me out please?
Thank you.
For your request to sort the product grid items, here is the jQuery code that you can use.
var values = [];
$('.block-level.h2').each(function() {
var temp = Array();
temp['value'] = parseInt($(this).html().replace('$',''));
temp['element'] = $(this).closest('.grid-item');
values.push(temp);
});
values.sort(function(a,b) { return b.value - a.value; });
var sortedHtml = '';
$.each(values, function(index, obj) {
if((index+1)%3==1) {
sortedHtml+=('<div class="grid product-cards__row"><div class="grid-item one-third palm-one-whole product-cards__item">'+$(obj.element).html()+'</div>');
} else if((index+1)%3==0) {
sortedHtml+=('<div class="grid-item one-third palm-one-whole product-cards__item">'+$(obj.element).html()+'</div></div>');
} else {
sortedHtml+=('<div class="grid-item one-third palm-one-whole product-cards__item">'+$(obj.element).html()+'</div>');
}
});
$('.product-cards').html(sortedHtml);
Hope this helps!
You can achieve this by the following code-
var values = Array();
$('.block-level.h2').each(function() {
values.push(parseInt($(this).html().replace('$','')));
});
values.sort(function(a, b){return b-a});
In your code above - the main problem is with $(a).data(".block-level.h2") since its trying to find an attribute with name data-.block-level.h2 in element a which doesn't exist. That's why the empty result.
I need to find all elements in a page by attribute value only (ignoring the key) using jquery.
Is there a way to do this easily?
Currently, I am just iterating on all elements in the page, on every property etc..
You can use $.expr, Element.attributes, Array.prototype.some()
$.expr[":"].attrValue = function(el, idx, selector) {
return [].some.call(el.attributes, function(attr) {
return attr.value === selector[selector.length - 1]
})
};
// filter element having attribute with `value` set to `"abc"`
$(":attrValue(abc)").css("color", "blue");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div title="abc">abc</div>
<div title="def">def</div>
<div title="ghi">ghi</div>
<div title="jkl">jkl</div>
Use brackets []
var ElementsWithAttributeKeyTest = $('[attributeKey="Test"]');
Or pass an object with the attribute name and value as parameter to this function:
var getElemsByAttribute = function(obj) {
if (obj) {
if (obj.attributeKey && obj.attributeValue) {
return $('[' + obj.attributeKey + '="' + obj.attributeValue + '"]');
}
}
}
var attrObj = {
attributeKey: 'data-color',
attributeValue: 'red'
}
getElemsByAttribute(attrObj).css('color', 'red');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<span data-color="red">Red</span>
<span data-color="red">Red</span>
<span data-color="green">Green</span>
<span data-color="blue">Blue</span>
<span data-color="red">Red</span>
<span data-color="green">Green</span>
If you want to search all attributes values you can use this small plugin:
$.fn.search_by_attr_value = function(regex) {
return this.filter(function() {
var found = false;
$.each(this.attributes, function() {
if (this.specified && this.value.match(regex)) {
found = true;
return false;
}
});
return found;
});
};
and you can use it like this:
$('*').search_by_attr_value(/^some value$/);
Based on this answer
You could define new function take as parameter the value you want to filter with (e.g get_elements_by_value(filter)), then inside this function parse all the elements of the page using $('*').each(), after that parse the attributes of every element el of those elements using attribute attributes like below :
$.each(el.attributes, function(){ })
Then inside the each loop you could make your condition and push the matched values with the passed filter inside matched[] that should be returned.
Check working example below, hope this helps.
function get_elements_by_value(filter){
var matched=[];
$('*').each(function(index,el) {
$.each(el.attributes, function() {
if( this.value===filter )
matched.push(el);
})
})
return $(matched);
}
get_elements_by_value('my_value').css('background-color','green');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div title="my_value">AA</div>
<div title="def">BB</div>
<input type='text' name='my_value' value='CC'/>
<p class='my_value'>DD</p>
<span title="test">EE</span>
I have many DIVs on my page with the same ID
eg:
<div id="myDiv1">
...
</div>
<div id="myDiv2">
...
</div>
<div id="myDiv3">
...
</div>
...
<div id="myDiv20">
...
</div>
...
As You see, the ID property looks almost the same - the only diffrence is that there is a number in each ID.
How to get the count of that DIVs? I thought I can do something like that:
var myDivs= document.getElementById('myDiv');
but returns null
You can do this using jQuery like this:
$('div[id^=myDiv]')
If you can't use jQuery, you'll need to call getElementsByTagName and loop through the values checking the ID property.
var divs = document.getElementsByTagName('div');
var counter = 0;
for(var i in divs) {
if(divs[i].id.indexOf('myDiv') === 0) {
counter++;
}
}
or just
document.querySelectorAll('[id^=myDiv]').length
you can use jquery
//this will give you all divs start with myDiv in the id
var divs = $("div[id^='myDiv']");
From this site:
function getElementsByRegExpId(p_regexp, p_element, p_tagName) {
p_element = p_element === undefined ? document : p_element;
p_tagName = p_tagName === undefined ? '*' : p_tagName;
var v_return = [];
var v_inc = 0;
for(var v_i = 0, v_il = p_element.getElementsByTagName(p_tagName).length; v_i < v_il; v_i++) {
if(p_element.getElementsByTagName(p_tagName).item(v_i).id && p_element.getElementsByTagName(p_tagName).item(v_i).id.match(p_regexp)) {
v_return[v_inc] = p_element.getElementsByTagName(p_tagName).item(v_i);
v_inc++;
}
}
return v_return;
}
Usage:
var v_array = getElementsByRegExpId(/^myDiv[0-9]{1,2}/);