Skip to content

Latest commit

 

History

History
1488 lines (993 loc) · 41.7 KB

analysis.md

File metadata and controls

1488 lines (993 loc) · 41.7 KB

Javascript 30 Analysis

This is a summary of the key information I took away from each project.

Back to top


1. Javascript Drum Kit

What I learned on this mini-project.

addEventListener

window.addEventListener('keydown', playSound);

This is used to attach an event handler to the window object. An event in this context is when "something happens to the window object".

  • keydown is the event name
  • playSound is the function that runs when the event happens

querySelector & querySelectorAll

const key = document.querySelector(`.key[data-key="${event.keyCode}"]`);

const keys = document.querySelectorAll('.key');

This will return the HTML element you trying to select (or all of them as a NodeList), an example of what will be stored in key is shown below.

<div data-key="65" class="key">
    <kbd>A</kbd>
    <span class="sound">clap</span>
</div>

classList

key.classList.add('playing');
key.classList.remove('playing');
key.classList.append('playing');

This quite simply adds classes like you would in jQuery with key.addClass.

transitionend

key.addEventListener('transitionend', removeTransition)

You can listen for when a transition finishes, the length of the transition (in this case) was given in the following CSS transition: all .07s ease;

Further research

  • NodeList

Back to top


2. JS and CSS Clock

What I learned on this mini-project.

Date object

You can extract the second, minute and hour of the date object by accessing it's object methods.

const seconds = now.getSeconds();
const minutes = now.getMinutes();
const hours = now.getHours();

setInterval

This can be used to perform a function at a given interval, here, 1000 is equal to 1 second.

setInterval(setDate, 1000);
  • setData - The method to run
  • 1000 - The interval to wait until running the method (again)

style

You can use dot notation to add styles to an element extracted from the DOM.

const secondHand = document.querySelector('.second-hand');

secondHand.style.transform = `rotate(${secondsDegrees}deg)`;

Here, the transform attribute (on the HTML element with the class second-hand) has been given a dynamic value.

transform-origin

This CSS attribute can be used to determine where a given transform 'pivots' from.

transform-origin: 100%;
  • 100% - Moves the pivot from its default position (which is the center of the element i.e 50%) to the end of the x-axis

transition-timing-function

Useful for adding a custom transition effect.

transition-timing-function: cubic-bezier(0, 2.11, 0.58, 1);

You can use chrome dev tools to create your cubic-bezier. More info on this here

Tasks

  • - Fix the transition judder at 0/60 seconds

Back to top


3. CSS Variables

What I learned on this mini-project.

variables

Like with SASS, you can create variables for use throughout your stylesheet.

/* Definition */
--base: #ffc600;

/* Use */
.hl {
    color: var(--base);
}

The prefix -- is necessary.

Note - Remember, that this can be overruled by capitalizing on the cascading property of CSS.

dataset

Can be used to access data attribute values given to HTML elements. These data elements must be prefixed with data-. An example is the following...

<input id="spacing" type="range" name="spacing" min="10" max="200" value="10" data-sizing="px">

You can access this value with the following code...

const suffix = this.dataset.sizing;

Tasks

  • Figure out why the range slider doesn't show when using dev tools

Back to top


4. Array Cardio Day 1

What I learned on this mini-project.

filter

This can be used to assess each item of an array against a condition, and create a new one for those that pass.

const fifteen = inventors.filter(inventor => (inventor.year >= 1500 && inventor.year < 1600));

Here, we used a more concise syntax. If the resulting boolean expression returns true it will 'pass the condition' and be returned in the filtered array.

  • inventor takes the role of the current iterand, much like i in a traditional for (var i = 0; i++; i < arr.length) loop

Array.from

This is useful when you wish to apply array methods to a node list extracted from a website (in this case wikipedia).

const links = Array.from(category.querySelectorAll('a'));

Now, you are able to apply, map, reduce, sort etc... to links.

reduce

This method takes an array and attempts to whittle it down to single value (or values shown in the next exanple).

const totalYears = inventors.reduce((total, inventor) => {
    return total + (inventor.passed - inventor.year);
}, 0)

It's best to think of the parameters total and inventor as an accumulator and iterand. The 0 provides a starting point for the total, since if it were omitted, it would use undefined to add the first iterand to.

reduce (part 2)

Perhaps a more complex use case for reduce is when trying to reduce multiple elements in an array.

The goal was to reduce each element to the number of occurrences in the array.

const transportation = data.reduce((obj, item) => {
    if (!obj[item]) {
        obj[item] = 0;
    }

    obj[item] ++;

    return obj;
}, {});

The key in this case, was to use an empty object as the initial value for the object, and call obj[key] for each iteration.

Back to top


5. Flex Panel Gallery

What I learned on this mini-project.

toggle

You can toggle a class with the following code. This will respond to an event via an event listener. This is commonly used in click events (which is what its used for in this case).

this.classList.toggle('open');
  • this refers to each separate panel when clicked on

event.propertyName

When listening for transitionend, the event might return multiple elements that were affected. Utilizing propertyName you can respond to a element with more specificity.

event.propertyName.includes('flex');
  • includes() - Used here, since IE explorer refers to the flex property as flex-grow

Tasks

Back to top


6. Type Ahead

What I learned on this mini-project.

fetch

In this case, fetch is used to retrieve data from a url which results in a JSON data source.

fetch(endpoint).then(blob => blob.json());

This will return a promise, that can be resolved. The json() method can be used to retrieve the data.

The following code will add the data to an array

fetch(endpoint).then(blob => blob.json()).then(data => cities.push(...data));

Note Use of the ... spread operator to push each data object into the array instead of it entirely (which would push the entire data source at index 0)

RegExp

In order to use a variable as your string to match, you need to create a RegExp object.

const regex = new RegExp(wordToMatch, 'gi');

This can then be used in match() methods, for example

return place.city.match(regex);

Back to top


7. Array Cardio Day 2

What I learned on this mini-project.

Array.prototype.some()

Checks against the array, and returns true if at least one item meets the condition specified.

const isAdult = people.some(person => (new Date()).getFullYear() - person.year >= 19);
  • new Date()).getFullYear() gets the current year

Array.prototype.every()

Checks against the array, and returns true if all items meets the condition specified.

const allAdults = people.every(person => (new Date()).getFullYear() - person.year >= 19);
  • new Date()).getFullYear() gets the current year

Array.prototype.find()

Checks against the array, and returns the result of the item, that meets the criteria (in this case it is an object)

const index = comments.find(comment => comment => comment.id === 823423);

Array.prototype.findIndex()

Checks against the array, and returns the index of the item that meets the condition specified.

const index = comments.findIndex(comment => comment.id === 823423);

Back to top


8. Fun with HTML5 Canvas

What I learned on this mini-project.

getContext

The canvas has properties that can be modified to alter the line style.

const ctx = canvas.getContext('2d');

ctx.strokeStyle = '#BADA55';
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.lineWidth = 10;

Destructuring assignment

ES6 allows you to easily name multiple variables, demonstrated by the the following code

[lastX, lastY] = [event.offsetX, event.offsetY];

Back to top


9. Dev Tools Domination

What I learned on this mini-project.

console

You can use %c to style the text you logged to the console.

console.log('%c This is blue by using percent c', 'color: blue');

You can also, log warning, errors and information to the console much like you would with regular text.

// warning!
console.warn('Warning');

// Error :|
console.error('ERROR!');

// Info
console.info('Crocodiles eat 3-4 people per year!');

If you wish to see an elements properties and methods in a cleaner form, the following code will make this easier

console.dir(p);

You can use use assertions in the console, the following example demonstrates checking to see if an element has a certain class.

const p = document.querySelector('p');
console.assert(p.classList.contains('ouch'), 'That is wrong!');

One useful feature for neatening the output on the console is groupCollapsed Using this along with groupEnd ensures that the data for each list item will be concise and separate.

dogs.forEach(dog => {
    console.groupCollapsed(`${dog.name}`);
    console.log(`This is ${dog.name}`);
    console.log(`${dog.name} is ${dog.age} years old`);
    console.groupEnd(`${dog.name}`);
});

Back to top


10. Hold Shift and Check Checkboxes

What I learned on this mini-project.

let

Using let for variable assignments is useful when you expect the the variable to change.

let lastChecked;

This is different to const which is for variables you wish to remain constant throughout the script.

shiftKey

You can use the shiftKey property of an event to check if its active

event.shiftKey;

In this case, this is used for a click event

checked

To check whether a checkbox has been checked or not, you can assess its checked property (I heard it too...)

checkbox.checked;

Back to top


11. Custom Video Player

What I learned on this mini-project.

You can access the video element and manipulate its behavior via it's properties and methods.

play and pause

To assess whether or not the video is paused, the following property can be checked.

// returns a boolean
video.paused;

To play and pause the video you, can call play and pause methods on the video object, like so

const method = video.paused ? 'play' : 'pause';
video[method]();

currentTime

To move along a video you can change its currentTime property.

video.currentTime += 10;

offsetWidth

In this example, we had to assess how far along the cursor was for a horizontal range element, offsetWidth gives the length of the element, whereas offsetX gives the amount the cursor is along the x axis (of the element).
The code to get the time of the video relative to the scrubbed amount is shown below.

const scrubTime = (event.offsetX / progress.offsetWidth) * video.duration;

timeupdate

This is a useful event that is fired when the video is playing (as in the time that the video has been playing is updated), in this case it was used to fill the progress bar proportionately.

video.addEventListener('timeupdate', handleProgress);

Tasks

  • Complete the fullscreen functionality

Back to top


12. Key Sequence Detection

What I learned on this mini-project.

event.key

When listening for a keyup event, you can access the name of the key being pressed.

event.key;

This will return, for example Shift if the shift key was pressed

splicing an array for the last pressed 'word'

If you are trying to match user input, you may need the last pressed x digits, a cool way of doing this is to add their input to an array and apply a splice followed by join.

let pressed = [];
pressed.push(event.key);
pressed.splice(-secretCode.length - 1, pressed.length - secretCode.length);

The splice in this case

  • Starts at the end of the array
  • Ends when the length of the secretCode has been met

Back to top


13. Slide in on scroll

What I learned on this mini-project.

debounce

When you want to manipulate the DOM on scroll, it's important to limit the number of events that elicit a response.

function debounce(func, wait = 20, immediate = true) {
    var timeout;
    return function() {
        var context = this,
            args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate)
                func.apply(context, args);
            };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow)
            func.apply(context, args);
        };
};

The debounce method will wait 20ms before registering an event, which will reduce browser overhead

window object

The window (and other objects) have plenty of properties associated with scrolling activity that can be viewed and manipulated.

window.scrollY
window.innerHeight
sliderImage.offsetTop

Properties above represent different values updated according to scrolling behavior.

Back to top


14. Javascript Reference vs Copying

What I learned on this mini-project.

strings, numbers and booleans

Javascript will make copies of these types, so changing the values like below is okay

let age = 100;
let age2 = age;

age = 200;

In this case, the age2 variable will keep its original value of 100

array

When dealing with arrays, you need to be aware of the concept of references.

const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
const team = players;

Here, modifying the team array's values will actually modify the players array, for example

team[3] = 'Lux';

console.log(players[3]); // 'Lux'

To leave the original array intact, you must make copies of it. There are multiple ways of doing this, some are shown below

const team2 = players.slice();
const team3 = [].concat(players);
const team4 = [...players];
const team5 = Array.from(players);

objects

The same principle of referencing (from arrays) apply here. To copy an object to another variable, the following code would work

const person = {
    name: 'Wes Bos',
    age: 80
};

const cap2 = Object.assign({}, person, { age: 99 });

The Object.assign() method takes in the following paramters...

  • target - In this case, this is a blank object {}
  • sources - Object(s) to add

Note

  • {age: 99} - This will modify the existing age variable in person

Back to top


15. LocalStorage

What I learned on this mini-project.

preventDefault

This is useful if you want to stop a form submitting, which by default, will redirect you to the form handling page.

event.preventDefault();

template literal ternary operator

A really cool feature implemented in this project, was the use of a ternary operator to dictate whether or not an attribute was given to some HTML.

<input type="checkbox" data-index=${index} id="item${index}" ${plate.done ? 'checked' : ''} />

Here, the ternary operator would either add checked or nothing, dictated by the boolean value returned from plate.done

event.target

When attaching event listeners to elements, you might want to access data from them.

In the case of form elements, with inputs and labels etc, you might not be able to distinguish which was clicked.

Using event.target, you can narrow down to which element is needed.

if (!event.target.matches('input')) return; // skip

This example, will return all elements clicked other than input's'

event delegation

When you wish to attach an event listener to an element that doesn't exist on the page, at the time of loading, event delegation is needed.

It works by attaching the event listener to a parent element (that does exist), which then passes on the instruction (delegates) to the child element being targeted.

itemsList.addEventListener('click', toggleDone);

function toggleDone(event) {
    if (!event.target.matches('input')) return; // skip
    const element = event.target;
    const index = element.dataset.index;
    items[index].done = !items[index].done;
    localStorage.setItem('items', JSON.stringify(items));

    populateList(items, itemsList);
}

itemsList is the parent element, that delegates the instruction to the event.target elements.

localStorage

Browsers, now have the ability to store local data for individual webpages and browsers. The data is stored as a string that can be parsed into javascript objects.

You can set and get items from localStorage.

localStorage.setItem('items', JSON.stringify(items));

Using JSON.stringify() here is necessary, as it allows you to convert the object’s key value pairs to it’s string representation. An example is shown below, which demonstrates utilizing the data and adding it to a variable to use between browser reloads.

This enables your pages to have continuity based on existing user behavior.

const items = JSON.parse(localStorage.getItem('items'));

Here, the 'items' refer to the string interpretation of the object, whilst JSON.parse converts the string back to a javascript object, ready for use.

Back to top


16. Mouse Move Shadow

What I learned on this mini-project.

destructuring objects

This is a neat way of assigning multiple key:value pairs to a single object.

const { offsetWidth: width, offsetHeight: height } = hero;

It can be a little confusing at first. In this case

hero.offsetWidth; // width
hero.offsetHeight; // height

event offset's

When you're looking at coordinates based on an event listener, you have to consider the position of the element being triggered upon.

In this case, the coordinates will change when a new target is hovered over.

Adding the elements offsets from the targeted element can counteract this. An example is shown below

if (this !== event.target) {
    x = x + event.target.offsetLeft;
    y = y + event.target.offsetTop;
}

The event in this case is attached to a div, and the event.target is a child element.

Back to top


17. Sort Without Articles

What I learned on this mini-project.

replace and trim

Replacing words through regular expressions can be done via the replace method.

bandName.replace(/^[a |the |an ]/, '').trim()

In this case, we are targeting a, the or an.

The spaces are used to prevent all words beginning with these sequences of letters being replaced.

Trim removes whitespace from the end of the string.

  • ^ Targets the start of the string
  • | Or operator

ES6 implicit returns

If a function's only task is to return something, then it's best to use implicit returns, which allows you to omit return.

(a, b) => strip(a) > strip(b) ? 1 : -1

This example uses a ternary operator, which is designed to return either 1 or -1.

Back to top


18. Adding Up Times with Reduce

What I learned on this mini-project.

data selector

If you give elements a data element, in the form data-x you can extract them through attribute selection, this is shown below.

const timeNodes = Array.from(document.querySelectorAll('[data-time]'));

Accessing the values for this particular case, can be done via timeNodes.dataset.time

ParseFloat

Numbers are extracted from HTML elements in this project, but they are stored as strings. Using this method you can convert them to the numeric type. This is useful for performing mathematical operations.

const [mins, secs] = timeCode.split(':').map(parseFloat);

In this case, the method has been applied through map.

Back to top


19. Webcam Fun

What I learned on this mini-project.

video

The source of your video is in the form of a URL, that can be generated by the navigator object. This is done by accessing it's property mediaDevices which in turn calls a property getUserMedia.

navigator.mediaDevices.getUserMedia({ video: true, audio: false });

The result of this is a promise that when successful, is used to generate the URL.

video.src = window.URL.createObjectURL(localMediaStream);

pixels

Browsers interpret images as a series of pixels, where each pixels' rgba values that are stored in a large two dimensional array of millions of values.

In these arrays, every pixel has four entries, one for each rgba value. So for example

  • [0, 1, 2, 3] Would mean a red value of 0, green value of 1 etc...

In this case, the pixels are drawn onto the canvas via drawImage which takes in the following parameters

  • video stream
  • starting x coordinate
  • starting y coordinate
  • width
  • height

insertBefore

This method provides the same functionality as prepend from jQuery.

strip.insertBefore(link, strip.firstChild);

Here, strip represents a div element.

Back to top


20. Speech Detection

What I learned on this mini-project.

SpeechRecognition()

This is a window object that lets you use your microphone to implement speech recognition functionality

window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;

const recognition = new SpeechRecognition();

In chrome, you need to prepend SpeechRecognition with webkit.

end

This is the event that can be listened for when the microphone receives input.

recognition.addEventListener('end', recognition.start);

The result of this, is a SpeechRecognitionResultList object which has many properties, one of which is the transcript containing the words that were interpreted.

Another property from this object, that was used here is isFinal, which attempts to detect the ending of the speech.

Back to top


21. Geolocation

What I learned on this mini-project.

geolocation

This is a property of the window object, that contains data about the users location. You must grant access for it to work.

navigator.geolocation.watchPosition(data => {
    console.log(data);

    speed.textContent = data.coords.speed;
    arrow.style.transform = `rotate(${data.coords.heading}deg)`;
    }, (error) => {
    console.error(error);
    alert('ENABLE GEOLOCATION!!!');
});

The geolocation object is only introduced very briefly.

watchPosition

This method, allows you to update the users position at regular intervals, instead of getting a snapshot of where they are.

The data returned then needs to be manipulated via a promise, that handles success and failure outcomes.

coords

Most of the data that you will need is contained in this object. Examples of this include the latitude, longitude and heading (representing degrees from north).

Back to top


22. Follow Along Link Highlighter

What I learned on this mini-project.

getBoundingClientRect()

Used to return an elements size and position relative to the window.

const linkCoords = this.getBoundingClientRect();

const coords = {
    width: linkCoords.width,
    height: linkCoords.height,
    top: linkCoords.top + window.scrollY,
    left: linkCoords.left + window.scrollX,
}

It returns an object, which represents the CSS borders associated with the element. The values returned are read-only and can not be updated these include left, top, x and y.

Values represent the border-box in pixels and are relative to the top-left of the viewport (this doesn't apply to width and height values).

scrollX and scrollY

When the scrolling position changes, the values returned above will adjust to be bound to the current top-left of the viewport. So, to make sure the values are bound to the top-left of the document, you need to add scrollX and scrollY, shown below.

let top = linkCoords.top + window.scrollY;
let left = linkCoords.left + window.scrollX;

Back to top


23. Speech Synthesis

What I learned on this mini-project.

speechSynthesisUtterance

This is an interface for the Web Speech API. It contains the content that the speech service will read, as well as options that can be configured, such as language and pitch.

const msg = new SpeechSynthesisUtterance();

// Example properties used
msg.lang;
msg.pitch;
msg.rate;
msg.text;
  • voiceschanged - This event listener can be used to attach an event to add voices to use.
  • getVoices() - Will extract the voices on the device being used as an array

SpeechSynthesis

This is the controller interface for the speech service, which can be used to get information about the voices available, on your particular device. It can also be used to start and pause the speech.

speechSynthesis.paused;
speechSynthesis.pending;
speechSynthesis.speaking;

speechSynthesis.cancel();
speechSynthesis.pause();
speechSynthesis.speak();

Above, are example properties and methods that can be used to alter the state of the speech device.

Anonymous function

At times you might want to provide a parameter to a function for use in an event listener. Unfortunately, doing this by a traditional function call will result in it being run on page load.

Using an anonymous function, you can avoid this problem

stopButton.addEventListener('click', () => toggle(false));

One caveat to this is that a new function will be created. Relying on this approach can cause unnecessary overhead to your code, which could have negative implications on your websites speed and efficiency.

Back to top


24. Sticky Nav

What I learned on this mini-project.

position: fixed

The main purpose of this project was to learn about the effects of changing an elements position to fixed.

When applying this property, the element is essentially taken out of the DOM which vacates the space it previously held in it.

This causes a reshuffle for the other elements, which can cause a judder when an elements position is changed to fixed.

.fixed-nav nav {
    position: fixed;
    box-shadow: 0 5px rgba(0, 0, 0, .1);
}

One workaround to this, is to fill in the space vacated by adding padding. This can be done multiple ways, but it makes sense to make this value dynamic, so that it adapts when the layout of the page is changed.

document.body.style.paddingTop = `${nav.offsetHeight}px`;

Back to top


25. Event Capture, Propagation, Bubbling and Once

What I learned on this mini-project.

capture

When an event listener has been attached to an element, that has parents with the same listener, triggering the event will lead to all elements registering.

By default the events will be triggered from the inside out, but setting capture to true will reverse this direction to outside in.

divs.forEach(div => div.addEventListener('click', logText, {
    capture: false
}));

once

This is a useful option for the addEventListener method, that will prevent the element from triggering multiple events. It has the same functionality as removeEventListener.

divs.forEach(div => div.addEventListener('click', logText, {
    once: true
}));

Event Propagation

This is the blanket term that refers to bubbling and capturing. It essentially means that events will cascade up and down the document object model from the event target to the window object.

The direction of propagation can be both ways.

A nice summary of the concept is explained by dividing it into three phases.

This was taken from the following article.

  • capture phase - From the window to the event target
  • target phase - The event target
  • bubble phase - From the event target back to the window

Back to top


26. Stripe Follow Along Nav

What I learned on this mini-project.

CSS > selector

This is used when you wish to match direct descendent elements.

const triggers = document.querySelectorAll('.cool > li');

So, in this case the first li tag, of elements with a class of cool will be selected.

Using multiple classes for progressive effects

In this project, an element needs to be displayed and faded in. To begin with, the element is given the following CSS... display: none, an unfortunate consequence of this, is that transitions can't be applied elements that aren't displayed.

By using multiple classes and adding CSS sequentially, you can first add the element to the page through a class with display: block, then add a second class with the desired transformation properties.

The following code demonstrates this.

this.classList.add('trigger-enter');
setTimeout(() => this.classList.contains('trigger-enter') && this.classList.add('trigger-enter-active'), 150);

Note, a delay of 150ms has been added before adding the second class, this is to maintain the order in which the classes are added.

getBoundingClientRect modification

This object, will by default, give positional values based on the current viewport's top-left point (which corresponds to (0, 0)).

On occasion however, you might want the element you are targeting to be based on another element.

To do this, you must get that element's positional values via getBoundingClientRect and subtract these from the target element's positional values.

An example is shown below, where the dropdown is positioned based on the 'nav'.

const navCoords = nav.getBoundingClientRect();
const dropdownCoords = dropdown.getBoundingClientRect();

const coords = {
    height: dropdownCoords.height,
    width: dropdownCoords.width,
    top: dropdownCoords.top - navCoords.top,
    left: dropdownCoords.left - navCoords.left
};

Back to top


27. Click and Drag

What I learned on this mini-project.

Flag variable

These can be used to control the flow of a method or other piece of functionality.

They are mainly used to hold a value until some condition changes, after which you can modify the variable. One of the most common use cases for this is holding a boolean which is dependent on some other piece of code.

let isDown = false;

isDown = true;

In this example, the isDown variable is used to track the state of the mouse. When the mousedown event is triggered the isDown variable is changed, which is used to add further functionality.

pageX and offsetLeft

In this project, the mousedown event is used to initiate the click and drag functionality. For this to work effectively, an anchor point was used, representing the initial click point, the pageX property of the event captures this value.

event.pageX

If a margin or padding is added, then the pageX value will be off, to compensate for this adjustment, you can subtract the pixels changed (from the parent element's offset) to the window.

The code to do this, is shown below

startX = event.pageX - slider.offsetLeft;

Back to top


28. Video Speed Controller

What I learned on this mini-project.

offsetHeight

This property represents the height of an element, including vertical padding and borders. It is measured in pixels and is returned as an integer.

const percent = y / this.offsetHeight;

In this case, offsetHeight was used in the percentage calculation used to fill the speed-bar.

Normalize value

It made sense for the speed-bar to have appropriate minimum and maximum values, to achieve this, normalization was used, allowing us to map the percentage scrolled, to these minimum and maximum values.

const playBackRate = (percent / (max - min)) + min;

In this case, minimum = 0.4 and maximum = 4. So, the percentage scrolled would fall between the two. For example 10% is approximately equal to a playBackRate of 0.43.

Back to top


29. Countdown Timer

What I learned on this mini-project.

setInterval() and clearInterval()

The setInterval method has been used in previous projects, but in this case it's used a little differently, in conjunction with clearInterval.

When you wish for a function or code piece of code to run every so often, setInterval can be used.

countdown = setInterval(() => {
    // method
    const secondsLeft = Math.round((then - Date.now()) / 1000);
    }, 1000); // time delay

Here, an anonymous function which defines a constant is ran every 1000 milliseconds.

In order to clear the countdown variable i.e stop the method running via setInterval you need to clear it. If you don't do this, and try to run the method whilst it's already running (through another function call), they will both run, which can cause erratic behavior.

clearInterval(countdown);

Here, the method being executed under a given time interval is assigned to countdown, so clearing the variable does the job of cancelling the method calls.

Working with timestamps

If you want the current time, then Date.now() can be used, this will return the number of milliseconds elapsed since 01/01/1970.

It's easy to turn this into a date object via new Date(milliseconds), where the value extracted from Date.now() is used as a parameter.

Using this object, various methods can be called, to extract different aspects of the time data such as the day, month and year.

const timestamp = Date.now();
const end = new Date(timestamp);
const hour = end.getHours();
const minutes = end.getMinutes();

Form element selectors

When you want to attach an event to a form, you can utilize this to extract it's input values.

document.customForm.addEventListener('submit', function (event) {
    const mins = this.minutes.value;
});

Here, an event listener is attached to the form via its name attribute customForm, and its inputs are extracted by accessing properties off this.

Back to top


30. Whack A Mole

What I learned on this mini-project.

isTrusted

Here, the click event is important in determining the outcome of the game, therefore we need to protect from false clicks that can be be mimicked through cheeky javascript code.

Using the isTrusted property allows you to confirm that the event was generated by a user action.

if (!event.isTrusted) return; // cheater

The code above, will return if the event was not a product of user action (not through a script).

Recursion

This technique was used to prevent the same hole from being used twice in a row. It's important to return the value in the randomHole method, so that it can be used recursively.

let lastHole;

function randomHole(holes) {
    const idx = Math.floor(Math.random() * holes.length);
    const hole = holes[idx];

    if (lastHole === hole) {
        return randomHole(holes);
    }

    lastHole = hole;
    return hole;
}

Here, the lastHole variable will be assigned to the randomly generated hole. If the following call generates the same hole, the randomHole will be called again until lastHole != hole.

Final Remark

This course does a really good job, of providing real world examples of javascript. This will definitely help you to retain information better than simply reading.

I highly recommend the course, so take it, if you have the time!