Аdding elements to a DOM via a javascript - javascript

Can you tell me how using only Javascript we can add elements to a html document? There is a function createCards() that creates cards, after that the forEach method fills these cards with content from some array. The last step remains, add to the document. I know that the prepend method is applicable here (and I don't like innerhtml... But I don't quite understand how to designate the element that I need to insert. Thanks a lot!
const initialCards = [
{
name: 'place1',
link: 'https://pictures.s3.yandex.net/frontend-developer/cards-compressed/arkhyz.jpg'
},
{
name: 'place2',
link: 'https://pictures.s3.yandex.net/frontend-developer/cards-compressed/chelyabinsk-oblast.jpg'
},
{
name: 'place3',
link: 'https://pictures.s3.yandex.net/frontend-developer/cards-compressed/ivanovo.jpg'
},
];
const editProfile = document.querySelector('.profile__edit-button');
const popupProfile = document.querySelector('.popup__profile');
const popupNewPlace = document.querySelector('.popup-new-place');
const newPlaceButton = document.querySelector('.profile__add-button');
const closeButtons = document.querySelectorAll('.popup__close');
const yourName = document.querySelector('.profile__info-name');
const nameInput = popupProfile.querySelector('#profile-name');
const yourJob = document.querySelector('.profile__info-subtitle');
const jobInput = popupProfile.querySelector('#profile-job');
const formProfile = popupProfile.querySelector('.popup__edit-profile');
const formNewPlace = popupNewPlace.querySelector('.popup__edit-profile');
const contentItems = document.querySelector('.content');
function createCard (item) {
const contentItemTemplate = document.getElementById('content-item').content;
const newContentItem = contentItemTemplate.querySelector('.content__item').cloneNode(true);
newContentItem.querySelector('.content__title').textContent = item.name;
newContentItem.querySelector('.content__item-image').alt = item.name;
newContentItem.querySelector('.content__item-image').src = item.link;
newContentItem.querySelector('.content__like').addEventListener('click', function(event){
event.target.classList.toggle('content__like_active');
})
newContentItem.querySelector('.content__trash').addEventListener('click',function(event){
(event.target.closest('.content__item')).remove();
});
return newContentItem;
};
initialCards.forEach(createCard);

You could use appendChild() method, "document.querySelector('.containerForExample').appendChild('newContentItem)

you should read these articles to get more familiar with how to create an element and add it to the DOM using javascript
create Element function
append child function
insert before function
I hope that solves your problem. Thanks

Related

How to make a function change only the first array element

I'm quite new to JavaScript, and I'm stuck with an issue which I didn't manage to find an answer for.
I have an array, each item of which is tied to a card in markup.
When a button is pressed, a form pops up and allows to enter name and url for the new image, which is then unshifted to thebeginning of the array.
The last element of the array is popped, so there's always the same number of elements.
And the issue itself is:
When I add a single card, it works perfect: last card is popped and the new one is tucked in the beginning.
But when I use and submit the form again, the card that I have previously edited changes as well, although it should not.
I suspect that the mistake lies in the function that updates the cards, but I'm all out of ideas how to fix it.
Is there a way to fix that function?
const formAdd = document.querySelector('.popup__form-add')
const newElement = { name: '', link: '' };
const blank = { name: '', link: '' };
const placeName = document.querySelector('.popup__edit_type_place-name');
const placeImage = document.querySelector('.popup__edit_type_place-picture');
const elements = document.querySelector('.elements');
const cards = elements.querySelectorAll('.element');
const buttonAdd = document.querySelector('.profile__button-add');
const buttonAddClose = document.querySelector('.popup__add-button-close');
//content popup functions
function popupAddDisplay() {
popupAdd.classList.add('popup_opened');
}
function popupAddHide() {
popupAdd.classList.remove('popup_opened');
}
function contentUpdate() {
event.preventDefault();
newElement.name = placeName.value;
newElement.link = placeImage.value;
console.log(newElement);
initialCards.pop();
initialCards.unshift(blank);
blank.name = newElement.name;
blank.link = newElement.link;
console.log(initialCards);
cardsCheck();
popupAddHide();
};
//cards array, page content loads from here
const initialCards = [{
name: 'Архыз',
link: 'https://pictures.s3.yandex.net/frontend-developer/cards-compressed/arkhyz.jpg'
},
{
name: 'Челябинская область',
link: 'https://pictures.s3.yandex.net/frontend-developer/cards-compressed/chelyabinsk-oblast.jpg'
},
{
name: 'Иваново',
link: 'https://pictures.s3.yandex.net/frontend-developer/cards-compressed/ivanovo.jpg'
},
{
name: 'Камчатка',
link: 'https://pictures.s3.yandex.net/frontend-developer/cards-compressed/kamchatka.jpg'
},
{
name: 'Холмогорский район',
link: 'https://pictures.s3.yandex.net/frontend-developer/cards-compressed/kholmogorsky-rayon.jpg'
},
{
name: 'Байкал',
link: 'https://pictures.s3.yandex.net/frontend-developer/cards-compressed/baikal.jpg'
}
];
//compares info from the markup with the array, then pushes array info into markup
function cardsCheck() {
cards.forEach(function(item, index) {
const nameAlt = initialCards[index].name;
const imageSrcAlt = initialCards[index].link;
item.querySelector('.element__name').textContent = nameAlt;
item.querySelector('.element__image').src = imageSrcAlt;
if (nameAlt == '') {
item.style.display = 'none'
}
console.log(nameAlt);
});
}
document.onload = cardsCheck();
buttonAdd.addEventListener('click', () => {
popupAddDisplay()
});
buttonAddClose.addEventListener('click', popupAddHide);
formAdd.addEventListener('submit', contentUpdate);```
You always use the same blank object. So at the end you have the same object multiple times in the array. If you change an attribute of this object it is changed wherever it is in the list also.
To avoid this you need to create a new object before adding it to the array
function contentUpdate() {
event.preventDefault();
newElement.name = placeName.value;
newElement.link = placeImage.value;
console.log(newElement);
initialCards.pop();
let blank = { name: '', link: '' };
initialCards.unshift(blank);
blank.name = newElement.name;
blank.link = newElement.link;
console.log(initialCards);
cardsCheck();
popupAddHide();
};
Every time you create a new card, it seems like you override the global variables blank and newElement.
However, you don't have to. You could create a local variable in your contentUpdate function called newElement.
That way, each time updateContent is called, a new local variable is created.
You could therefore try the following code:
const formAdd = document.querySelector('.popup__form-add')
const placeName = document.querySelector('.popup__edit_type_place-name');
const placeImage = document.querySelector('.popup__edit_type_place-picture');
const elements = document.querySelector('.elements');
const cards = elements.querySelectorAll('.element');
const buttonAdd = document.querySelector('.profile__button-add');
const buttonAddClose = document.querySelector('.popup__add-button-close');
//content popup functions
function popupAddDisplay() {
popupAdd.classList.add('popup_opened');
}
function popupAddHide() {
popupAdd.classList.remove('popup_opened');
}
function contentUpdate() {
event.preventDefault();
const newElement = {}
newElement.name = placeName.value;
newElement.link = placeImage.value;
console.log(newElement);
initialCards.pop();
initialCards.unshift(newElement);
console.log(initialCards);
cardsCheck();
popupAddHide();
}

Change Object Index

Is there way to change the index dynamically? or rebuild this object to where the 1 will be the Id of what ever object get passed into the function? Hope this makes sense.
export const createTree = (parentObj) => {
//keep in memory reference for later
const flatlist = { 1: parentObj }; <---- change the 1 based on parent.Id
...
}
My attempt thinking it would be easy as:
const flatlist = { parentObj.Id: parentObj };
Use computed property names to create a key from an expression:
const createTree = (parentObj) => {
const flatlist = { [parentObj.id]: parentObj };
return flatlist;
}
console.log(createTree({ id: 1 }));

Adding a class to a created element

The parameter of my function is a function. It should create an element but I should still be able to add attributes by using the parameter details.
E.g.:
const addElement = (details) => {
const element = document.createElement('div');
}
addElement(function() {
element.id = 'my-div'; // Not working since element is not defined
});
Well, I have tried to store the element in an object to be able to use it outside of that function.
let element = {};
const displayVideo = (type, details) => {
element = document.createElement(type);
element.width = 200;
element.height = 200;
element.classList.add('my-class'); // <--- THE PROBLEM!
if (details) {
details();
}
document.querySelector('#layer').insertBefore(element, document.querySelector('#el'));
};
displayVideo('VIDEO', function () {
element.controls = true;
});
My element can not be created because of element.classList.add('my-class'); and I don't even get an error message. If I remove that line, it works but I would still like to be able to add a class to that object. How can I do this?
Just pass element into the function. Since you're just editing properties on the object, this won't cause reference vs value errors.
const addElement = (details) => {
const element = document.createElement('div');
if (details) details(element);
return element;
}
const ele = addElement(function(element) {
element.id = 'my-div';
});
console.log(ele);
In this case details could be something like classname.
function element(type, classname) {
var element = document.createElement(type);
if (classname !== undefined) {
element.classList.add(classname);
}
return element;
};
element("div","my-class"); //<div class="my-class"></div>
Of course instead of classname you could use an array or an object and loop through in order to set multiple attributes.
Or you could store the return value of your function in a variable and then add all the attributes:
var myelement = element("div");
myelement.classList.add("my-new-class");
myelement //<div class=​"my-new-class">​</div>​

Am doing the destructing right?

I have a coding challenge, which am sure am getting it right , but the challenge requires that certain steps need to be in account before moving forward. And i seem to be skipping a step which is to de-structure a value from a target of an event(hope am saying it right)
The question is to get the expected event parameter to the target property with a de-structure.
Is my code wrong?
const displaySelectedUser = (event) => {
var newcal = event.target.value;
console.log(newcal);
console.log((event.target.value));
var user = getSelectedUser(newcal);
var properties = Object.keys(user);
console.log(properties);
properties.forEach(prop => {
const span = document.querySelector(`span[data-${prop}-value]`);
if (span) {
span.innerText = user[prop];
}
});
};
It's not wrong - but the only practical opportunity you have for destructuring is here:
var newcal = event.target.value;
Do this:
var { target: { value: newcal } } = event;
Because you're not using the other properties of event, you could move this up to the function declaration instead:
const displaySelectedUser = ({ target: { value: newcal } }) => {...}
Now newcal will already be defined as event.target.value in your function.

Updating one element after another updates

I'm working on a page in which one element ('.item--itemprice') updates its text through another function that I'd prefer not to touch. What I'd like to do is get another element ('.header--itemprice') to update so that its text matches the first element.
Unfortunately, it seems that handler below is acting faster than the updating function. As a result, the header either stays with the previous text or changes to a blank string. Is there a way to delay the final line below until after the first element is finished updating?
$('select').on('change', function() {
const headPrice = document.querySelector('.header--itemprice');
const lowerPrice = document.querySelector('span.item--itemprice');
const $lowerText = $(lowerPrice).text();
$(headPrice).text($lowerText);
});
Here's the preexisting function:
$(document).ready( function () {
$('#txtQuantity, .ProductGroupItemQuantity').blur(updatePrice);
});
function updatePrice() {
var itemPriceEl = $('.item--itemprice');
var itemCountEl = $('#txtQuantity');
var groupUpdateEl = $('#lnkProductGroupUpdatePrice');
var groupPriceEl = $('.pdetail--price-total');
var totalPriceEl = $('.ProductDetailsPricing');
var itemPrice = moneyToNumber(itemPriceEl.text());
var itemCount = moneyToNumber(itemCountEl.val());
var itemTotalPrice = itemCount * itemPrice;
var groupTotalPrice = 0;
// Trigger Group Update
groupUpdateEl.click();
groupTotalPrice = moneyToNumber(groupPriceEl.text());
// Calculate Total Price
totalPriceEl.text('Total: $' + Number(groupTotalPrice + itemTotalPrice) / 100);
}
/*$('select').on('change', function() {
const headPrice = document.querySelector('.header--itemprice');
const lowerPrice = document.querySelector('span.item--itemprice');
const $lowerText = $(lowerPrice).text();
$(headPrice).text($lowerText);
});*/
function moneyToNumber(moneyEl) {
try {
return Number(moneyEl.replace(/[^0-9\.]+/g,"").replace(/\D/g,''));
} catch (err) {
return 0;
}
}
If you don't want to touch the other function at all and assuming it is also being called on the change event of select. A really hacky way could be, something like this -
$('select').on('change', function() {
setTimeout (function()
{
const headPrice = document.querySelector('.header--itemprice');
const lowerPrice = document.querySelector('span.item--itemprice');
const $lowerText = $(lowerPrice).text();
$(headPrice).text($lowerText);
}, 0);
});
In that case, the better way is changing the function, you can even trigger a event when the function is executed and watch this event to trigger the other function to change the element ('.header--itemprice')

Categories