I have two the same forms on the same page and script that works only for the first form.
I'm a beginner and this is a challenge for me; I tried add the `for (var i = 0; i < input.length; i++) but it doesn't work out. I will be grateful for any help.
var el = document.querySelector(".js-tac");
input = document.querySelector('.js-tel')
input.addEventListener('input', evt => {
const value = input.value
if (!value) {
el.classList.remove("is-visible");
return
}
const trimmed = value.trim()
if (trimmed) {
el.classList.add("is-visible");
} else {
el.classList.remove("is-visible");
}
})
document.querySelector return the first matched element. So you need document.querySelectorAll which will give a collection. Then iterate that collection like this
document.querySelectorAll('.js-tel').forEach((input)=>{
// not using arrow function since using this to target the element
input.addEventListener('input', function(evt){
const value = this.value
// rest of the code
})
})
The problem is that you are only getting one input element. (querySelector returns the first matching element, not all matching elements). You likely want to use querySelectorAll to get a NodeList (which will contain all matching nodes). You can iterate over those.
Based on how you seem to be using it, I'd recommend making sure your js-tac and js-tel are wrapped in some common parent, and use querySelectorAll to find those. Then, you can use querySelector to find the js-tel and js-tac.
var nodes = document.querySelectorAll('.js-parent')
//If you don't export forEach to be available, you can also just do a standard
//for loop here instead.
nodes.forEach((parent) => {
var el = parent.querySelector(".js-tac");
input = parent.querySelector('.js-tel')
...
})
Related
I want to use lazy loading effect and in my code everything is going ok, but querySelector section.
I've stored some elements in a variable and I wanna apply observer function on theme.
And I also print every output in console.log to see the things.
But this error happens:
Uncaught TypeError: imgs.forEach is not a function
This is my code:
const imgs = document.querySelector("[data-src]");
const options = {
threshold:1,
};
const observer = new IntersectionObserver((entries,observer) => {
entries.forEach(entry => {
let src = entry.target.getAttribute('data-src');
if(!entry.isIntersecting){
return;
}
entry.target.src=src;
console.log(entry)
observer.unobserve(entry.target);
})
},options)
// Probleme is here
imgs.forEach(img => {
observer.observe(img);
})
Try with querySelectorAll like below code,
const imgs = document.querySelectorAll("[data-src]");
as querySelector will return single matched element, but querySelectorAll will return an NodeList of all matched elements.
Use querySelectorAll instead that should fix it
Reference the mdn documentation
The Document method querySelectorAll() returns a static (not live)
NodeList representing a list of the document's elements that match the
specified group of selectors.
instead of
const imgs = document.querySelector("[data-src]");
try this
const imgs = document.querySelectorAll("[data-src]");
Although for some browser using querySelectorAll(selector).forEach() will work. But it is not supported by all browsers. So the safe way to do this is using a for loop for looping over the NodeList. So you should do something like this,
const imgs = document.querySelector("[data-src]");
// other coddes...
for(let i = 0; i<imgs.length; i++) {
// your code.
}
I think this will be the safest way.
Document.querySelector()
returns a single element and you cannot loop over a single element.
document.querySelectorAll()
returns all the elements with the class, id, tagname etc provided in the parenthesis.
I want to use lazy loading effect and in my code everything is going ok, but querySelector section.
I've stored some elements in a variable and I wanna apply observer function on theme.
And I also print every output in console.log to see the things.
But this error happens:
Uncaught TypeError: imgs.forEach is not a function
This is my code:
const imgs = document.querySelector("[data-src]");
const options = {
threshold:1,
};
const observer = new IntersectionObserver((entries,observer) => {
entries.forEach(entry => {
let src = entry.target.getAttribute('data-src');
if(!entry.isIntersecting){
return;
}
entry.target.src=src;
console.log(entry)
observer.unobserve(entry.target);
})
},options)
// Probleme is here
imgs.forEach(img => {
observer.observe(img);
})
Try with querySelectorAll like below code,
const imgs = document.querySelectorAll("[data-src]");
as querySelector will return single matched element, but querySelectorAll will return an NodeList of all matched elements.
Use querySelectorAll instead that should fix it
Reference the mdn documentation
The Document method querySelectorAll() returns a static (not live)
NodeList representing a list of the document's elements that match the
specified group of selectors.
instead of
const imgs = document.querySelector("[data-src]");
try this
const imgs = document.querySelectorAll("[data-src]");
Although for some browser using querySelectorAll(selector).forEach() will work. But it is not supported by all browsers. So the safe way to do this is using a for loop for looping over the NodeList. So you should do something like this,
const imgs = document.querySelector("[data-src]");
// other coddes...
for(let i = 0; i<imgs.length; i++) {
// your code.
}
I think this will be the safest way.
Document.querySelector()
returns a single element and you cannot loop over a single element.
document.querySelectorAll()
returns all the elements with the class, id, tagname etc provided in the parenthesis.
I am mostly familiar with java selenium, and I am new to both JS and Protractor. Lets say I am trying to click an option from a list of options with a common identifier..
var options = $('.options');
How could I get all elements with that common identifier, and then select one by its text? I can not do driver.findElements like I could in java since there is no reference to driver..
This is what I have tried so far but its not working and I think its due to my inexperience with JS
this.selectCompanyCode = function(companyCode) {
dropDownMenus[0].click();
var companyCodeOptions = $('[ng-bind-html="companyCode"]');
companyCodeOptions.filter(function (elem) {
return elem.getText().then(function text() {
return text === companyCode;
});
}).first().click();
};
Select all elements with common identifier: $$('.options'); That selects all elements with a class of .options -- equivalent of element.all(by.css('.options')). This returns an ElementArrayFinder. Also see .get() for how to choose an element by index from the ElementArrayFinder.
Find by text, you could use cssContainingText(css, text). For example,
var loginBtn = element(by.cssContainingText('button.ng-scope', 'Login'));
But if for some reason those are not providing the expected results, you can use .filter() (docs here) on an ElementArrayFinder to go through the array of elements and find an element based on a condition you specify. For example,
var allOptions = $$('.options');
allOptions.filter(function (elem) {
return elem.getText().then(function (text) {
return text === 'What you want';
});
}).first().click();
And, although I've never used regular Java Selenium (so I don't know if this is the same), but there is indeed a browser reference (and therefore findElements function): http://www.protractortest.org/#/api?view=ProtractorBrowser.
Hope it helps!
Edit:
Using your code:
this.selectCompanyCode = function(companyCode) {
// where is dropDownMenus defined? This has function no reference to it.
dropDownMenus.get(0).click(); // should be this
var companyCodeOptions = $$('[ng-bind-html="' + companyCode + '"]');
return companyCodeOptions.filter(function (elem) {
return elem.getText().then(function text() {
return text === companyCode;
});
}).first().click();
};
second edit:
Assuming company code is unique, you probably don't need to use filter. Try this:
this.selectCompanyCode = function(companyCode) {
dropDownMenus.get(0).click();
var companyCodeOptions = $('[ng-bind-html="' + companyCode + '"]');
return companyCodeOptions.click();
};
Use cssContainingText
element(by.cssContainingText(".option", "text")).click();
http://www.protractortest.org/#/api?view=ProtractorBy.prototype.cssContainingText
I have an element with multiple elements inside. All of the elements inside have the same name. Is there any way to remove them using one function?
(refer to this question for example Remove multiple children from parent?
Here's a solution that removes the first level children with the specified name for the parent with the specified id. If you want to go deeper, you can recursively call it on the child elements you get inside (you'll have to add a parent parameter as well).
function removeChildren (params){
var parentId = params.parentId;
var childName = params.childName;
var childNodes = document.getElementById(parentId).childNodes;
for(var i=childNodes.length-1;i >= 0;i--){
var childNode = childNodes[i];
if(childNode.name == 'foo'){
childNode.parentNode.removeChild(childNode);
}
}
}
And to call it:
removeChildren({parentId:'div1',childName:'foo'});
And a fiddle for testing:
Notes: You can only access the name element dependably in JavaScript when it supported on your element (e.g. NOT on DIVs!). See here for why.
UPDATE:
Here's a solution using className based on our conversation:
function removeChildren (params){
var parentId = params.parentId;
var childName = params.childName;
var childNodesToRemove = document.getElementById(parentId).getElementsByClassName('foo');
for(var i=childNodesToRemove.length-1;i >= 0;i--){
var childNode = childNodesToRemove[i];
childNode.parentNode.removeChild(childNode);
}
}
2021 Answer:
Perhaps there are lots of way to do it, such as Element.replaceChildren().
I would like to show you an effective solution with only one redraw & reflow supporting all ES6+ browsers.
function removeChildren(cssSelector, parentNode){
var elements = parentNode.querySelectorAll(cssSelector);
let fragment = document.createDocumentFragment();
fragment.textContent=' ';
fragment.firstChild.replaceWith(...elements);
}
Usage: removeChildren('.foo',document.body);: remove all elements with className foo in <body>
ok this should be easy. First get the parent element:
var theParent = document.getElementById("notSoHappyFather");
then get an array of the nodes that you want to remove:
var theChildren = theParent.getElementsByName("unluckyChild");
Lastly, remove them with a loop:
for (var i = 0; i < theChildren.length; i++)
{
theParent.removeChild(theChildren[i]);
}
A sample of your HTML would get you a more complete answer, but one can fairly easy call DOM functions to get the list of children and just remove them. In jQuery, remove all children would be something like this:
$("#target > *").remove();
or
$("#target").html("");
And, you can see a demo here: http://jsfiddle.net/jfriend00/ZBYCh/
Or, not using jQuery you could also do:
document.getElementById("target").innerHTML = "";
If you're trying to only remove a subset of the children (and leave others intact), then you need to be more specific how one would determine which children to leave and which to remove. In jQuery, you could use a .find() select or a filter() selector to narrow the list of children to just the children you wanted to target for removal.
I would like to change the class for all the fields in a specific fieldset.
Is there a way to loop through the fields in a fieldset?
You can use getElementsByTagName.
var fieldset= document.getElementById('something');
var fieldtags= ['input', 'textarea', 'select', 'button'];
for (var tagi= fieldtags.length; tagi-->0) {
var fields= fieldset.getElementsByTagName(fieldtags[tagi]);
for (var fieldi= fields.length; fieldi-->0;) {
fields[fieldi].className= 'hello';
}
}
(If you only care about input fields, you could lose the outer tag loop.)
If you needed them in document order (rather than grouped by tag) you'd have to walk over the elements manually, which will be a pain and a bit slow. You could use fieldset.querySelectorAll('input, textarea, select, button'), but not all browsers support that yet. (In particular, IE6-7 predate it.)
Using jQuery (yay!):
$('#fieldset-id :input').each(function(index,element) {
//element is the specific field:
$(element).doSomething();
});
Note the solution below is for NON-JQUERY Implementations.
Implement a getElementsByClassName Method like this:
After you implement the code below you can then use document.getElementsByClassName("elementsInFieldSetClass") it will return an array of the elements with that class.
function initializeGetElementsByClassName ()
{
if (document.getElementsByClassName == undefined) {
document.getElementsByClassName = function(className)
{
var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
var allElements = document.getElementsByTagName("*");
var results = [];
var element;
for (var i = 0; (element = allElements[i]) != null; i++) {
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
results.push(element);
}
return results;
}
}
}
window.onload = function () {
initializeGetElementsByClassName();
};
Another jQuery solution here.
If you are simply adding a class(es) to the elements, it's this simple:
$('fieldset :input').addClass('newClass');
.addClass() (like many other jQuery functions) will work on all of the elements that match the selector.
Example: http://jsfiddle.net/HANSG/8/
Permanently? Find & replace in your editor of choice.
When the user clicks something? jQuery way:
$('fieldset <selector>').each(function() {
$(this).removeClass('old').addClass('new');
});