querySelectorAll is not a function - javascript

I'm trying to find all oferts in the var articleFirst, but the return message in the console says that "querySelectorAll" is not a function. Why I do get that error?
This is my HTML:
<article class="first">
<div class="feature parts">
<div class="oferts">
<div class="heart icons"></div>
<h1>Build with passion</h1>
</div>
</div>
</article>
This is my JavaScript:
var articleFirst = document.querySelectorAll("article.first");
var oferts = articleFirst.querySelectorAll(".oferts");
Error:
Uncaught TypeError: articleFirst.querySelectorAll is not a function

Try do do this:
var articleFirst = document.querySelectorAll("article.first");
console.log(articleFirst)
var oferts = articleFirst[0].querySelectorAll(".oferts");
console.log(oferts)
With console you can see what is happening.
Or just do this:
document.querySelectorAll("article.first .oferts");

querySelectorAll is a method found on Element and Document nodes in the DOM.
You are trying to call it on the return value of a call to querySelectorAll which returns a Node List (which is an array like object). You would need to loop over the Node List and call querySelector all on each node in it in turn.
Alternatively, just use a descendant combinator in your initial call to it.
var oferts = document.querySelectorAll("article.first .oferts");

You need to use document.querySelector instead of document.querySelectorAll because the next query depends on a single HTMLElement but document.querySelectorAll returns a NodeList.
document.addEventListener('DOMContentLoaded', TestCtrl);
function TestCtrl() {
var firstArticle = document.querySelector('article.first');
console.log('oferts', firstArticle.querySelectorAll('.oferts'));
}
<article class="first">
<div class="feature parts">
<div class="oferts">
<div class="heart icons"></div>
<h1>Build with passion</h1>
</div>
</div>
</article>

A little verbose but you could try qselectorAll('article') then turn that nodeList into an array and pick the first index.. so something like:
let articleList = querySelectorAll('article'); // makes a NodeList of all article tags on the webpage
let article = Array.from(articleList);
article[0];

Related

Combine $ and _ to pluck by data values?

I have a list of jquery elements with a data attribute.
Now I want to get a list of these data attributes.
As the data-attribute is some kind of an object property, I thought this might work with underscores pluck method.
Is this even possible?
See this short example:
var divs = $("div");
// now do something
// expected result: [1, 2, 3]
<script src="https://cdnjs.com/libraries/underscore.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-foo="1">a</div>
<div data-foo="2">b</div>
<div data-foo="3">c</div>
<div>x</div>
Solution
Based on #romeo-sierra this is the way I wrote it down (as I already have jquery objects). Underscores pluck is superfluous
var foos = $("div").map(function() {
return $(this).data("foo");
}).toArray();
console.log(foos);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div data-foo="1">a</div>
<div data-foo="2">b</div>
<div data-foo="3">c</div>
<div>x</div>
Vanilla JS can accomplish this just fine, no jQuery nor any other library needed:
const foos = [...document.querySelectorAll('[data-foo]')]
.map(elm => elm.dataset.foo);
console.log(foos);
<div data-foo="1">a</div>
<div data-foo="2">b</div>
<div data-foo="3">c</div>
<div>x</div>
ES5 version:
var foos = Array.prototype.map.call(document.querySelectorAll('[data-foo]'), function(elm) {
return elm.dataset.foo;
});
console.log(foos);
<div data-foo="1">a</div>
<div data-foo="2">b</div>
<div data-foo="3">c</div>
<div>x</div>
How about the following, that uses pure jQuery? (since you already are using it)
var arr = [];
$('div[data-foo]').each(function(){
arr.push($(this).data("foo")); // should return the value
});
console.log(arr);
Check this fiddle out.
You definitely have to lookup for a specific data attribute.
You can't just drain the whole page for elements data attribute and obtain a complete list like that.
But if you know what you look for...
See below
var attribute = "foormidable";
$("*").each(function(){
var match = $(this).attr("data-"+attribute);
if(typeof(match)!="undefined"){
console.log(match);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-foorm="1">a</div>
<div data-foormidable="2">b</div>
<div data-foolahlayouuu="3">c</div>
<div>x</div>
OR using .data()
var attribute = "foormidable";
$("*").each(function(){
var match = $(this).data(attribute);
if(typeof(match)!="undefined"){
console.log(match);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-foorm="1">a</div>
<div data-foormidable="2">b</div>
<div data-foolahlayouuu="3">c</div>
<div>x</div>
That last one will get the value of THE OBJECT... Be it dynamic via JS code.
That is real different from the on load markup attribute value.
;)

jQuery .size() function doesn´t work with a variable

At many points in my code I need to know how many .page classes are used.
To know this I use $(".page").size()
I want to save this information into a variable.
So I wrote this:
var vari = {
*more variables*
totalPageCount : $(".page").size()
};
The Problem is that vari.totalPageCount always gives 0 back.
With console.log() I get this:
console.log($(".page").size()); // Return 8
console.log(vari.totalPageCount); // Return 0
Edit:
Here is a example how i use it.
JS:
var vari = {
currentPage : 0,
pageAnimations : 0,
animationList : ".fade-in, .fade-out",
totalPageCount : $(".page").size(),
};
var footer = {
html : function(){
var html;
var date = this.date();
for(var i=0; i<vari.totalPageCount; i++){
html = '<span class="pageNumber" id="pageNumber">Folie:'+i+' • '+vari.custom["companyName"]+' • '+date+'</span>';
$("#normalPage"+i).append(html);
}
return;
}
};
HTML:
<body class="presWrapper">
<div class="pageWrapper">
<div class="page startPage" id="startPage">
<h2 class="mainTitle">Lorem</h2>
<h4 class="subTitle">Ipsum</h4>
</div>
</div>
<div class="pageWrapper">
<div class="page normalPage" id="normalPage1">
<div class="content">
<p class="fade-in">HELLO WORLD</p>
</div>
</div>
</div>
<div class="pageWrapper">
<div class="page endPage" id="endPage">
<div class="content">
<p class="fade-out">HELLO SATURN</p>
<p class="fade-out">HELLO WORLD</p>
<p class="fade-in">HELLO WORLD</p>
<p>pTag</p>
</div>
</div>
</div>
</body>
Any suggestions to solve this problem?
vari.totalPageCount Gets evaluated only when it is declared.
As a result it will only have the value of $(".page").size() when it is first run.
Unless you are waiting on document ready the children of .page have not yet been added and it has length 0.
When you later call the console and execute the selector again - you get the true count in the console message - but the stored value has already been calculated as 0 within vari.
length() and size() are equivalent functions in jquery but size has been deprecated so length is the appropriate function to call. But in either case - its likely you are just evaluating the length too early when the vari object is constructed for it to have a meaningful value.
Does the following give you the wrong value for the property:
$(document).ready(function () {
var vari = {totalPageCount: $('.page').length};
console.log(vari.totalPageCount);
});
Relevant documentation
The .size() method is deprecated as of jQuery 1.8.
Use length property instead:
var vari = {
*more variables*
totalPageCount : $(".page").length;
};
Also, make sure you are using this code at the bottom of the script or inside a document ready handler. You won't get accurate information if you try to get it before DOM has been fully setup.
This will increment count for every element with having the page class
var count = 0;
$('.page').each(function() {
count++;
});
var vari = {
totalPageCount: count
};
Working jsFiddle

Find Custom Elements that start with a specified prefix

I have a bunch of Custom Elements that begin with 'food-cta-'. I am looking for a way in JavaScript/jQuery to be able to select these elements. This is similar to how I can use $('*[class^="food-cta-"]') to select all the classes that start with food-cta-. Is it possible to do a search for elements that start with 'food-cta-'?
Note that I will be injecting this search onto the page, so I won't have access to Angular.
Example of Custom Elements:
<food-cta-download>
<food-cta-external>
<food-cta-internal>
EDIT: The code I am looking at looks like:
<food-cta-download type="primary" description="Download Recipe">
<img src="">
<h2></h2>
<p></p>
</food-cta-download>
The app uses AngularJS to create Custom Elements which I believe is called Directives.
You can use XPath with the expression
//*[starts-with(name(),'food-cta-')]
Where
//* is wildcard for all nodes
starts-with() is a XPath function to test a string starts with some value
name() gets the QName (node name)
and 'food-cta-' is the search term
Pass it into document.evaluate and you will get a XPathResult that will give you the nodes that were matched.
var result = document.evaluate( "//*[starts-with(name(),'food-cta-')]", document, null, XPathResult.ANY_TYPE, null );
Note you can use any node as the root, you do not need to use document. So you could for instance replace document with the some div:
var container = document.getElementById("#container");
var result = document.evaluate( "//*[starts-with(name(),'food-cta-')]", container, null, XPathResult.ANY_TYPE, null );
Demo
let result = document.evaluate( "//*[starts-with(name(),'food-cta-')]", document, null, XPathResult.ANY_TYPE, null );
let nodes = [];
let anode = null;
while( (anode = result.iterateNext()) ){
nodes.push( anode.nodeName );
}
console.log(nodes);
<div id="container">
<br>
<food-cta-download type="primary" description="Download Recipe">
<img src="">
<h2></h2>
<p></p>
</food-cta-download>
<span>Some span</span>
<food-cta-something>
<img src="">
<h2></h2>
<p></p>
</food-cta-something>
<div>In between
<food-cta-sub>
<img src="">
<h2></h2>
<p></p>
</food-cta-sub>
</div>
<food-cta-hello>
<img src="">
</food-cta-hello>
<food-cta-whattt>
</food-cta-whattt>
</div>
Try this..
let customElements = $('*')
.filter((index,element) => /FOOD-CTI-/.test(element.tagName));
Note, .tagName should return the result in uppercase. This should get you a jQuery object of the elements you want. It will traverse the entire DOM though. It'll be slow.
This uses the "all selector".
Caution: The all, or universal, selector is extremely slow, except when used by itself.
You can traverse less then entire dom too, by specifying something like $("body *"). Not sure where you have put the Custom Elements, and where they're allowed.
As an aside, I wouldn't use Custom Elements, microformats are a better idea at least now, they're also better supported, and they're less likely to change.
You probably have to just go to the elements in question and check if their tagName begins with that given string...
var myPrefix = "mycustom-thing-";
$("body").children().each(function() {
if (this.tagName.substr(0, myPrefix.length).toLowerCase() == myPrefix) {
console.log(this.innerHTML); // or what ever
}
})
https://jsfiddle.net/svArtist/duLo2d0z/
EDIT: Included for efficiency's sake:
If you can predict where the elements will be, you can of course specify that circumstance.
In my example, the elements in question were direct children of body - so I could use .children() to get them. This would not traverse lower levels.
Reduce the need for traversal by the following:
Start on the lowest needed level ($("#specific-id") rather than $("body"))
If the elements are all to be found as direct children of a container:
Use $.children() on the container to obtain just the immediate children
Else
Use $.find("*")
If you can tell something about the containing context, filter by that
For example $("#specific-id").find(".certain-container-class .child-class *")
Why not extend jquery selectors?
$(':tag(^=food-cta-)')
Would be possible with the following implementation:
$.expr[':'].tag = function tag(element, index, match) {
// prepare dummy attribute
// avoid string processing when possible by using element.localName
// instead of element.tagName.toLowerCase()
tag.$.attr('data-tag', element.localName || element.tagName.toLowerCase());
// in :tag(`pattern`), match[3] = `pattern`
var pattern = tag.re.exec(match[3]);
// [data-tag`m`="`pattern`"]
var selector = '[data-tag' + (pattern[1] || '') + '="' + pattern[2] + '"]';
// test if custom tag selector matches element
// using dummy attribute polyfill
return tag.$.is(selector);
};
// dummy element to run attribute selectors on
$.expr[':'].tag.$ = $('<div/>');
// cache RegExp for parsing ":tag(m=pattern)"
$.expr[':'].tag.re = /^(?:([~\|\^\$\*])?=)?(.*)$/;
// some tests
console.log('^=food-cta-', $(':tag(^=food-cta-)').toArray());
console.log('*=cta-s', $(':tag(*=cta-s)').toArray());
console.log('food-cta-hello', $(':tag(food-cta-hello)').toArray());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<br>
<food-cta-download type="primary" description="Download Recipe">
<img src="">
<h2></h2>
<p></p>
</food-cta-download>
<span>Some span</span>
<food-cta-something>
<img src="">
<h2></h2>
<p></p>
</food-cta-something>
<div>In between
<food-cta-sub>
<img src="">
<h2></h2>
<p></p>
</food-cta-sub>
</div>
<food-cta-hello>
<img src="">
</food-cta-hello>
<food-cta-whattt>
</food-cta-whattt>
</div>
This supports a pseudo-CSS-style attribute selector with the syntax:
:tag(m=pattern)
Or just
:tag(pattern)
where m is ~,|,^,$,* and pattern is your tag selector.

Get next textarea outside div without id

I need to get the next textarea, but I'm not being able with next or even find.
Sample code HTML:
<div>
<div class="guides_chapters_button" onclick="surroundtest('[center]', '[/center]');">Center</div>
<div class="guides_chapters_button" style="text-decoration: underline;" onclick="surround('[u]', '[/u]');">u</div>
</div>
<textarea class="guides_chapters_textarea" id="textareamatch" name="matchupm" rows="7" cols="25"></textarea>
JS:
window.surround = function surround(text2,text3){
$("#textareamatch").surroundSelectedText(text2, text3);
}
function surroundtest(text2,text3){
var c = $(this).parent().next('textarea');
c.surroundSelectedText(text2, text3);
}
JS FIDDLE: http://jsfiddle.net/qmpY8/1/
What I need working is surroundtest, the other is an example working but using the id. I would love to replace that one because Im usinc cloned objects.
The this statement in surroundtest applies to the window object and not the element. What you should do is to change the function definition as so:
function surroundtest(element, text2,text3){
var c = $(element).parent().next('textarea');
...
}
And the HTML accordingly:
<div class="guides_chapters_button" onclick="surroundtest(this, '[center]', '[/center]');">Center</div>
If this is the HTML you are going with, then .closest() can also be used to get the textarea element.Like below:
var c = $(element).parent().closest('textarea');

Last id of an Element Javascript

How can i read the last element id using javascript?
for example :
<div id='print'>
<p id=1>some data</p>
<p id=2>some data</p>
<p id=3>some data</p>
<p id=4>some data</p>
<p id=5>some data</p>
</div>
I need to detect the id of last
I need max number of the id actually.it's generated sequentially.
First off, id values cannot be numbers. They must start with a non-number.
You can get the last child with this plain javascript (no jQuery required):
var lastChild = document.getElementById("print").lastChild;
var lastChildID = lastChild.id;
or in one line, it would be this:
var lastChildID = document.getElementById("print").lastChild.id
FYI, in case you need access to any other children you can always get all the children and then fetch the one you want:
var children = document.getElementById("print").children;
if (children.length > 1) {
var first = children[0];
var last = children[children.length - 1];
var second = children[1];
}
Now that you've explained what you're really trying to do, I'd suggest this:
<div id='print'>
<p data-num="1">some data</p>
<p data-num="2">some data</p>
<p data-num="3">some data</p>
<p data-num="4">some data</p>
<p data-num="5">some data</p>
</div>
And, then this javascript:
var lastValue = document.getElementById("print").lastChild.getAttribute("data-num");
Using the data-xxx format is forward compatible with the HTML5 specification and usable in older browsers with getAttribute().
Try this:
getElementById('print').lastChild.id;
If you use jQuery you could do something like this $("div#print :last-child").attr('id')
In jQuery you can simply use their selectors to find this:
$("p").last().attr("id");
Try this way:-
$('p:last').attr('id')
OR
$('div#print p:last').attr('id')

Categories