I need to set the attribute ID to a group of <div> elements which are within a parent <div>.
The parent <div> has an ID, and some of the child <div> have an ID but others don't.
The HTML code would be:
<div id="my_parent_div">
<div id="my_child_div_a">Here is some text A</div>
<div>Here is some text B</div>
<div>Here is some text C</div>
<div>Here is some text D</div>
</div>
After applying Javascript/JQuery it should look:
<div id="my_parent_div">
<div id="my_child_div_a">Here is some text A</div>
<div id="new_added_id_b">Here is some text B</div>
<div id="new_added_id_c">Here is some text C</div>
<div id="new_added_id_d">Here is some text D</div>
</div>
I tried the following:
<script type="text/javascript">
$('div').each(function(eq, el) {
el = $(el);
if(typeof(el.attr('id')) === "undefined") {
el.attr('id', 'div-' + eq);
}
});
</script>
But it will give IDs to all <div> without an ID in the whole HTML document. I need to set the IDs only to the child elements of #my_parent_div that do not have one and I would like to set specific IDs (instead of id="div-10", id="div-11", id=div-12)
I appreciate your suggestions
Your selector is $('div') which will target all div elements on the page. To make it only select div under #my_parent_div use this selector instead : $('#my_parent_div div')
The code will now look like this :
<script type="text/javascript">
$('#my_parent_div div').each(function(eq, el) {
el = $(el);
if(typeof(el.attr('id')) === "undefined") {
el.attr('id', 'div-' + eq);
}
});
</script>
Update:
Answering your question on the comment
If you want to have a specific id name for each element I would say you create an array listing all the names.
var ids = ["cat", "dog", "rat", "chicken"];
Then create a variable which will count every time it loops so you can use that to get the name on that array on a certain loop.
So putting it all together, will look like this :
var count = 0;
$('#my_parent_div div').each(function(eq, el) {
var ids = ["cat", "dog", "rat", "chicken"];
el = $(el);
if(typeof(el.attr('id')) === "undefined") {
el.attr('id', ids[count]);
count++;
}
});
I'd suggest the following:
// select the relevant element(s),
// set the 'id' property of those elements using prop():
$('#my_parent_div div').prop('id', function (i,v) {
// the first argument ('i') is the index of the current
// element from amongst the collection,
// the second ('v') is the current value of the property
// we're accessing:
// if the current id is an empty string (v === '') or
// it's undefined ('undefined === typeof v)
// we set the id to the string 'new_added_id_' plus
// the String created from the character-code of 97 ('a')
// plus the element's index in the collection. Otherwise,
// if the id is set we return the existing id:
return v === '' || 'undefined' === typeof v ? 'new_added_id_' + String.fromCharCode(97 + i) : v;
});
$('#my_parent_div div').prop('id', function(i, v) {
return v === '' || 'undefined' === typeof v ? 'new_added_id_' + String.fromCharCode(97 + i) : v;
});
div {
width: 80%;
margin: 0 auto 0.5em auto;
border: 2px solid #000;
}
div > div[id]::before {
content: 'ID: ' attr(id);
color: #f00;
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="my_parent_div">
<div id="my_child_div_a">Here is some text A</div>
<div>Here is some text B</div>
<div>Here is some text C</div>
<div>Here is some text D</div>
</div>
External JS Fiddle demo, for experimentation.
References:
JavaScript:
String.fromCharCode().
typeof.
jQuery:
prop().
Related
I need to pull the text content from a DOM selector, that contains delivery information, including country name, which I need to put in a variable.
I have a list of the possible countries:
var countries = [
"France",
"Denmark",
"Finland"
];
And the DOM selector:
var dom_Selector = document.querySelector("#primary > div > table.Order > tbody > tr > td > table > tbody > tr > td > table > tbody > tr:nth-child(2) > td:nth-child(1)");
Here is a sample of the HTML content of this td-element:
<br>Firstname Lastname<br>Street name<br>Postalcode City<br>Country<br><br>Leveres til:<br>Pickup location<br>Firstname Lastname<br>Street name<br>Postal code and city<br>Country<br>
So the challenge is that the selector doesnt wrap the country string; therefore the entire contents of the selector needs to be searched.
If there is a match to the array of countries, I then need to return which country is matched.
Then there is a second step, which is that I need to match the country name to a country code; e.g. France -> FR, Denmark -> DK, Finland -> FI.
So the result from the text content of the selector will be for instance "FI" - a country code. And this needs to be put in a variable.
document.querySelector returns only the first element within the document that matches the specified selector. IF you want to iterate over all the elements that could match the selector you need to use querySelectorAll
const selector = document.querySelectorAll('.container .country');
let countries = [];
selector.forEach((node) => {
countries.push(node.innerText);
});
console.log(countries);
<div class="container">
<span class="country">France</span>
<span class="country">Spain</span>
<span class="country">Germany</span>
</div>
Use querySelectorAll method instead of querySelector.
var countries = [];
document.querySelectorAll(".content .Delivery_TD").forEach(function(itm) {
countries.push(itm.textContent);
});
console.log(countries);
<div class="content">
<div class="Delivery_TD"> C1 </div>
<div class="Delivery_TD"> C2 </div>
<div class="Delivery_TD"> C3 </div>
<div class="Delivery_TD"> C4 </div>
</div>
If I understood correctly what you want to do,
I suggest you to to that kind of things:
(See snippet for working example, and comments in the code)
var countries = [
"France",
"Denmark",
"Finland"
];
// Example of code only for 1 element
console.log("Result for a querySelector:");
var dom_Selector = document.querySelector("body > div.content.Delivery_TD");
// The query selector above will return only the first matching element
countries.forEach(function(val) {
if (dom_Selector.innerHTML.includes(val)) {
console.log(val, ": found!");
}
});
// For multiple elements
console.log("Results for a querySelectorAll:");
var dom_Selector = document.querySelectorAll("body > div.content.Delivery_TD");
// The query selector above will return all the matching elements
dom_Selector.forEach(function(elm) {
countries.forEach(function(val) {
if (elm.innerHTML.includes(val)) {
console.log(val, ": found!");
}
});
});
body>div.content.Delivery_TD {
border: 1px solid black;
padding: 4px 8px;
}
<body>
<div class="content Delivery_TD">
Delivery from France the 05/03/2018 at 09:50PM
</div>
<div class="content Delivery_TD">
Delivery from Finland the 05/06/2018 at 11:50AM
</div>
<div class="content Delivery_TD">
Delivery from Denmark the 05/04/2018 at 06:20PM
</div>
</body>
I hope it helps!
UPDATE
First of all you want your array of countries to be associative in order to have the information of the key (FR, FN etc)
Something like that
var countries = {
"FR": "France",
"DN": "Denmark",
"FN": "Finland"
}
Then you can find the code from the country inside the string like that
var dom_Selector = ..... Your selector
var dom_Selector_text = dom_Selector.textContent;
// or
// var dom_Selector_text = dom_Selector.firstChild.nodeValue;
var result = "";
for (var key in countries) {
if(dom_Selector_text.indexOf(countries[key]) !== -1){
result = key;
}
}
return result
I have an array of numbers which I need to target on pages like this:
sku = [1243,3453,6453, ..... ]
These values are inside a div on a page like this:
<div id="product_1243">
<div class="block">
test
</div>
</div>
<div id="product_3453">
<div class="block">
test
</div>
</div>
<div id="product_6453">
<div class="block">
test
</div>
</div>
I have created a function to check if a number from the array exists in this div:
sku.forEach(function (element) {
if ($("div[id*='product_item_code_" + element +"']").length) {
alert("this exists" + element);
}
});
This works, but I want to ask two questions:
1) How to use insertAfter below to insert some HTML after each <div class="block">. It should only get inserted if the statement is true of course.
$("<p>test!</p>").insertAfter(....);
2) if this is best for performance because my array is actually much much bigger with over 1000 values to check for in the forEach.
Thanks
Use append or appendTo if block is the only child of product_***
var $el = $("div[id*='product_item_code_" + element +"']");
if ( $el.length) {
alert("this exists" + element);
$("<p>test!</p>").appendTo( $el );
}
or
var $el = $("div[id*='product_item_code_" + element +"']");
if ( $el.length) {
alert("this exists" + element);
$el.append( "<p>test!</p>" )
}
In case block is not the only child
var $el = $("div[id*='product_item_code_" + element +"']");
if ( $el.length) {
alert("this exists" + element);
$("<p>test!</p>").insertAfter( $el.find( ".block" ) );
}
How about this? Store products instead of querying it each time as it affects performance.
const products = $('div[id^=product_item_code]')
products.each((index, element) => {
if(sku.includes(element.id.split('_')[1]))
$('.block', element).after('<p>test!</p>')
})
I have a label in a form defined as follows and the jQuery code below locates the 'Description' label and changes it for me to 'Program Description':
$(".ms-accentText").filter(function () {
return $(this).text() == "Description";
}).text('Program Description');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3 class="ms-accentText">Description</h3>
But I have another label of 'Name' that has html markup that is used to tag the label with an asterisk, to define the associated field as being required, as listed below:
The similar jQuery code which is listed below does not locate and change the label:
$(".ms-accentText").filter(function () {
return $(this).text() == "Name";
}).text('Program Name');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3 class="ms-accentText">Name<span class="ms-formvalidation"> * </span></h3>
How can I target the 'Name' label, when the extra asterisk related html mark-up code included?
I'm new to using jQuery.
Thanks,
Wayne
By using combination of :contains jquery selector + append you can achieve more efficient flow:
$(() => {
const query = 'Name'
const $name = $(`.ms-accentText:contains(${query})`)
.filter(function () {
const textChildTexts = [...this.childNodes]
// filtering to select only direct text nodes
// to skip the asterisk part
.filter(node => node && node.nodeType === Node.TEXT_NODE)
// getting the text out of node
.map(node => node && node.textContent)
// joining all the texts into a string to compare
.join('');
return textChildTexts === query;
});
const $asterisk = $name.find('.ms-formvalidation');
$name.text('Program Name').append($asterisk);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3 class="ms-accentText">Name<span class="ms-formvalidation"> * </span></h3>
<h3 class="ms-accentText">Project Full Name<span class="ms-formvalidation"> * </span></h3>
You could create a custom filtering function that removes any descendant elements and trims the containing text, and use that like this
function f(what) {
return function(index, elem) {
var clone = $(elem).clone();
clone.find('*').remove();
return clone.text().trim() === what;
}
}
$(".ms-accentText").filter(f('Description')).css('color', 'blue');
$(".ms-accentText").filter(f('Name')).css('color', 'red');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3 class="ms-accentText">Description</h3>
<h3 class="ms-accentText">Name<span class="ms-formvalidation"> * </span></h3>
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>
<div id="table1"></div>
<div id="table2"></div>
<div id="table3"></div>
<div id="table4"></div>
<div id="table5"></div>
...
How to select all elements with "table" and an ID > 4.
Something like this might help you:
var test = /table(\d+)/;
$("[id^='table']").filter(function () {
return parseInt(test.exec(this.id)[1], 10) > 4;
});
It will match all elements starting with 'table' and then filter out those ending with values smaller than or equal to 4.
You can go over each element that the id starts with table [id^='table'] and check if the rest (the number) is bigger than 4
Example here http://jsfiddle.net/fLg00oxq/2/
$("[id^='table']").each(function(){
var id = $(this).attr('id').substr(5); // remove table and leave just the number
if(id > 4 ){
// Your code here
}
});
Edit, Updated
Try
v1 (for numerically ordered id's , i.e.g., table1 -> table2)
$("[id=table4] ~ [id*=table]")
v2 (unordered id's)
$("[id*=table]").not(function() {
// return elements that _don't_ match the selector ,
// `id` cast as `Number` <= 4
return this.id.match(/\d+/)[0] <= 4
})
See
Attribute Equals Selector [name="value"]
Next Siblings Selector (“prev ~ siblings”)
Attribute Contains Selector [name*="value"]
.not()
$("[id*=table]").not(function() {
// return elements that _don't_ match the selector ,
// `id` cast as `Number` <= 4
return this.id.match(/\d+/)[0] <= 4
})
.each(function() {
this.innerText = this.id
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="table10"></div>
<div id="table2"></div>
<div id="table9"></div>
<span></span>
<div id="table6"></div>
<div id="table5"></div>
<div id="table1"></div>
<div id="table7"></div>
<div id="table8"></div>
<div></div><br />
<div id="table3"></div>
<div id="table4"></div>
If your div they ordered will in example:
Edit your HTML :
<div class="table"></div>
<div class="table"></div>
<div class="table"></div>
<div class="table"></div>
<div class="table"></div>
Scripts
$(document).ready(function() {
$('.table:gt(2)').each(function() {
// Apply your functions for each div ....
});
}
This will do it:
$("div[id^=table]").slice(4);
Basically it selects all the div elements with id starting with "table". After that it removes four first matches and returns all the remaining jQuery objects.
So this has an assumption that there is <div id="table1"> ... <div id="table2"> ... <div id="table[n+1]">.
demo
var $tables = $('[id^=table]').filter(function(){
return +this.id.replace(/\D+/,'') > 4;
});
$tables.hide(); // Use example
the above will get the number out of the selector ID and compare if greater than 4. $tables will now result in a collection of elements returned by the jQuery's filter() method.
.replace(/\D+/,'') will remove all non-numeric (D+) Characters; the unary + will convert the String result to Number and > 4 does the desired.
For a micro-Plugin extension you can go for:
// Retrieve elements from mixed ID str+number
// Returns a collection of elements with ID number greather than the num argument
$.fn.idNumGreaterThan = function(num){
return this.filter(function() {
return +this.id.replace(/\D+/,'') > num;
});
};
$('[id^=table]').idNumGreaterThan(4).hide();
// Also with class selectors (element must have a mixed alphaNumeric ID)
$('.element').idNumGreaterThan(4).hide();
You can try with this code, however i think that there are better ways to do it:
for (var i = 4; i <= 100; i++) {
$('#table'+i)...
};
You Could try the contain selector like so $('div[id~=table]')
Reference http://api.jquery.com/attribute-contains-word-selector/