Getting Null when trying to query the path to my button element - javascript

Issue:
I want to return the button Element within my document that matches the specified selector, in this case ".comment-body__interaction--delete" but keep getting a return of null every time I console.log the variable that contains the return element.
Background Info
The HTML element I'm Trying to target has been inserted into the document via innerHTML.
All my scripts are at the bottom of the index.html page
I'm using querySelector at the bottom of the js document.
I know my class name is correct because I can style it via CSS.
my code
// LOCATION VARIABLES ***
const conversation = document.querySelector('.conversation-container-posted');
const form = document.querySelector('form');
console.log(form);
// Array THAT HOLDS ALL MY COMMENT OBJECTS
let objectsArray;
// VARIABLE THAT HOLDS MY HTML TEMPLATE
const template = (singleCommentObj) => {
return `
<article class="comment-container">
<figure class="comment-container__picture">
<img class="comment-container__picture-img" src="${singleCommentObj.image}" alt="profile picture" />
</figure>
<div class="comment-body">
<h3 class="comment-body__name">${singleCommentObj.name}</h3>
<div class="comment-body__date">${singleCommentObj.date}</div>
<article class="comment-body__comment"><p>${singleCommentObj.comment}</p></article>
<div class="comment-body__interaction">
<div class="comment-body__interaction--likes">Likes</div>
<button id="${singleCommentObj.id}" class="comment-body__interaction--delete">Delete</button>
</div>
</div>
</article>
<hr class="comment-container__divider"/>
`;
};
const displayComment = (object) => {
let staticComments = object
.sort((a, b) => b.timestamp - a.timestamp)
.map((values) => {
values.image = 'https://loremflickr.com/48/48';
values.date = moment.unix(values.timestamp / 1000).fromNow();
return template(values);
})
.join('');
conversation.innerHTML = staticComments;
};
// Gets AN ARRAY OF OBJECTS FROM THE api AND ASSIGNS IT TO objectsArray
// CALLS displayComment WITH objectsArray AS A PARAMETER TO INSERT ITS CONTENT INTO THE DOM
axios
.get('https://project-1-api.herokuapp.com/comments?api_key=7d8d085e-486e-42dc-b836-58009cbfa68f')
.then((response) => {
objectsArray = response.data;
displayComment(objectsArray);
})
.catch((error) => {
console.log(error);
});
form.addEventListener('submit', (e) => {
e.preventDefault();
let fluidObject = new FormData(e.target);
fluidObject = Object.fromEntries(fluidObject);
axios
.post('https://project-1-api.herokuapp.com/comments?api_key=7d8d085e-486e-42dc-b836-58009cbfa68f&content-type=application/json', {
name: fluidObject.name,
comment: fluidObject.comment,
})
.then((response) => {
objectsArray.push(response.data);
displayComment(objectsArray);
})
.catch((error) => {
console.log(error);
});
});
// DELETE
const a = document.querySelector('.comment-body__interaction--delete');
console.log(a);
This console.log(a) returns NULL

The code that creates the said element, displayComment is in an asynchronous actions callback.
You have to wait for the action to complete before you try to access the element.
In other words const a = document.querySelector('.comment-body__interaction--delete'); executes before your request was successful and the elements were created.

Related

save all content clicked into state initial as array

i use usestate to create saveImages and setSaveImages, this initial as array, i want to each time i call the function, the content is different, so each time must to push to the array that info, but instead of do push, only replace the 1 position of array, doesnt add new position with different info. I don't know if I explain myself
const galery = useSelector((state) => state.search);
const dispatch = useDispatch();
const [saveImages, setSaveImages] = useState([]);
function savePhoto(e) {
e.preventDefault();
const { target } = e;
const content = target.photo.src;
setSaveImages(content)
console.log(content)
localStorage.setItem("img", saveImages);
dispatch(actionAddFavorite(content));
}
return(
<section className="w-full gap-0 sm:columns-2 md:columns-3 xl:columns-4 2xl:columns-5 3xl:columns-6">
{galery.map((item, index) => {
return (
<form onSubmit={savePhoto} key={index} className="relative">
<button className="bg-gray absolute left-5 top-3 shadow-md">
Guardar
</button>
<img
name="photo"
className="object-cover p-2"
src={item.urls.regular}
alt={item.alt_description}
/>
</form>
);
})}
</section>
)
You set your saveImages to contain "content", but what you want is to add "content" to existing saveImages array. Here is how you can do this:
setSaveImages(oldImages => {
return [...oldImages, content];
});
And here you can learn everything you need to know about state in react

Can't get the images from an API to show up

I'm using an API to get information for a database sort of thing. I want the images to be displayed to the right of the text but the images aren't showing up at all. I tried multiple different keys and still nothing. Here is what it currently looks like:
The images are not showing up as you can see.
Here is the JS (its pulling the data from here https://api.tvmaze.com/shows/347/episodes):
// DATABASE const sunnyList = document.getElementById('sunnyList'); let sunnyInfo = [];
searchBar.addEventListener('keyup', (e) => { const searchTarget = e.target.value.toLowerCase(); const filteredSunny = sunnyInfo.filter(sunny => {
return sunny.name.toLowerCase().includes(searchTarget) || sunny.airdate.toLowerCase().includes(searchTarget) || sunny.airtime.includes(searchTarget) });
displayInfo(filteredSunny); });
const loadLayout = async () => {
try {
const res = await fetch('https://api.tvmaze.com/shows/347/episodes');
sunnyInfo = await res.json();
displayInfo(sunnyInfo);
} catch (err) {
console.error(err);
} };
const displayInfo = (sunny) => {
const htmlString = sunny
.map((sunny) => {
return `
<li class="character">
<div class="detail">
<h2>${sunny.name}</h2>
<p>Season ${sunny.season} Episode ${sunny.number}</p>
<p>${sunny.airdate}</p>
<p>${sunny.airtime}</p>
<p>${sunny.rating.average}</p>
</div>
<img src="${sunny.image}"></img>
</li>
`;
})
.join('');
sunnyList.innerHTML = htmlString; };
loadLayout();
I've tried sunny.image.medium and sunny.image.original but it still doesn't show up.
Any help is appreciated :)
The image is not a url string, but an object with the following shape:
{
medium: string,
original: string
}
where both strings contain the actual image URLs.
For your use case medium probably makes more sense, so you can do this:
<img src="${sunny.image?.medium}"></img>
Edit
Added optional chaining because some items do not have image property.
The problem your are facing is that not all objects have images.
Please try this code:
const displayInfo = (sunny) => {
const htmlString = sunny
.map((sunny) => {
const img = sunny.image ? sunny.image.medium : "https://picsum.photos/200/300"
return `
<li class="character">
<div class="detail">
<h2>${sunny.name}</h2>
<p>Season ${sunny.season} Episode ${sunny.number}</p>
<p>${sunny.airdate}</p>
<p>${sunny.airtime}</p>
<p>${sunny.rating.average}</p>
</div>
<img src=${img} />
</li>
`;
})
.join('');
sunnyList.innerHTML = htmlString; };

Why when i am searching for something else is deleting the previous contents

Why when you are searching for something else is deleting the previous contents ?For example first you search for egg and show the contents but then when you search for beef the program deletes the egg and shows only beef.Code :
const searchBtn = document.getElementById('search-btn');
const mealList = document.getElementById('meal');
const mealDetailsContent = document.querySelector('.meal-details-content');
const recipeCloseBtn = document.getElementById('recipe-close-btn');
// event listeners
searchBtn.addEventListener('click', getMealList);
mealList.addEventListener('click', getMealRecipe);
recipeCloseBtn.addEventListener('click', () => {
mealDetailsContent.parentElement.classList.remove('showRecipe');
});
// get meal list that matches with the ingredients
function getMealList(){
let searchInputTxt = document.getElementById('search-input').value.trim();
fetch(`https://www.themealdb.com/api/json/v1/1/filter.php?i=${searchInputTxt}`)
.then(response => response.json())
.then(data => {
let html = "";
if(data.meals){
data.meals.forEach(meal => {
html += `
<div class = "meal-item" data-id = "${meal.idMeal}">
<div class = "meal-img">
<img src = "${meal.strMealThumb}" alt = "food">
</div>
<div class = "meal-name">
<h3>${meal.strMeal}</h3>
Get Recipe
</div>
</div>
`;
});
mealList.classList.remove('notFound');
} else{
html = "Sorry, we didn't find any meal!";
mealList.classList.add('notFound');
}
mealList.innerHTML = html;
});
}
It's because you are replacing the contents in the mealList element every time.
A simple workaround would be to retrieve the the innerHTML values before you update it.
Something like
let html = mealList.innerHTML;
rather than starting off empty every time you call the function should do the trick.

html button click to add value in javascript class

I have a few buttons with different categories. When the user clicks on the button, the correct category should be displayed. In every category, there are a few products, each with their own "add to cart"-button.
So, the user clicks "beds" and then adds item #3 to the cart (which updates and so on).
I have managed to do this with classes IF the user can't choose a category. It also works without classes if I add the buttons dynamically in js. But again, without allowing the user to choose a category.
I also want the user to be able to search for an item, get the item/ items displayed, and add it to the cart.
Get Products
class Products {
async getProducts() {
try {
const result = await fetch("/data/products.json");
const data = await result.json();
let products = data.items;
products = products.map((item) => {
const { category, title, price } = item;
const { id } = item.sys;
const image = item.image.url;
return { category, title, price, id, image };
});
return products;
} catch (error) {
console.log(error);
}
}
}
Display Products
class UI {
async displayProducts(products, searchText) {
let matches = products.filter(item => {
const regex = new RegExp(`^${searchText}`,'gi');
return item.category.match(regex);
})
let result = "";
matches.forEach((product) => {
result += `
<!-- single product -->
<article class="product">
<div class="img-container">
<img
src=${product.image}
alt="product"
class="product-img"
/>
<button class="bag-btn" data-id=${product.id}>
<i class="fas fa-shopping-cart">add to cart</i>
</button>
</div>
<h3>${product.title}</h3>
<h4>$${product.price}</h4>
</article>
<!-- end single product -->
`;
});
productDOM.innerHTML = result;
}
getBagButtons() {
const buttons = [...document.querySelectorAll(".bag-btn")];
In HTML I used onclick="displayProducts('bed')"
This will not work tho, since displayProducts is in a class.
I have also tried to add an id to each button and add an eventlistener in DOMContentLoaded, but that wrecks the rest of my DOMContentLoaded stuff
DOMContentLoaded
document.addEventListener("DOMContentLoaded", () => {
const ui = new UI();
const products = new Products();
// setup app
ui.setupAPP();
products
.getProducts()
.then((products) => {
ui.displayProducts(products);
Storage.saveProducts(products);
})
.then(() => {
ui.getBagButtons();
ui.cartLogic();
});
});
These are just a few of the things I've tried, but for each try, one issue is fixed but one or more issues are added, so I could really use some help here. Thanks!
These are the changes we made:
All category buttons gets this event listener
onclick="searchNdisplay(new UI, new Products, 'category text');"
This initializes the ui and products and they get displayed, so we changed it to use the searchNdisplay function
document.addEventListener("DOMContentLoaded", () => {
const ui = new UI();
const products = new Products();
// setup app
ui.setupAPP();
searchNdisplay(ui, products, "");
Storage.saveProducts(products);
});
This function repopulates the page with products that met the search criteria.
function searchNdisplay(ui, products, search)
{
products
.getProducts()
.then((products) => {
if (search == "")
{
ui.displayProducts(products);
}
else
{
ui.displayProducts(products, search);
}
})
.then(() => {
ui.getBagButtons();
ui.cartLogic();
});
}

How is it possible that piece of code that was working is now ignored?

I have coded a ajax based "JS TABS" containing .JSON file like 10 months ago, now wanted to reuse it, and can't find out why it's not working. I haven't touched it since and don't know where is the bug.
When i click the button to render products nothing prints out - except console telling me: items is undefined = so i moved it inside function changeCategoryItems(categoryId) { } well no errors but nothing renders...can someone help me ?
Here is a codepen reference of what i mean: https://codepen.io/Contemplator191/pen/WNwgypY
And this is JSON : https://api.jsonbin.io/b/5f634e0c302a837e95680846
If codepen is not suitable/allowed here is whole JS for that
let items = [];
const buttons = document.querySelectorAll('button');
const wrapper = document.querySelector('section.products');
buttons.forEach(function (button) {
button.addEventListener('click',event => {
changeCategoryItems(event.target.dataset.category);
});
});
function changeCategoryItems(categoryId) {
let items = [];
const buttons = document.querySelectorAll('button');
const wrapper = document.querySelector('section.products');
const viewItems = (categoryId == 0 ) ? items : items.filter(item => item.category == categoryId);
wrapper.innerHTML = "";
viewItems.forEach(item => {
const div = document.createElement('div');
div.setAttribute("class", "product");
div.innerHTML = createItem(item);
wrapper.appendChild(div);
});
};
function createItem(item) {
return `
<div class="product__img">
<img src="${item.img}" class="">
</div>
<div class="product__name _tc">
<h4 class="">${item.heading}</h4>
</div>
<div class="text-desc product__desc">
<p class="">${item.description}</p>
</div>
<div class="product__bottom-content">
<span class="product__info">${item.info}</span>
${item.btn}
</div>
`
}
fetch('https://api.jsonbin.io/b/5f634e0c302a837e95680846')
.then(function (res) { return res.json() })
.then(function (data) {
items = data.items;
changeCategoryItems(1);
});`
In your fetch you're trying to assign data.items to the items variable but the api doesn't return data with an items node so items is undefined. It's possible the api changed their return format since the last time you used it which would explain why it worked previously.
this seems to fix it
.then(function (data) {
items = data;
changeCategoryItems(1);
});
Your issue is in this line:
items = data.items;
Now, the returned value is an array, hence you can use it as it is.
The updated codepen

Categories