getElementById check multiple conditions - javascript

I am trying to build a function that checks if all fields are populated, if populated then show div if not hide.
I can get this to work on one fields however i have then tried two ways of checking multiple.
first
if first condition met I then ran other condition checking second field nested inside the first... this done not work.
second
I passed in an array of ID's rather than a single... this did not work either..
I am left with a working function that only works if first filed is populated can anyone think of a solution to this or maybe i passed in my array incorrectly.
My code
var myVar = setInterval(myTimer, 10);
function myTimer() {
if(!document.getElementById('Email').value) { // I need this to pass if multiple id's
var divsToHide = document.getElementsByClassName("somediv"); //divsToHide is an array
for(var i = 0; i < divsToHide.length; i++){
divsToHide[i].style.visibility = "hidden"; // or
divsToHide[i].style.display = "none"; // depending on what you're doing
}
}
else {
var divsToHide = document.getElementsByClassName("somediv"); //divsToHide is an array
for(var i = 0; i < divsToHide.length; i++){
divsToHide[i].style.visibility = "visible"; // or
divsToHide[i].style.display = "block"; // depending on what you're doing
}
}
}

Make it so your function takes an argument of the element ID and the class Name you need to check for.
Also, never use .getElementsByClassName() (read here for why). Instead, use .querySelectorAll().
And, you can use the modern .forEach() API of arrays and node lists (not in IE though), which is simpler than managing traditional for loops with indexes.
Lastly, use pre-made CSS classes instead of inline styling.
// You just need to pass the ID and Class to the following line
var myVar = setInterval(function(){ myTimer([id here],[class here]) }, 10);
function myTimer(id, class) {
// Set up these references just once and the rest of the code
// will be easier to read
var elem = document.getElementById(id);
var divsToHide = document.querySelectorAll("." + class);
// Instead of negative logic, reverse the if branches
if(elem.value) {
divsToHide.forEach(function(){
this.classList.remove("hidden"); // Much simpler than inline styling
});
} else {
divsToHide.forEach(function(){
this.classList.add("hidden");
});
}
/* Use pre-made CSS classes instead of inline styling */
.hidden { display:none; }

If you have an array of the IDs such as
let idArray = ['foo', 'bar', 'baz']
You can iterate through an array using a for loop
for (i = 0; i > idArray.length; i++) {
if (!document.getElementById(idArray[i]).value) {
// your hide logic
} else {
// your show logic
}
}

You can create a const of all elements that need to validate. For example,
const elementIdsToBeValidated = ['name', 'email'];
You can also create validator functions that returns true and false based on input,
const nameValidator = (val) => !!val;
const emailValidator = (email) => !!email;
const validators = [nameValidator, emailValidator];
Then you can run your timer function,
var myVar = setInterval(myTimer(['name', 'email']), 10);
function myTimer(ids) {
ids.forEach(id => {
const el = document.getElementById(id);
const val = el.value;
const divEl = document.getElementById('error');
const valid = validators.reduce((acc, validator) => validator(val), false);
if(valid) {
divEl.style.display = 'none';
} else {
divEl.style.display = 'block';
}
});
}
You can look at this stackBlitz example,
https://stackblitz.com/edit/js-ie7ljf

Related

JS HTML CSS: how to make a function dynamically repeat with different variables each time while not repeating the same variables inside de function

Intertwining Functions
I've been trying to make functions different but both have have the same original function.
Here are my selectors:
const popControl = document.getElementById("pop");
const popHeader = document.getElementById("header");
const popButton = document.getElementById("close");
const popTitle = document.getElementById("title");
const popBody = document.getElementById("body");
const popControl2 = document.getElementById("pop2");
const popHeader2 = document.getElementById("header2");
const popButton2 = document.getElementById("close2");
const popTitle2 = document.getElementById("title2");
const popBody2 = document.getElementById("body2");`
With all my id's selected, I create my first function, called verifyPosition:
function verifyPosition(circleLeftPosition, circleRightPosition, moveBy) {
console.log(circleLeftPosition, circleRightPosition);
if (circleLeftPosition == "550px" && circleRightPosition == "75px") {
popButton.addEventListener("click", closePosition);
openPosition();
}
}
Now, I must create the other, malfunctioning func, verifyPosition2:
function verifyPosition2(circleLeftPosition, circleRightPosition, moveBy) {
console.log(circleLeftPosition, circleRightPosition);
if (circleLeftPosition == "550px" && circleRightPosition == "75px") {
popButton2.addEventListener("click", closePosition2);
openPosition2();
}
}
For some reason, my verifyPosition2 does not work, and it does not matter what you put in it.
This brings me to my final questions:
Why is it not working?
And how can I make it work?
Thanks and thanks all!
Hint: [!ch.edit] tag means I have edited this question.
You may try the below approach
function verifyPosition(circleLeftPosition, circleRightPosition, moveBy, selector_extension) {
if (circleLeftPosition == "550px" && circleRightPosition == "75px") {
const popButton = document.getElementById("close" + selector_extension);
// Checkout the below code, if verifyPosition is called multiple times on same element, there is chance of setting multiple click events on popButton
popButton.addEventListener("click", function (e) { return closePosition(e, selector_extension); });
openPosition(selector_extension);
}
}
function closePosition(e, selector_extension) {
// access the required elements using `selector_extension`
}
function openPosition(selector_extension) {
// access the required elements using `selector_extension`
}

Cannot append comparison value to DOM using javascript

The following function checks a form submission value against a data set. Currently, I am able to return a match using console.log. My question is, given that the function is working correctly in terms of comparison, how can I append the result to the body of my page? I attempted it with the following but could not get it to work:
function lookForMatches(){
const slugName = `${slugData.slug()}`;
for (var i = 0; i < globalArticles.length; i++) {
if(slugName === globalArticles[i]["slug"]){
const showMatches = document.createElement('div')
showMatches.innerHTML(`<p>${globalArticles[i]["slug"]}<p>`);
document.getElementById("slugResults").appendChild(showMatches);
}
else {
console.log("No Matches")
}
}
}
Any help would be much appreciated!
As others have mentioned, innerHTML is a property, not a function:
The Element property innerHTML gets or sets the HTML or XML markup contained within the element.
const content = element.innerHTML;
element.innerHTML = htmlString;
In your case, your code should look like this:
function lookForMatches() {
const slugName = `${slugData.slug()}`;
for (var i = 0; i < globalArticles.length; i++) {
if (slugName === globalArticles[i]["slug"]) {
const showMatches = document.createElement("div");
// Set's the inner HTML
showMatches.innerHTML = `<p>${globalArticles[i]["slug"]}</p>`;
document.getElementById("slugResults").appendChild(showMatches);
} else {
console.log("No Matches");
}
}
}

Iterating over a nodelist, getting the length of a value of a node item

I am trying to dynamically grab ZIPcodes and validate them when the length is 5.
I used querySelectorAll to grab the Zipcode fields on the page, as well as a few other fields I will use after validating.
I iterate over the nodelist and pass it to another function, where the eventlistener kicks off if the value is the correct length.
function GetZipCodeDetails() {
var zipId = document.querySelectorAll("[id*='ZipCode']");
var countyId = document.querySelectorAll("[id*='CountyId']");
var stateId = document.querySelectorAll("[id*='StateId']");
var phoneId = document.querySelectorAll("[id*='PhoneNumber']");
for (var i = 0; i < zipId.length; i++) {
if (zipId[i].length = 5)
AssortedZipCodeFunctions(zipId[i], countyId[i], stateId[i], phoneId[i]);
}
}
function AssortedZipCodeFunctions(zipId, countyId, stateId, phoneId) {
//Runs auto-county/state function only when zipcode field is completed
document.addEventListener("keyup", (e) => {
if (zipId.value.length == 5) {
GetCountyAndStateFromIds(zipId, countyId, stateId, phoneId);
} });
}
The code works perfectly for me as it is listed above; I am just trying to move the second function into the first function, but I can't figure out how. I am just stuck on how come I can't do the following:
function GetZipCodeDetails() {
var zipId = document.querySelectorAll("[id*='ZipCode']");
var countyId = document.querySelectorAll("[id*='CountyId']");
var stateId = document.querySelectorAll("[id*='StateId']");
var phoneId = document.querySelectorAll("[id*='PhoneNumber']");
for (var i = 0; i < zipId.length; i++) {
document.addEventListener("keyup", (e) => {
if (zipId[i].value.length == 5) {
GetCountyAndStateFromIds(zipId[i], countyId[i], stateId[i], phoneId[i]);
}
});
}
}
The above gives: "TypeError: Cannot read property 'value' of undefined
at HTMLDocument."
I have figured out that the for loop is calling the second function, instead of waiting until the Zipcode value is 5... so all that happened is I passed it to another function? Or maybe I am stuck on how to get the length of the value of a node item? Please help.
In your event listener you are adding it to the document instead of each element separately
for (var i = 0; i < zipId.length; i++) {
zipId[I].addEventListener("keyup", (e) => {
if (zipId[i].value.length == 5) {
GetCountyAndStateFromIds(zipId[i], countyId[i], stateId[i], phoneId[i]);
}
});
}

element.getElementsByClassName is not a function

Currently I'm working in card filter, but I get jobCards[card].getElementsByClassName is not a function.
const cardHasRequirementFilter = function(card){
for(let requirementInFilter in listForFiltering){
let requirementsByCard = jobCards[card].getElementsByClassName("job-requirements__requirement");
for(let requirementInCard in requirementsByCard){
if(requirementInCard.innerHTML === requirementInFilter.innerHTML ){
return true;
}
}
}
return false;
}
When I call that function i do it this way
jobCards[card].style.display = cardHasRequirementFilter(card)===true?"flex":"none";
I tried with:
jobCards[card].style.display = cardHasRequirementFilter(jobCards[card])===true?"flex":"none";
const cardHasRequirementFilter = function(card){
for(let requirementInFilter in listForFiltering){
let requirementsByCard = card.getElementsByClassName("job-requirements__requirement");
for(let requirementInCard in requirementsByCard){
if(requirementInCard.innerHTML === requirementInFilter.innerHTML ){
return true;
}
}
}
return false;
}
And i get the same error...
I tried on Edge and chrome.
All my code is:
const btnsRequirements = document.getElementsByClassName("job-requirements__requirement");
const jobCards = document.getElementsByClassName("job-list__card-job");
/* All non repetible requirements existent. */
const listRequirements = {};
/* The cards will be filtered by this requirements to be
filtered, if it's empty, then all cards will be shown. */
const listForFiltering = {};
for (let requirement of btnsRequirements) {
let text = requirement.innerHTML;
listRequirements[text] = text;/* Creates a new property with the same value, if already existe, it's overited. */
requirement.addEventListener("click", function () {
let requirementClicked = this.innerHTML;
listForFiltering[requirementClicked] = requirementClicked;
filterCardsByRequirementsChoosed();
}, false);
}
const filterCardsByRequirementsChoosed = function(){
let numEntries = Object.entries(listForFiltering).length;
if ( numEntries === 0){
/* if there's no filter, then show all. */
for(let card of jobCards){
jobCards[card].style.display = "flex";
}
}else{
for(let card in jobCards){
jobCards[card].style.display = cardHasRequirementFilter(card)===true?"flex":"none";
}
}
};
const cardHasRequirementFilter = function(card){
for(let requirementInFilter in listForFiltering){
let requirementsByCard = jobCards[card].getElementsByClassName("job-requirements__requirement");
for(let requirementInCard in requirementsByCard){
if(requirementInCard.innerHTML === requirementInFilter.innerHTML ){
return true;
}
}
}
return false;
}
First look at the filterCardsByRequirementsChoosed function. You have both for-of and for-in loops, but are using them as though they're the same.
The for-of should be:
for(let card of jobCards){
// jobCards[card].style.display = "flex";
card.style.display = "flex";
}
The for-in was done correctly, but using for-of is a little nicer IMO.
So it seemed you were just passing the wrong value to the function in question.
Actually, I do see that you're only calling the problem function in the for-in loop, and are passing the property name. So you seem to be doing that correctly.
One thing to keep in mind is that your jobCards is a "live list". So if any of those elements get removed from the DOM, or even if the class you used to fetch them gets removed, those elements will be also removed from the jobCards list immediately.
in your loop
for(let card of jobCards)
card is your variable that will represent the elements in jobCards as they are being iterated through. It is not an index.
So you need to do
card.getElementByClassName(...)
card.style.display(...)
EDIT—
As per the comment below... you use the for in loop... which iterates over properties of the object. For an array... this will include the indices and other properties such as #length, etc giving you the error.

Pass Arguments from One Function to Another Without Calling It

I'm trying to get either options or, ideally, dynamicTable passed from initializeTable to the applyTableFilters function and I'm having problems getting the expected values. I'm using List.js to make a table dynamic and I need to pass or recreate the dynamicTable object so I can go ahead and use it to filter the table.
Here is the function that creates the List.js object from the HTML table:
function initializeTable(options) { // initializes table to be dynamic using List.js functions
var dynamicTable = new List("table-content", options);
dynamicTable.on("updated", function (list) { // writes a message to the user if no results are found
if (list.matchingItems.length == 0) {
document.getElementById("no-results").style.display = "block";
}
else {
document.getElementById("no-results").style.display = "none";
}
});
console.log(dynamicTable);
console.log(options);
console.log(arguments.length);
applyTableFilters.bind();
}
I've tried different methods to pass the variables to the function below. I tried .call, applyTableFilters(args), and .apply, but the problem is that I do not want the function to execute from inside here, only when the click event from the button goes off (not shown in these functions).
This is the function I want to pass the object to and proceed to make the filter functions using it:
function applyTableFilters(dynamicTable) {
var form = document.getElementById("filter-form");
//console.log(options);
//var dynamicTable = new List("table-content", options);
console.log(dynamicTable);
var filters = form.querySelectorAll('input[type="checkbox"]:checked');
dynamicTable.filter(function (item) {
console.log(item);
console.log(item._values);
if (item.values().id == 2) {
return true;
}
else {
return false;
}
//var filterStrings = [];
//console.log(filters);
//for (var i = 0; i < filters.length; i++) {
// var filterVal = filters[i].value;
// var filterString = "(" + item.values().column == filterVal + ")"; // filterVal.contains(item.values().column) ||
// filterStrings.push(filterString);
// console.log(filterVal);
// console.log(filterString);
//}
//console.log(filterStrings);
//var filterString = filterStrings.join(" && ");
//console.log(filterString);
//return filterString;
});
}
I've used:
applyTableFilters.bind(this, dynamicTable/options);
applyTableFilters.bind(null, dynamicTable/options);
applyTableFilters.bind(dynamicTable/options);
Switching between the two since I don't need both passed if one ends up working, etc. I always get a mouse event passed in and that's not even the right type of object I'm looking for. How can I get the right object passed? Also all the values in the first function are not empty and are populated as expected so it's not the original variables being undefined or null. Thanks in advance.
From your initializeTable function return a function that wraps the applyTableFilters function with the arguments you want.
Then assign the returned function to a var to be executed later.
function initializeTable(options) {
var dynamicTable = new List("table-content", options);
// other stuff
return function () {
applyTableFilters(dynamicTable)
}
}
// other stuff
var applyTableFiltersPrep = initializeTable(options)
// later, when you want to execute...
applyTableFiltersPrep()
JSFiddle example

Categories