My solutions for the JavaScript 30 Day Challenge.
-
Takeaways: Be sure to note the differences between keydown, keyup, and keypress. If using keydown, the event continues to fire multiple times if the user holds the key down, so you need to be aware of that and account for that if needed. I disabled the key after the initial keydown and then re-enabled it on keyup to avoid the sound being played a million times.
-
Takeaways:
transform-originis useful for controlling where the transform takes place. The default is 50%, or in the middle of the element, and 0% or 100% puts the origin at one of the ends. -
Takeaways: Range and color input styles vary from browser to browser, so be sure to test everywhere you plan on supporting.
element.datasetis supported in IE11+, butelement.getAttributeis supported everywhere.filteris a neat CSS property for applying various graphical effects, but it's newer so it isn't supported in old browsers. If you are using your mouse, thechangeevent fires on range inputs when you've let go (so onmouseup), but theinputevent fires anytime the input changes, even while you are holding the click and dragging. -
Takeaways: Know your array helpers. DOM APIs like
querySelectorAllreturn a collection of nodes (in this case, DOM elements) in aNodeList, which is somewhat similar to an array but doesn't have all the methods that theArrayprototype does. For example, you can't callreduceon aNodeList. You first need to convert theNodeListto an array, which can be done withArray.from().reduce()is an efficient way to combine amap()andfilter()so that you don't have to loop through the array twice. -
Takeaways: Flexbox is great for positioning elements! Transitions look even cooler when you use a cubic-bezier timing function. The transitionend event is only helpful if you can avoid having the transition called multiple times. For example, the panels grow and shrink in this demo, so unless you disable the clicking during the transition, you can get into a weird state if someone clicks multiple times. I solved the problem with CSS transitions alone, and you can see if you click on a panel rapidly it is handled well. You can include orientation specific CSS on mobile devices using media queries. In my case, I only show the panels when the device is in landscape orientation.
-
Takeaways: When using the fetch API, the first thing you need to do is transform the data with the
.json()method. Autocomplete dropdowns take a lot of work to be accessible. They need to have proper ARIA roles and attributes, they need to show hover and focus indicators, and they need to be accessible for keyboard-only users. -
Takeaways: Know your array helpers.
somereturnstrueif at least one element in the array meets the test function's criteria orfalseif none of the elements meet the test function's criteria.everyreturnstrueif all the elements in the array meet the test function's criteria orfalseif even one element doesn't meet the test function's criteria.findreturns the first element that meets the test function's criteria or returnsundefinedif none of the elements meet the test function's criteria.findIndexreturns the index of the first element that meets the test function's criteria or -1 if none of the elements meet the test function's criteria. -
Takeaways: Drawing on a canvas is relatively simple. If you change the canvas's
widthattribute, the canvas clears itself. On a device that uses a mouse, the drawing functionality can be achieved with mouse events likemousedown,mousemove,mouseup, andmouseout. In order to make the drawing functionality work on touch screen devices, you must implement the corresponding touch events, liketouchstart,touchmove, andtouchend. -
Takeaways: There are many more ways to write data to the console than just with
console.log! You can do string interpolation with%s, but template literals make that feature a little less exciting. You can style your message with%c, which is pretty neat. Other useful methods arewarn,error,info,assert,clear,dir,group/groupCollapsed/groupEnd,count,time/timeEnd, andtable. -
Hold Shift and Check Checkboxes
Takeaways: Shift-clicking to select multiple boxes is a really nice feature to help make the user experience better when dealing with long lists. When implementing this functionality you need to handle both the selecting and deselecting of multiple checkboxes. It's important that inputs have labels on them so that both the checkbox itself and the label text are clickable. You can disable text highlighting with the CSS rule
user-select: none. -
Takeaways: A lot goes into building a custom HTML5 video player in order to make it accessible and keyboard navigable.
-
Takeaways: Nothing too exciting here. Key loggers are pretty simply to make, just listen to the
keyupevent and record the event'skeyorkeyCodevalue. -
Takeaways: Introducing images or other content with subtle animations can be a nice touch to your website when done properly. When handling scroll events (or any event that fires repeatedly over a short period of time), you can choose to debounce or throttle your function so that it runs less frequently. A debounced function sets up a timer that gets reset every time the function is called, so your wrapped function only executes once the timer has been able to fully run. A throttled function on the other hand simply limits how often the wrapped function can be called and does not reset its internal timer when the function is called repeatedly. For example, if you are listening to the scroll event with a throttled function that is limited to run every 200ms, and you scrolled non-stop for about one second, the throttled function would be called 5 times. A debounced function would have only been called once, 200ms after you had stopped scrolling.
-
JavaScript References vs. Copying
Takeaways: Numbers, strings, and booleans are passed by copy (or by value). Arrays and objects are passed by reference, so you need to be sure to actually make a copy of the array or object if you want to modify the copy without also modifying the original. You can make copies of arrays with methods like
slice,concat,Array.from, or the spread operator (...). You can make copies of objects with methods likeObject.assignor the spread operator (...). One thing to note is that all these methods make shallow clones, meaning that they only make copies one level deep. So if you have a deeply nested object, you make a copy of it, and then you modify a value on the copied object that is on the second level or deeper, it will also modify the value of the original object too. -
Takeaways: Local storage is a key-value store that only supports strings. If you want to store arrays or objects, you need to stringify them with
JSON.stringifyand then store that value. When retrieving the value, you can then callJSON.parseto turn your value back into an array or object. -
Takeaways: When calculating the X and Y coordinates, there are a lot of things to take into account.
HTMLElement.offsetHeightandHTMLElement.offsetWidthare the element's layout height and width.HTMLElement.offsetLeftandHTMLElement.offsetTopare the number of pixels that the upper left corner (or top, respectively) of the current element is offset to the left (or top, respectively) within theHTMLElement.offsetParentnode.event.target.offsetXandevent.target.offsetYfrom theMouseEventare the offset between the mouse pointer and the left (or top, respectively) edge of the target element. -
Takeaways: Nothing too exciting here. RegEx is a useful thing to know and can be used in a string's
replacemethod. Strings can be compared with operators like<and>. When doing string comparisons, earlier letters like "c" are evaluated as being "less than" later letters like "t". Uppercase letters are evaluated as being "less than" lowercase letters (meaning uppercase letters come first). So, to do an impartial comparison, it can be useful to convert your strings to all lowercase or all uppercase before doing the comparison. -
Takeaways:
NodeListsare not the same asArraysand have different methods on their prototype. You can easily create an array from aNodeListusing theArray.frommethod.reduceis a handy method to loop through your array and transform it into another data type, like an object or a number. When dealing with large data sets, you want to avoid looping over the data multiple times, as that is not very efficient. -
Takeaways: Creating filters is fun! Canvases and videos can be used to display live video streams as well to take photos. Image data on a canvas can be retrieved, manipulated, and returned to create some neat effects. The
getUserMediaAPI is relatively young and has gone through some changes in the past few years, so you have to include quite a lot of fallback code to handle things properly in older browsers. For example,navigator.getUserMediais now found atnavigator.mediaDevices.getUserMedia, and this method returns a Promise rather than using callbacks. To attach the media stream to the video element, you used to be able to usecreateObjectURL, but that method is being deprecated in favor of simply set the value ofvideo.srcObjectto the media stream. In order to make this demo work on mobile devices, you also have to set a few more attributes on the video element:muted,autoplay, andplaysinline. This keeps the video in the context of your webpage instead of breaking out into the mobile device's own native video player.NOTE: Access to the user's camera requires the webpage to be served over HTTPS, so if your site does not have an SSL Certificate (like mine), you can still visit the site with a url that begins with
https://, you'll just get a warning from your browser that the site is not secure. You can then choose to still visit the site. -
Takeaways: The Speech Recognition API is an experimental technology that doesn't have wide browser support yet. Still, it's a neat concept.
NOTE: Access to the user's microphone requires the webpage to be served over HTTPS, so if your site does not have an SSL Certificate (like mine), you can still visit the site with a url that begins with
https://, you'll just get a warning from your browser that the site is not secure. You can then choose to still visit the site. -
Takeaways: The Geolocation API can retrieve more data than just the user's latitude and longitude. On mobile devices, it can also give you the speed and the heading (direction) of the device when it's moving. The location data isn't always super accurate and can be gathered in a few different ways (this list goes from most accurate to least accurate): GPS, a WiFi positioning system, triangulation with your mobile network, or using the device's IP address.
NOTE: Access to the user's location requires the webpage to be served over HTTPS, so if your site does not have an SSL Certificate (like mine), you can still visit the site with a url that begins with
https://, you'll just get a warning from your browser that the site is not secure. You can then choose to still visit the site. -
Takeaways:
Element.getBoundingClientRectreturns the size of an element and its position relative to the viewport (not its position relative to the document if you've scrolled). If you want to take into account scroll position as well, you can usewindow.scrollYorwindow.scrollX. -
Takeaways: Speech Synthesis Utterance is a pretty cool API. It can be used to read text to you out loud in various different voices. The API is still considered experimental, but it does have decent support from most major browsers. IE doesn't support it though (surprise, surprise).
-
Takeaways: Implementing a sticky nav and other subtle transitions and animations on your web page can make it go from boring to awesome, if done properly. The scale effect is a nice touch.
-
Event Capture, Propagation, Bubbling, and Once
Takeaways: Events bubble up the DOM by default, but you can make then capture down the DOM by passing an option when adding your event listener. When removing event listeners, you should be as specific as you can be, so if you added an event listener with a method and some config options, you should remove it with that same method and config options. If you stop the event propagation, it stops being handled on the additional elements that it would have normally bubbled up or captured down to. The
onceoption is a new option that allows you to have the event handler run just once and then remove the event listener on that element so that it doesn't run again unless you re-add the event listener again. -
Takeaways: Follow-along nav animations are difficult to implement, especially when you try to take into account hovering with a mouse, focusing/tabbing with a keyboard, and mobile touch events. This example isn't perfect, but it's a nice proof of concept.
-
Takeaways:
Element.scrollLeftis the amount of pixels that an element has been scrolled from the left.Event.pageXis the X coordinate of the event (mousemove in this case) relative to the document.Event.clientXis the X coordinate of the event (mousemove in this case) relative to the viewport. These two numbers would be different if you had horizontally scrolled on the entire page (and same forEvent.pageYandEvent.clientYwhen the page has been vertically scrolled). -
Takeaways: Mouse coordinates are calculated a little differently than touch coordinates. Likewise, mouse events use different event listeners than touch events (ex.
mousemovevs.touchmove). -
Takeaways: A really neat trick for keeping accurate timers is to calculate the amount of seconds left each tick based on the current time and the start time rather than simply setting up a seconds variable that you decrement by 1 each tick. This helps prevent issues that occur if the interval is deprioritized by other process running in the event loop or if the user switches to a different tab in their browser.
-
Takeaways: The
isTrustedread-only property of theEventinterface is a boolean that is true when the event was generated by a user action, and false when the event was created or modified by a script or dispatched viaEventTarget.dispatchEvent().
