Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document Object Model - practice #159

Merged
merged 20 commits into from
Sep 5, 2022
Merged

Conversation

zhenyakornilov
Copy link
Contributor

Document Object Model - practice

Demo |
Code base

The code is submitted in a dedicated feature branch.

Only code files are submitted.

Please, review.

@zhenyakornilov
Copy link
Contributor Author

Removed DOM calls from loop in renderButtons function

@zhenyakornilov
Copy link
Contributor Author

Could you give some advice how to load image faster?

@kasionio kasionio self-requested a review August 22, 2022 20:04
@kasionio kasionio self-assigned this Aug 22, 2022
Copy link
Contributor

@kasionio kasionio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job, looking good! Please take a look at the comments. And I found some weird behavior. A highlighted zone is also active but doesn't have a hover effect
image

box-sizing: border-box;
}

ul,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this style applies just for li tags, so you can leave just one tag here
https://developer.mozilla.org/en-US/docs/Web/CSS/list-style

background: none;
color: inherit;
border: none;
padding: 0;
Copy link
Contributor

@kasionio kasionio Aug 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you specified this property for all elements in the first lines

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en" id="root">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a common practice to divide responsibility - ids for JS, classes for styling. Better to use the wrapper in this case and set styles for wrapper, not for htmltag. Using html styling is even bad for performance reasons

Copy link
Contributor Author

@zhenyakornilov zhenyakornilov Aug 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can I use :root pseudo-class in CSS instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the common use of :root is for variables declaration. For such files root will be always html
https://developer.mozilla.org/en-US/docs/Web/CSS/:root

.nav-item {
border-bottom: 1px solid #f5f5dc;
width: 20rem;
margin: 10;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are the units?

<header class="header">
<span class="dropdown-wrap">
<button class="dropdown">
<i class="fa-solid fa-bars fa-lg"></i>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fa-solid fa-bars fa-lg. What are these classes for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's Font Awesome prebuilt classes, I thought it is not needed to change them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right. my bad

}

function renderArticle(museumObj, content) {
const contentHTML = `
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

function toggleSelectedButton(museums, content) {
let selectedButton = document.getElementsByClassName("nav-item")[1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logically, default value is the first element of the array, not second

function changeTheme() {

const checkbox = document.getElementById("switcher");
checkbox.addEventListener("change", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to separate the handler function from a listener.
el.addEventListener("change", handler);
function handler {}


document.addEventListener("DOMContentLoaded", main);

function renderButtons(arr, menu) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arr sounds too generic. We can name it listOfCards for example or what you prefer more

function renderButtons(arr, menu) {
let buttonsHTML = ``;

arr.forEach(({ btnName }) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map looks like the optimal choice

@kasionio
Copy link
Contributor

kasionio commented Aug 22, 2022

About images - the simplest way is to compress images or use a lightweight format such as webp. One more option - while an image is loading you can set some default placeholder instead. Also, HTML has a cool tag picture, take a look on it
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture
https://developers.google.com/speed/webp

@zhenyakornilov
Copy link
Contributor Author

Tried to make all fixes accordingly to remarks.

@zhenyakornilov
Copy link
Contributor Author

I have questions about some remarks, see in comments above.

@zhenyakornilov
Copy link
Contributor Author

Nice job, looking good! Please take a look at the comments. And I found some weird behavior. A highlighted zone is also active but doesn't have a hover effect image

this one looks to be fixed too

Copy link
Contributor

@kasionio kasionio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great progress, but let's improve JS part 🚀

</main>
<footer class="footer">
<a class="footer-link" href="https://github.com/zhenyakornilov" target="_blank">
<span><i class="fa-brands fa-github"></i> Yevhen Kornilov</span>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is a good practice to place one tag in a line

grid-template-areas: "header-top header-top" "content-main content-main" "footer-bottom footer-bottom";
}

.dropdown {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't understand this remark here.

Do You mean something wrong with grid-template-areas?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have two similar classes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet I don't get what I have to change here(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

look at line 132

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what's wrong here. I defined .dropdown in CSS with display none to hide and then changed this in media query to make it visible.

}

.dropdown-wrap {
display: inline;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it the default display value?

outline: inherit;
}

:root {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use html if you want

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I change html font-size since I use rem and when html font-size is equal to 62.5% then 1 rem is like 10 pixels, 2.1rem is 21 pixels etc. It makes more clear to me rem values to interpret them as pixels.

}

.header .check-switch:checked + .theme-switcher .circle {
transform: translatex(2.4rem);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

X from capital :))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too specific selector, WDYT?

@@ -0,0 +1,89 @@
"use strict";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make JS more readable let's try to do some improvements:

we can declare all elements which we found by getElement at the top of the file;
then we can declare all functions. Functions should be pure, which means do one thing;
at the bottom, we can add listeners;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed index.js. Did You mean something like it looks now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet. Divide listeners and functions
element.addEventListener(event, listener);
Look below, the listener is bold

function showMuseumInfoByClick(museums, content, menu) {
  menu.addEventListener("click",function ({ target }) {
    if (target.tagName.toLowerCase() === "button") {
      const currentContentObject = museums.filter(
        ({ btnName }) => btnName === target.textContent
      );
      renderArticle(currentContentObject[0], content);
    }
  });
} 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

separated listeners and functions

@@ -0,0 +1,15 @@
function toggleDarkClass() {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to add spaces inside a function. It should looks like a block of code


const buttons = document.getElementsByClassName("nav-item");

function getContextObj() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please explain what function name getContextObj mean. I really want to understand :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function returns object from museums array to render as content.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean name. getConteNtObject?

renderArticle(getContextObj(), content);

for (let button of buttons) {
button.addEventListener("click", function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here you added a listener to every button. why not add a listener to the navigation menu?


renderArticle(getContextObj(), content);

for (let button of buttons) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to use a different approach. for...of is not needed here. now it seems that you take different parts of code from different sources

@zhenyakornilov
Copy link
Contributor Author

Tried to make changes accordingly to recommendations, but still have some questions above.

@kasionio
Copy link
Contributor

Please do not resolve comments, I need to see them

Copy link
Contributor

@kasionio kasionio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job! Please take a look at the comments and make corresponding changes. Also add hover effect to theme-switcher

grid-template-areas: "header-top header-top" "content-main content-main" "footer-bottom footer-bottom";
}

.dropdown {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

look at line 132

<body class="body">
<div class="wrapper">
<header class="header">
<span class="dropdown-wrap">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You deleted this class in the CSS file

<p class="museum-desc">${description}</p>
</div>
<div class="additional-wrapper">
<p class="museum-link">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a look at when you can use p tag and find appropriate tag
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p

<ul class="menu-items" id="menu"></ul>
</nav>
<main class="content">
<article class="content-body" id="content"></article>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have misunderstanding here. I have h2 tag added with JS inside article tag, isn't it can be counted as header? Or shall I set h2 tag inside index.html? May I just change article tag to div then?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right, I missed h2. All is fine here

import switchTheme from "./utils.js";

function main() {
const dropdownBtn = document.getElementById("dropdown");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you get element by id dropdown and name it dropdownBtn, which means button. seems inconsistent naming here

@@ -0,0 +1,89 @@
"use strict";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet. Divide listeners and functions
element.addEventListener(event, listener);
Look below, the listener is bold

function showMuseumInfoByClick(museums, content, menu) {
  menu.addEventListener("click",function ({ target }) {
    if (target.tagName.toLowerCase() === "button") {
      const currentContentObject = museums.filter(
        ({ btnName }) => btnName === target.textContent
      );
      renderArticle(currentContentObject[0], content);
    }
  });
} 

</div>
<div class="additional-wrapper">
<p class="museum-link">
<span>Visit </span>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why span? you can leave this text without wrapping in a tag

const contentHTML = `
<h2 class="museum-title">${name}</h2>
<div class="desc-wrapper">
<img class="museum-image" src="${imageSrc}" alt="photo of museum">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alt should be moved to data.js as one of the paramters, because it can't be the same for different images

@zhenyakornilov
Copy link
Contributor Author

New chnages added, but some questions left.

Copy link
Contributor

@kasionio kasionio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better now, great job!
Some small changes left. And about the hover effect on switchTheme button. All interactive elements should have pointer cursor on hover


function showMuseumInfo({ target }) {
if (target.tagName.toLowerCase() === "button") {
const currentContentObject = museums.filter(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

function showMuseumInfo({ target }) {
if (target.tagName.toLowerCase() === "button") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do not use .closest here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also better to prevent rendering when you click on the same button which already selected


themeSwitcher.addEventListener("change", toggleDarkClass);
dropdownBtn.addEventListener("click", openDropdownMenu);
listMenu.addEventListener("click", showMuseumInfo);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good article to understand the events bubbling process
https://javascript.info/bubbling-and-capturing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@zhenyakornilov
Copy link
Contributor Author

Added latest changes

Copy link
Contributor

@kasionio kasionio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make last small improvements ;)

const contentBody = document.getElementById("content");

function renderButtons(museumsObj, menu) {
let buttonsHTML = museumsObj
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you have plural, better name it like buttonsListHtml


function showMuseumInfo({ target }) {
if (target.closest(".btn-text")) {
let currentSelectedBtn = target.closest(".nav-item");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can move it higher and then make instead of two one if statement

let currentSelectedBtn = target.closest(".nav-item");
if (!currentSelectedBtn.classList.contains("active")) {
const [currentContentObject] = museums.filter(
({ btnName }) => btnName === target.textContent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better use id to identify the target item, not the text. For example, we can have two items with the same button name. So, in such cases we should always use id for DOM manipulation

@zhenyakornilov
Copy link
Contributor Author

Added new changes accordingly to remarks.

Copy link
Contributor

@kasionio kasionio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, I guess :) Good job 👍

@kasionio kasionio merged commit 3c6dc96 into kottans:main Sep 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants