# TINKER - Javascript Part 0 **Tinker Guide**: https://hackmd.io/nxonDCa3Tm6Wvjc20eekiw?both **Group**: (Alex) Yixuan Xu, Yijia Wu, Kelly Huang, Dorothy Licorish ## Developer Tools Open up **[Bootstrap Meowmix](https://codepen.io/jmk2142/pen/EwKXbo)** as the sandbox for learning the developer tools. - What seems to be the difference between what gets printed in the console when you do `console.log` vs `console.dir` ? Hint: click on the caret that appears before the output with the `console.dir`. - `console.log` gives us the HTML code of that particular element, but the `console.dir` gives us all the attributes of that element in an array. - In the `Elements` tool right-click on the `#catBadge` and do `Copy > Copy Selector`. Paste it somewhere - what do you get? Try this with another element. - We got "#catBadge", which looks like a CSS selector. We tried this with a `<p>` element, we got `body > div:nth-child(1) > div > div > div > p`. We see that by copying the selector, we get CSS selectors of that element we copied from. - Like before, this time try `Copy > Copy JS Path`. Then, in your console type `console.dir()` and inside the parentheses paste what you copied. We are passing *an argument* into the `console.dir()` function call. Press `ENTER` to execute the code. - We got all the attributes of the element with id `#catbadge` - Try this again but for the "Extremely Deadly" badge that is inside our Table. - We got all the attributes of the element with selector `span.badge.badge-danger` - Based on your tinkering around with this tool, can you make any inferences about the code and how it works? - JS, CSS work together with HTML. HTML is the element blocks, CSS is for visual styles, and JS is for making the elements interactive. They are all interrelated. - Try some other things in the console. Any JS will work here. - We tried `clear()` and it cleared all our console history! - We tried `alert("helloooo!")` and it gave us a pop-up on the top of the page. ## Elements as HTML vs JS Objects Given that, let's look at a single representation of an element as an object, how we'd find it in the DOM. ```javascript= let el = { tagName: "DIV", id: "myID", className: "business-card", textContent: "TC" } ``` With above example code, what JS code do you need to write and execute in order to: - GET the class name of the element? - `element.className` - READ the text content of the element? - `element.textContent` - CHANGE the ID of the element to "ABC123"? - `element.id = "ABC123"` - WRITE/REPLACE the text "Teachers College, Columbia U." to this element? - `element.textContent = "Teachers College, Columbia U."` - ADD (not replace) a class "special" to the element? - `element.classList.add("special");` or `element.className += " special";` ## Objects in Objects - Analogy to Document Object Model Now lets revisit and imagine the DOM, represented as a giant nested JS Object with each object representing an element and its property/values. ```javascript= let el = { tagName: "DIV", id: "myID", className: "business-card", children: [ { tagName: "IMG", src: "http://myphoto.com" }, { tagName: "A", href: "http://mywebsite.com", textContent: "My Name" } ] } ``` In reference to the above code, what JS code do you need to write and execute in order to: - GET the anchor element object? - `el.children[1]` - READ the content of the anchor element? - `el.children[1].textContent` - Change the source of the image element to "images/unicorn.gif" ? - `el.children[0].src = "images/unicorn.gif";` - ADD the class "important" to all elements in the `children` list? - `el.children[0].className = "important";` - `el.children[1].className = "important";` - What if there were 1000 children element objects in this list? - We can use a `for` loop to iterate through all 1000 elements: ``` for (let i=0; i<1000; i++){ el.children[i].className = "important"; } ``` - What if also, we only wanted to add the class "important" if the element is an anchor and NOT an image? - we can add conditional logic using `if` to only add a class if it's an anchor ``` for (let i=0; i<el.children.length; i++){ if (el.children[i].tagName == "A") { el.children[i].className = "important"; } } ``` If I run some magical code that queries the page, finds, and returns to you an object that represents an element, and I give it the variable name `specialEl`... What code would you need to run in order to: - GET the type of element this is? - `specialEl.tagName` - Check whether this element has an ID? - `if (specialEl.id)` - Change the text content of this element from "Code yuck" to "Code YES!" ? - specialEl.textContent = "CODE YES!"; - To add the class "X" to this element? (It already has a class called "Z".)? - `specialEl.className += " X";` - Check whether there are any other nested elements inside this one? - `specialEl.children.length` ## Querying Elements from the DOM ```htmlembedded= <!-- HTML --> <div id="x" class="apple"> <div id="y"> <p class="story">My Paragraph</p> </div> </div> ``` ```javascript= // Computer conceptualizes the DOM like this: { tagName: "DIV", id: "x", className: "apple", children: [ { tagName: "DIV", id: "y", children: [ { tagName: "P", className: "story", textContent: "My Paragraph" } ] } ] } ``` ```javascript= document.querySelector("#x"); // returns object representing element div#x document.querySelector("#x").className; // returns class "apple" of div#x document.querySelector("#x").className = "apricot"; // sets|changes class of div#x // Using variables helps make our code readable and references reusable let el = document.querySelector("#y"); // returns the div#y object console.log(el.className); // prints "" to the console el.className = "pineapple"; // sets the class to "pineapple" let paragraph = el.children[0]; // el was div#y, children at index 0 is p.story alert(paragraph.textContent); // alert popup with textContent value ``` So now we can use Javascript to query the DOM, get elements, and then change them using what we understand about object manipulation. Above demo code: - Create a new PEN in codepen and copy the HTML into the HTML panel. - Go into debug mode and try the above JS code line by line in the console. - Get comfortable TYPING out this level of code by memory. Using **[Bootstrap Meowmix](https://codepen.io/jmk2142/pen/EwKXbo)**: - Apply the patterns and techniques above to: - Select and query elements of your choosing. - Read the values of different element properties. - Set or change the values of different element properties. - HINT: Since this is a bootstrap page - there are certain classes like the ones that end in `danger, warning, info, primary` that if you switch out... will give you an interesting effect. - Report your findings and thoughts. - One thing we noticed is that certain elements can have very very long selectors. For example, we copied the selector for a `.row` div and got `document.querySelector("body > div:nth-child(2) > div:nth-child(7)")`. We feel that this can be very difficult for us to implement in our code. - We tried to add a class to an element both by using`classList` and `className` properties. We can append a string to `className`. But when we try to use `push()` method that we learned in FCC on `classList`, it doesn't work. After some search, we realized that we would use `add()` which is a method for `Set` object. It turns out `classList` isn't an array. - We noticed properties like `innerText`, `textContent` are very similar and can get confusing. We did more research on this thread https://stackoverflow.com/questions/35213147/difference-between-textcontent-vs-innertext. This seems really tricky, we may need to be concious of whether a text is currently displayed or how a newline character will be shown. ## CSS Properties ```htmlembedded= <div class="pet">CAT</div> ``` ```css= .pet { width: 100px; font-family: Helvetica; background-color: gold; } ``` ```javascript= { tagName: "DIV", className: "pet", style: { width: "100px", fontFamily: "Helvetica", backgroundColor: "gold" } } ``` Above Demo Code: Compare and contrast the syntax of the CSS (rules) and how the computer represents the style object as part of the DOM. - What are some of the key differences between the two? - While there is a dash "-" in the CSS attribute, JavaScript doesn't have the dash. Instead, it uses camel case. - If you wanted to change the background color to "salmon" what would you write in the console (JS code?) - `document.querySelector(".pet").style.backgroundColor = "salmon"; ` Using **[Bootstrap Meowmix](https://codepen.io/jmk2142/pen/EwKXbo)**: - Using `document.querySelector()` and `console.dir()` lookup the `style` property of an element and browse through the list of properties available. - What are some style properties you've used in CSS before and can you manipulate them through JS? - We noticed styles like `color`, `backgroundColor`, `fontFamily`, `borderColor` and many more...There are so many! - If an element is not using a style rule, how is that represented in the object as a property/value pair? - It will be a property with an empty string `""` as value. ## Traversing the DOM... Using **[Bootstrap Meowmix](https://codepen.io/jmk2142/pen/EwKXbo)**: - Using the `Element` inspector with Meowmix, use the `Copy > Copy JS Path` to grab an element and set it to a variable `el`. - Use `console.dir(el)` to print an element object to the console. - Explore the object, "opening it up" by clicking on the small triangle/caret next to it. - Browse/Scroll through the object to get a superficial awareness of the different properties available. Thoughts? - There are so many properties we can potentially manipulate, a lot of them we haven't even seen before. We see properties starting with `aria`. By doing more research, we see that these are related to web accessibilities. We noticed a lot of `onSomething` properties which signifies interactions like clicking or dragging. We think that this can create some interesting interactive effects on our sites. - Dig deeper by clicking into the following properties. - `children` - `parentElement` - `nextElementSibling` - `previousElementSibling` - What do the values of these properties represent? - `children` includes all the children elements within this element, when we click the caret next to it, we get another whole list of properties again - `parent` contains the element that is the parent of our selected element. When we click into it, it also shows a list of properties. - `nextElementSibling` contains the next element following our selected element within the same parent. It also has a list of properties. - Though our `previousElementSibling` shows `null`, we suspect that if our selected element has a previous element within the same parent, it will show the previous element and its properties. - What is the relationship between an element and the values of these above properties? - We can identify parent-child and also sibling relationships bewteen our selected element and the values of these properties. - How far does the rabbit hole go? - This is endless! We can click the carets, go back and forth, and see another whole list of properties. Every element has this set of properties. We see how connected all the HTML elements are. Extend your thoughts to the following context: ```htmlembedded= <article id="item-xyz"> <h3>Code is fun!</h3> <p class="lead">It's a challenge but...</p> <p>I practice every day at <a href="http://codepen.io">Codepen</a></p> <div> <span class="author">Professor JK</span> <span class="published">05/16/2021</span> </div> </article> ``` ```javascript= // Code to articulate let el = document.querySelector("div > span"); let name = el.textContent; console.log(name); let articleEl = el.parentElement.parentElement; alert(articleEl.id); let pargraphEl = articleEl.querySelector(".lead"); let linkEl = paragraphEl.nextElementSibling.querySelector("a"); linkEl.href = "http://codepen.io/jmk2142"; let dataEl = document.querySelector("div"); dataEl.children[0].textContent = "05/16/2022"; ``` - Take turns verbally articulating the above code line by line, expression by expression to describe the state changes, sequence of statements/routines, and causality of executing said routines. - Try using terms like: - object, function, call, return, property, value, data, string, first/second/next/then, variable, assign, get, set, execute, console, print, index. - There are a few new twists here. You can make observations about the code behavior by creating a pen with the HTML and going through the JS in the console line by line. - What is the implication of this with respect to starting at some location within the structure of the DOM and getting to another location? In other words, "traversing the DOM". - Using JS, we can navigate through all the HTML elements by finding the relationships between elements, such as parent, child or silbling relationship. In a sense, every element is connected to one another. And we can point to a certain element in a lot of different ways, such as by query selecting itself, or by finding its parent, child or siblings. ## Manipulating the Web for Practice Use **[Bootstrap Meowmix](https://codepen.io/jmk2142/pen/EwKXbo)** for the following. Or feel free to use any website (E.g. Twitter, Pinterest, Facebook, TC's website) to hack around. Meowmix is simpler so it'll be more clear in terms of what is what. But "hacking" a website and fabricating fake-news is a lot more fun. :camera_with_flash: - Using the `Elements` inspector and `Console`, tinker around the Meowmix page and get comfortable with the Javascript we've been talking about above: - Querying elements - Reading element properties - Manipulating the value of said properties - Report back what you set out to do as a Tinker group, how you went about it, what the results were, and what you noticed / learned as it relates to the materials covered above. - We started "hacking" the TC page https://www.tc.columbia.edu/. We wanted to first change the banner text at the top. By using inspect, we click on the banner text and got the element highlighted for us. It was in a `<strong>` tag. Then, we copied the JS path and in the console, we added `console.dir(document.querySelector("body > div.header-notification-wrap > div > h3 > strong"))` just to check the different properties it has. - We then created a variable and changed the texts: ```javascript= let el = document.querySelector("body > div.header-notification-wrap > div > h3 > strong"); el.textContent = "NO SCHOOL!" ``` ![](https://i.imgur.com/RHLhWBs.jpg) - Now we have "NO SCHOOL!" for banner. - We then want to change a certain link since we haven't done so in this tinker. We got the JS path on the link element "tc.edu/preparedness" ```javascript= let ll = document.querySelector("body > div.header-notification-wrap > div > p > strong > span > a"); console.dir(ll); ll.href = "https://www.cdc.gov/"; ``` - Now when we click the link, it takes us to the CDC website. - We feel like though the information from writing`console.dir()` can be overwhelming, it can be really helpful to see the different properties we can manipulate. We can always find a certain property to change using JS. ## Super Challenges **Challenge 1:** Create a function that changes the text color to `#e91e63` any time the function is called. - Function name: something appropriate - Parameters: 1 String argument - a CSS Selector - Body: function should query the element using the argument, then change the appropriate property. - Returns: none - Other: proper indentation ```javascript= function changeColor(selector){ document.querySelector(selector).style.color = "#e91e63"; } ``` **Challenge 2:** Create a function that can will change the text content of a list of element. Instead of `document.querySelector()` you will need to use `document.querySelectorAll()` See [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) - Function name: something appropriate - Parameters: 2 String arguments - a CSS Selector, a text message - Body: function should query ALL elements matching the selector you passed in as an argument. It should loop through the list of elements returned by `querySelectorAll()` and for each element object, add or change the text content to the text message passed in as the second argument. - Returns: none - Hints: arrays, loops - Other: proper indentation, formatting ```javascript= function changeText(selector, message){ let items = document.querySelectorAll(selector); for (let i=0; i<items.length; i++){ items[i].textContent = "message"; } } ``` **Challenge 3**: Refactoring above function to augment its behavior. Function will alternate between adding color and changing text, as well as set an id for all elements. Additional Function 1: - Function name: `colorizedEl` - Parameters: 1 element Object argument - Body: this function should change the color property of the passed in element object to `#e91e63`. - Returns: the element object that you just changed the color of ```javascript= function colorizedEl(el){ el.style.color = "#e91e63"; return el; } ``` Additional Function 2: - Function name: `editedEl` - Parameters: 2 arguments - 1 element Object argument, 1 text message - Body: this function should add or change the text content to the text message passed in as the second argument. - Returns: the element object that you just changed the text of ```javascript= function editedEl(el, message){ el.textContent = message; return el; } ``` Additional Function 3: - Function name: `setID` - Parameters: 1 element Object argument - Body: this function should set an id on the element passed into the function as your argument to the following pattern: `id-` + `randomNum`. E.g. `id-101`, `id-224`, `id-694`. - Returns: none ```javascript= function setID(el){ el.id = "id-" + Math.floor(Math.random() * (1000 - 100) + 100).toString(); } ``` Refactored Function: Function from Challenge 2 but integrating the additional Function 1, 2, and 3 - Function name: something appropriate - Parameters: 2 String arguments - a CSS Selector, a text message - Body: Using your existing function from Challenge 2 you will modify/refactor it to do the following new thing. While looping through elements you will alternate between changing the color and changing the text. If the index is even you should use `colorizedEl` to change the color of the element. If the index is odd you should use `editedEl`. All elements should be given an id using the `setID` function. - Returns: none - HINT: arrays, loops, conditionals, using the function returns in a smart way (see Additional Function 1 and 2), calling functions in functions. - Other: proper indentation, formatting ```javascript= function changeAll(selector, message){ let items = document.querySelectorAll(selector); for (let i=0; i<items.length; i++){ if (i%2 === 0){ // even index items[i] = colorizedEl(items[i]); } else { // odd index items[i] = editedEl(items[i], message); } setID(items[i]); } } ```