I'm trying to search an array of HTML elements with search value from another array. Inside a function getElement() there is an array order which holds string value. This array determines the order of search. Also there is another array elements with all the html elements to be searched. The function block looks like
getElement(){
const order = ['email-error', 'name-error', 'age-error'];
const elements = document.querySelectorAll('[data-status]')
}
When there is a validation error, html elements will be attached with data-status property. In case of a validation error, the getElement() function is called. The value of the data-status will be email-error for email input, name-error for name input etc.
What I'm trying to achieve is; for eg: take a value from order array, say email-error. Search the elements array if it has an element with data-status="email-error". If it exists, return the element and stops the search; else search with all values from order array.
I've written some HTML to test the code.
This is is the way to do it, if you want to loop over all array values and check:
function getElement() {
const order = ['email-error', 'name-error', 'age-error'];
const elements = document.querySelectorAll('[data-status]')
let foundElement = null
elements.forEach((elem) => {
if (order.includes(elem.getAttribute('data-status')) && !foundElement) {
foundElement = elem
}
})
return foundElement
}
console.log(getElement())
<div data-status="email-error"></div>
<div data-status="name-error"></div>
<div data-status="test-class"></div>
Maybe you could do a function on your own like this:
https://stackoverflow.com/a/784015/13604954
Or use the built-in Array.prototype.includes:
https://stackoverflow.com/a/40717204/13604954
You could implement a nested loop.
for(let i = 0; i < order.length; i++) {
for(let j = 0; j < elements.length; j++) {
if( order[i] == elements[j] ) {
return orders[i]
}
}
}
This will loop through both arrays fully, matching each value from one array to each value from the other unless there's a match, in which case it would return the matching element and break the loop.
You could also use the built in JS .forEach() method, which automatically loops through arrays.
order.forEach(orderEl => {
elements.forEach(elementEl => {
if (orderEl === elementEl) {
return orderEl
}
})
})
Related
I would like to write a JS generic function that can process indifferently a single element selected by its ID or multiple element selected by class.
var el1 = document.getElementById('myId');
myFunction(el1)
var el2 = document.getElementsByClassName('myClass');
myFunction(el2)
My problem is to write the function. I started something like:
function myFunction(el) {
if (typeof el == undefined) process(el);
else {
for (let i=0 ; i<el.length ; i++)
process(el[i]);
}
}
I'm not really confident in this solution:
not sure about the test (typeof ... == undefined)
not sure about the loop, map should probably be a better option
Since this should be something commonly used, I'm convinced that some of you has already think to the best way to write this code.
You can probably just accomplish this via a wrapper for the querySelectorAll() function, which is a built-in function used to easily query the DOM:
function myFunction(selector) {
return document.querySelectorAll(`#${selector}`) || document.querySelectorAll(`.${selector}`);
}
This will return a NodeList of the matching elements (first checking for a given id attribute and if that fails, attempting to find any elements sharing the same name as a class attribute).
So if you wanted to perform some process, you could simply throw an iterator on the result if one exists and perform it against each element:
function myFunction(selector) {
let nodes = document.querySelectorAll(`#${selector}`) || document.querySelectorAll(`.${selector}`);
if(nodes) {
for (var i = 0, i < nodes.length; i++) {
process(nodes[i]);
}
}
}
Example
function myFunction(selector) {
return document.querySelectorAll(`#${selector}`) || document.querySelectorAll(`.${selector}`);
}
<div id='id'>id</div>
<div class='class'>class</div>
<br />
<button onclick='alert(myFunction("id"));'>Find By ID</button>
<button onclick='alert(myFunction("class"));'>Find By Class</button>
I have two array with objects inside in it. I want to compare the values of a particular key from both arrays and do something with that. I have tried using inArray but couldn't succeed. Below is my code.
function initialize() {
geometry = 'http://yyyy.cartodb.com/api/v2/sql?q=SELECT name,ST_AsGeojson(the_geom) from msa_usa';
$.getJSON(geometry,
function(data) {
var place_names = [];
place_names.push({
name: "Abilene",
average: 8.65
});
for (i = 0; i < place_names.length; i++) {
if ($.inArray(data.rows[i].name, place_names[i].name) > -1) {
geom.push((data.rows[i].st_asgeojson));
average_value.push(place_names[i].average);
} else
(console.log("else"));
//console.log(place_names[i].name);
}
})
}
console.log(average_value.length);
console.log(geom.length);
I'm not sure why you're trying to use $.inArray() at all. It appears you're just trying to compare two properties on two objects (which happen to be in arrays, but you're already indexing to a particular object). If that's the case, then you can just directly compare the two properties:
if (data.rows[i].name === place_names[i].name)
But, in your code, you appear to have just created place_names so it will only have one value in it, not a whole bunch of values in it. So, now that confuses me as to what you're really trying to do here.
For more help, please describe in words what you're really trying to accomplish. Are you just trying to see if one particular .name property is in the data.rows array of objects?
If so, that would be a different piece of code like this:
function findPropInArray(array, propName, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][propName] === value) {
return i;
}
}
return -1;
}
Then, in your code you could use something like this:
if (findPropInArray(data.rows, "name", "Abilene") !== -1) {
// "Abilene" was as a name property in data.rows
}
According to the docs,
{name:"M", phone:"1"} predicate will return an array of items which have property name containing "M" and property phone containing "1".
I want to implement an or between those keys. for example it should return the rows which have property name containing "M" and also the rows having phone property containing "1".
Is there any expression by which I can do that? or I'll have to implement a custom filter for the same
you may try array filter method
list.filter(function(element){ return element.name.includes('M'); })
Can also try jquery
$.grep:
$.grep(list, function(element){ return element.name.includes('M'); })
Not sure if it's too early to conclude but it looks like creating a custom filter is the solution.
Here's it is,
.filter('orFilter', function () {
return function (list, filterOn) {
var out = [];
for (var i = 0; i < list.length; i += 1) {
var item = list[i];
for (var key in filterOn) {
var val = filterOn[key];
if (~item[key].indexOf(val)) {
out.push(item);
break;
}
}
}
return out;
}
});
I'll wait if someone posts a better solution.
if(document.readyState === 'complete') {
function $(elements) {
var matches = document.querySelectorAll(elements);
for (var i = 0; i < matches.length; i++) {
var item = matches[i];
}
return item;
}
}
$('div.test').style.fontSize = '36px';
<div class="test">asdf</div>
<div class="asdfd">test</div>
<div class="test">test</div>
I'd like to select all elements using querySelectorAll, but this seems to only affect the last element.
You are assigning the variable within the loop which will only return the last one. You should build an array of matches by declaring the variable outside of the loop or return the matches:
function $(elements) {
return document.querySelectorAll(elements);
}
Or:
function $(elements) {
var matches = document.querySelectorAll(elements);
var items = [];
for (var i = 0; i < matches.length; i++) {
items.push(matches[i]);
}
return items;
}
You assign each item to var item in turn.
After you've assigned the last one, you return the current value of item (which is the last one).
Return matches and then loop over it to set the font size of each item in turn.
Let's take a look at what your $ function is doing.
Select all items which match the query
Assign the first item in the list to item...
Assign the nth item to item
Return item which now contains the last element
So $() returns only the last element, and on that object, you are doing the assignment .style.fontSize = '36px'
There is no simple way to implement $ to do exactly what you are trying to. You could try a function which is called like this:
$(selector, {
fontSize : "36px"
});
It would look something like this:
function $(selector, properties) {
var matches = document.querySelectorAll(selector);
for (var i = 0; i < matches.length; i++) {
for (var j in properties) {
matches[i].style[j] = properties[j];
}
}
}
I'd recommend you fully understand what this is doing before moving on.
Also, the way you have used document.readyState makes it redundant. You should enclose the function call in your document.readyState, not the definition.
The variable item not is a array, then it is being overrided on each iteration loop.
Or define a array in order by save all selectors, or add the return in for loop.
Of course! the variable item holds the current iteration match. After the for cycle completes, it will naturally hold the last matched element. Javascript is executed sequentially, meaning the return statement will be executed after the forcycle.
I see you are trying to use chaining. This won't work with your current structure as your selector function will only ever return the last matched element from your querySlectorAll.
I think in this case it would be better to either pass a function that you want to do to each element or return an array/nodelist for another function to use;
function $(elements, method) {
var matches = document.querySelectorAll(elements);
for (var i = 0; i < matches.length; i++) {
method(matches[i]);
}
}
$('div.test', function (elem) {elem.style.fontSize = '36px';});
if(document.readyState === 'complete') {
function $(elements) {
var matches = document.querySelectorAll(elements);
for (var i = 0; i < matches.length; i++) {
var item = matches[i];
}
return item;
}
}
$('div.test').style.fontSize = '36px';
<div class="test">asdf</div>
<div class="asdfd">test</div>
<div class="test">test</div>
I need to get the ID of an element but the value is dynamic with only the beginning of it is the same always.
Heres a snippet of the code.
<form class="form-poll" id="poll-1225962377536" action="/cs/Satellite">
The ID always starts with poll- then the numbers are dynamic.
How can I get the ID using just JavaScript and not jQuery?
You can use the querySelector for that:
document.querySelector('[id^="poll-"]').id;
The selector means: get an element where the attribute [id] begins with the string "poll-".
^ matches the start
* matches any position
$ matches the end
jsfiddle
Try this.
function getElementsByIdStartsWith(container, selectorTag, prefix) {
var items = [];
var myPosts = document.getElementById(container).getElementsByTagName(selectorTag);
for (var i = 0; i < myPosts.length; i++) {
//omitting undefined null check for brevity
if (myPosts[i].id.lastIndexOf(prefix, 0) === 0) {
items.push(myPosts[i]);
}
}
return items;
}
Sample HTML Markup.
<div id="posts">
<div id="post-1">post 1</div>
<div id="post-12">post 12</div>
<div id="post-123">post 123</div>
<div id="pst-123">post 123</div>
</div>
Call it like
var postedOnes = getElementsByIdStartsWith("posts", "div", "post-");
Demo here: http://jsfiddle.net/naveen/P4cFu/
querySelectorAll with modern enumeration
polls = document.querySelectorAll('[id ^= "poll-"]');
Array.prototype.forEach.call(polls, callback);
function callback(element, iterator) {
console.log(iterator, element.id);
}
The first line selects all elements in which id starts ^= with the string poll-.
The second line evokes the enumeration and a callback function.
Given that what you want is to determine the full id of the element based upon just the prefix, you're going to have to do a search of the entire DOM (or at least, a search of an entire subtree if you know of some element that is always guaranteed to contain your target element). You can do this with something like:
function findChildWithIdLike(node, prefix) {
if (node && node.id && node.id.indexOf(prefix) == 0) {
//match found
return node;
}
//no match, check child nodes
for (var index = 0; index < node.childNodes.length; index++) {
var child = node.childNodes[index];
var childResult = findChildWithIdLike(child, prefix);
if (childResult) {
return childResult;
}
}
};
Here is an example: http://jsfiddle.net/xwqKh/
Be aware that dynamic element ids like the ones you are working with are typically used to guarantee uniqueness of element ids on a single page. Meaning that it is likely that there are multiple elements that share the same prefix. Probably you want to find them all.
If you want to find all of the elements that have a given prefix, instead of just the first one, you can use something like what is demonstrated here: http://jsfiddle.net/xwqKh/1/
I'm not entirely sure I know what you're asking about, but you can use string functions to create the actual ID that you're looking for.
var base = "common";
var num = 3;
var o = document.getElementById(base + num); // will find id="common3"
If you don't know the actual ID, then you can't look up the object with getElementById, you'd have to find it some other way (by class name, by tag type, by attribute, by parent, by child, etc...).
Now that you've finally given us some of the HTML, you could use this plain JS to find all form elements that have an ID that starts with "poll-":
// get a list of all form objects that have the right type of ID
function findPollForms() {
var list = getElementsByTagName("form");
var results = [];
for (var i = 0; i < list.length; i++) {
var id = list[i].id;
if (id && id.search(/^poll-/) != -1) {
results.push(list[i]);
}
}
return(results);
}
// return the ID of the first form object that has the right type of ID
function findFirstPollFormID() {
var list = getElementsByTagName("form");
var results = [];
for (var i = 0; i < list.length; i++) {
var id = list[i].id;
if (id && id.search(/^poll-/) != -1) {
return(id);
}
}
return(null);
}
You'll probably have to either give it a constant class and call getElementsByClassName, or maybe just use getElementsByTagName, and loop through your results, checking the name.
I'd suggest looking at your underlying problem and figure out a way where you can know the ID in advance.
Maybe if you posted a little more about why you're getting this, we could find a better alternative.
You use the id property to the get the id, then the substr method to remove the first part of it, then optionally parseInt to turn it into a number:
var id = theElement.id.substr(5);
or:
var id = parseInt(theElement.id.substr(5));
<form class="form-poll" id="poll-1225962377536" action="/cs/Satellite" target="_blank">
The ID always starts with 'post-' then the numbers are dynamic.
Please check your id names, "poll" and "post" are very different.
As already answered, you can use querySelector:
var selectors = '[id^="poll-"]';
element = document.querySelector(selectors).id;
but querySelector will not find "poll" if you keep querying for "post": '[id^="post-"]'
If you need last id, you can do that:
var id_list = document.querySelectorAll('[id^="image-"]')
var last_id = id_list.length
alert(last_id)