diff --git a/README.md b/README.md index 041293f..4630ab2 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,15 @@ # Modular JS -## Basics +## Events + +[basics](events/basics.md) +[bubbling](events/bubbling.md) +[input events](events/input.md) + +## Modular JS -[Events](events) -[Hoisting](hoisting) [JavaScript Module Patterns](modules) +[Hoisting](hoisting) [Webpack](webpack) ## AJAX diff --git a/events/README.md b/events/README.md deleted file mode 100644 index bc19945..0000000 --- a/events/README.md +++ /dev/null @@ -1 +0,0 @@ -includes Event Bubbling and Custom Events diff --git a/events/basics.md b/events/basics.md new file mode 100644 index 0000000..050c632 --- /dev/null +++ b/events/basics.md @@ -0,0 +1,254 @@ +# DOM EVENTS + +## LESSON OBJECTIVES + +1. Describe what a browser event is +1. Create a click event +1. Use a named, referenced function as the click handler for the listener +1. Create a custom event + +## Describe what a browser event is + +Interacting with the page (`events_example`) + +Every kind of interactivity in the browser is an event: clicks, mouseovers, key presses, scrolling, resizing, loading the page, and more. + +When you interact with the browser it checks to see if there is a _listener_ for that interaction. + +If there is a _listener_ present, the browser will try to run any _handlers_ for those interactions. + +A _handler_ is just a function that runs a desired procedure. + +## Create a click event + +How can we set up a _click_ event? + +We need: + +1. An element to set it on +2. A _listener_ that listens for the event: on _which element_ should the event take place +3. A _handler_ that runs the procedure we want to have happen when the event is triggered + +Make a button in the html: + +```html + +``` + +```javascript +const $btn = $('#btn'); + +$btn.on('click', () => { + const $p = $('

').text("THE EARTH IS ROUND"); + $('body').append($p); +}); +``` + +### Named Function + +We can abstract the anonymous function out and give it a name: + +Separate function, not inside the listener: + +```javascript +const addText = () => { + const $p = $('

').text("THE EARTH IS AN OBLATE SPHEROID"); + $('body').append($p); +} +``` + +We can then reference it in the event Listener: + +```javascript +$btn.on('click', addText); +``` + +With a named function, we can use the same handler for more than one DOM element. + +### Referenced Function + +Note that we do not invoke the function with parentheses. We do not want to invoke the function right away, we merely want to _reference_ it to be invoked when the listener runs it. + +* The function should be defined before it is used in the event listener +* When the function is invoked inside the event listener **leave out the parentheses**. We do not want to invoke the function right away! We merely want to reference that function in the listener. + +Here the function is invoked and will run immediately: + +```javascript +$btn.on('click', addText()); +``` + +We don't want this! We only want the function to run when the user has clicked on the button. + +Complete code: + +```javascript +const $btn = $('#btn'); + +const addText = () => { + const $p = ('

').text("THE EARTH IS AN OBLATE SPHEROID"); + $('body').append($p); +} + +$btn.on('click', addText); +``` + +Let's do something fancier, and toggle the background-color of the page using `.toggleClass()` + +```javascript +const changeClass = () => { + $('body').toggleClass('black'); +} + +$('#btn').on('click', changeClass); +``` + +CSS: + +```css +.black { + background-color: black; +} +``` + +### Activity (15 min) + +* Separate an anonymous handler function from one of your event listeners, and make it a named function instead. +* Make it so that the named handler will run when the button is clicked. (Remember to make sure the function is _referenced_ and not _invoked_ when you set it on the listener). +* Make it so that the click will work only after the user has clicked. + +**Extra Activity** + +Make it so each time click the button, that background-color of the page will toggle. + +**Extra Activity** + +* Add yet another button, and make it so that when this extra button is clicked, it will run the exact same handler as your previous button. + +**Extra Activity** + +* Make it so that when you click either of these buttons, an image will toggle on and off the page. There is no toggleImage method so you'll have to do it programmatically. Click once = message appears. Click again = message disappears. Click again = message reappears, etc. _Hint:_, you can use a global variable boolean and toggle it upon click. + +### Ask (5 min) + +* What is the difference between a named vs anonymous function? +* What is the difference between an invoked vs a referenced function? +* What is the difference between an event listener and an event handler? +* When would you want to use a named function over an anonymous one? + +### EXTRA: mouseenter and mouseleave + +There is a special jQuery method for hover. We can replicate it using `.on()` by making an event for `mouseenter` and a separate event for `mouseleave` + +```javascript + $('#some-div').on('mouseenter', function() { + $('body').css('background-color', 'red'); + }); + + $('#some-div').on('mouseleave', function() { + $('body').css('background-color', 'white'); + }); +``` + +* How would we re-arrange this to make our anonymous functions named functions? + +## Create a custom event + +You can even create your own custom events + +```javascript +$( "#foo" ).on( "custom", function( event, param1, param2 ) { + alert( param1 + "\n" + param2 ); +}); +$( "#foo").trigger( "custom", [ "Custom", "Event" ] ); +``` diff --git a/events/bubbling.md b/events/bubbling.md new file mode 100644 index 0000000..55dda8c --- /dev/null +++ b/events/bubbling.md @@ -0,0 +1,238 @@ +# EVENT BUBBLING + +## Lesson Objectives + +1. Describe event bubbling +1. Prove that event bubbling occurs +1. Access the event parameter +1. Differentiate between an event's `target` and `currentTarget` +1. Stop event propagation +1. Have an event handler return false + +## Describe event bubbling + +When elements are nested within the DOM, the DOM needs a way to decide which elements ought to trigger an event. + +![](https://i.imgur.com/ZwtfS98.png) + +If a click event listener is set on the outer element, the green box, will a click on the inner element, the pink box, also trigger the event? + +Does the pink box somehow 'block' the event? Does the "click me" text block it? + +What _belongs_ to the green box? + +```javascript + $('.outside').on('click', () => { + console.log('OUTSIDE is clicked'); + }); +``` + +![](https://i.imgur.com/HuTEZIn.png) + +Nothing within the green box blocks the event. Everything belongs to the green box. No matter where inside the green box you click, you'll get the console log. + +### Bubbles + +When you click on the pink box, this is the lowest level of your mouse location, the `target` of the event. JS checks to see if there is an event listener on this element. + +Then, the event bubbles up to the parent, the green box, and checks to see if there is a listener there. + +But, it doesn't stop there! + +The event bubbles up through all parents to the body, and checks that too! + +The event finally stops bubbling at the `document`. + +## Prove that event bubbling occurs + +So, if we set a listener on the pink element, the question is, will that also trigger the listener on the green one? Will it "bubble" up? + +```javascript + $('.outside').on('click', () => { + console.log('OUTSIDE is clicked'); + }); + + $('.inside').on('click', () => { + console.log('INSIDE is clicked'); + }); +``` + +Clicking on the innermost element: + +![](https://i.imgur.com/y1wUz8c.png) + + +### Test bubbling: Set listener on body + +```javascript + $('.outside').on('click', () => { + console.log('OUTSIDE is clicked'); + }); + + $('.inside').on('click', () => { + console.log('INSIDE is clicked'); + }); + + $('body').on('click', () => { + console.log('BODY is clicked'); + }); +``` + +Clicking on the innermost element: + +![](https://i.imgur.com/yNHoVTJ.png) + +## Access the event parameter + +```javascript + $('.inside').on('click', (event) => { + console.log('INSIDE is clicked'); + }); +``` + +When the `.on` method (or any JS event listener method) runs the callback function, it supplies the callback with an argument: an object that represents the event. + +When can use this param in our callback. Call it what you like: you will see `e`, `ev`, `event`, etc. + +## Differentiate between an event's `target` and `currentTarget` + +On the `event` object, you can see the innermost thing that was clicked with `event.target`, and the thing that has the event listener with `event.currentTarget`. + +**Comment out the inside and body event listeners** + +On the outside event listener: + +```javascript + $('.outside').on('click', (event) => { + console.log('OUTSIDE target is: ', event.target); + console.log('OUTSIDE currentTarget is: ', event.currentTarget); + }); +``` + +If you click the green box (the outside element): + +![](https://i.imgur.com/MjYtPJj.png) + +`target` and `currentTarget` are the same. + +If you click the pink element (the inner element), we expect the event to bubble to the outside and trigger the event listener: + +![](https://i.imgur.com/QU8aryL.png) + +`target` is the innermost element that was clicked: the **inside** pink one. + +`currentTarget` is the element on which the event listener is set: the **outside** green one. + +### Consider this + +```javascript + $('.outside').on('click', (event) => { + console.log('OUTSIDE target is: ', event.target); + console.log('OUTSIDE currentTarget is: ', event.currentTarget); + }); + + $('.inside').on('click', (event) => { + console.log('INSIDE target is: ', event.target); + console.log('INSIDE currentTarget is: ', event.currentTarget); + }); + + $('body').on('click', (event) => { + console.log('BODY target is: ', event.target); + console.log('Body currentTarget is: ', event.currentTarget); + }); +``` + +If you click on the body, which listeners will be triggered? what will be the value of `target` for each listener? and what will be the value of `currentTarget` for each listener? + +If you click on the outside box, which listeners will be triggered, what will be the value of `target` for each listener? and what will be the value of `currentTarget` for each listener? + +If you click on the inner box, which listeners will be triggered? what will be the value of `target` for each listener? and what will be the value of `currentTarget` for each listener? + + +## Stop event propagation + +If you want to isolate an element and prevent bubbling, use + +* `event.stopPropagation()` + +```javascript + $('.inside').on('click', (event) => { + console.log('INSIDE target is: ', event.target); + console.log('INSIDE currentTarget is: ', event.currentTarget); + event.stopPropagation(); + }); +``` + +Clicking on the inside element no longer triggers the outer event listeners: + +![](https://i.imgur.com/NvYnaQI.png) + +Clicking on the outer event listener still triggers bubbling as expected: + +![](https://i.imgur.com/2AMW1gK.png) + + +## Have an event handler return false + +When using jQuery, you can use `return false` within your event handlers to stop all of the default behavior associated with events, such as bubbling. + +* `event.stopPropagation()` to stop bubbling +* `event.preventDefault()` to stop forms from refreshing the page + +```javascript + $('.outside').on('click', (event) => { + console.log('OUTSIDE target is: ', event.target); + console.log('OUTSIDE currentTarget is: ', event.currentTarget); + return false; + }); + + $('.inside').on('click', (event) => { + console.log('INSIDE target is: ', event.target); + console.log('INSIDE currentTarget is: ', event.currentTarget); + return false; + }); + + $('body').on('click', (event) => { + console.log('BODY target is: ', event.target); + console.log('Body currentTarget is: ', event.currentTarget); + return false; + }); +``` + +## Element targeting with jQuery + +Let's say I make a few copies of the squares: + +```html +

+

Click me ... ?

+
+
+ +
+

Click me ... ?

+
+
+ +
+

Click me ... ?

+
+
+``` + + ![](https://i.imgur.com/TBfw31S.png) + + +By wrapping `event.currentTarget` in jQuery I can use jQuery methods on the target, and only affect the elements I clicked (not the others) + +```javascript +$(event.currentTarget).css('background-color', 'black'); +``` + +```javascript + $('.outside').on('click', (event) => { + $(event.currentTarget).css('background-color', 'black'); + }); +``` + +![](https://i.imgur.com/XilWxHt.png) diff --git a/events/input.md b/events/input.md new file mode 100644 index 0000000..b929c50 --- /dev/null +++ b/events/input.md @@ -0,0 +1,179 @@ +# DOM Input + +### LESSON OBJECTIVES +_after this lesson, students will be able to:_ + +1. Capture text input from the browser +1. Use a form's submit event +1. Build a list from input + +## Capture text input from the browser + +Provide a means for the user to provide input, and capture that input with an event handler. + +Make an input field and a button in index.html + +```javascript + + +``` + +Set an event on the submit + +```javascript +$('#submit-btn').on('click', () => { + console.log('clicked'); +}); +``` + +Make it so the handler grabs the value inside the input box (and logs it to check) + +Use jQuery `.val()` + +```javascript +$('#input-box').val() +``` + +```javascript + $('#submit-btn').on('click', () => { + console.log('clicked'); + console.log( $('#input-box').val() ); + }); +``` + +### You Do + +* Make an input box and a button. The input should ask for the user's favorite TV show +* When you click the button, make it so that a message appears on the page: "Hi! Your favorite show is: _show name from input_" + +**Extra** + +* Instead of a TV show name, ask the user to input the url for an image that they like +* When the user clicks the submit button, add an `img` to the page and set the `src` attribute to the input value. Get the image to show on the page. + +## Use a form's submit event + +With a **form** tag you can hit the enter key to submit the form data. + +```javascript +
+ + SUBMIT +
+``` + +app.js + +Set the handler on the form element instead of the submit. + +```javascript + $('form').on('submit', () => { + console.log('clicked'); + console.log( $('#input-box').val() ); + }); +``` + +### Prevent default refresh + +When you submit the form, the default action is to refresh the page. Let's prevent this default behavior using the freebie `event`. + +```javascript + $('form').on('submit', (event) => { + console.log('clicked'); + console.log( $('#input-box').val() ); + event.preventDefault(); + }); +``` + +### Reset your input field + +`.trigger()` can trigger events on elements (click, hover, etc). The `reset` event clears a text input + +```javascript +$(elem).trigger('reset'); +``` + +```javascript + $('form').on('submit', (event) => { + console.log('clicked'); + console.log( $('#input-box').val() ); + event.preventDefault(); + $(event.currentTarget).trigger('reset'); + }); +``` + +## Build a list from input + +Make a nonsense list to store any kind of nonsense + +* Make a `list` array where nonsense data will be stored +* Push input into the list +* Run a function **render** that will render items in the list. + +```javascript +const list = []; + +$('form').on('submit', (event) => { + console.log('clicked'); + console.log( $('#input-box').val() ); + + list.push( $('#input-box').val() ); + + event.preventDefault(); + $(event.currentTarget).trigger('reset'); + + render(); +}); +``` + +* Make **render** function to iterate over all items in the list + +```javascript +const render = () => { + console.log('render everything in the list'); + console.log('list: ', list); + list.forEach((item) => { + + console.log(item); + + }); +} +``` + +* Let's build in some `ul`s for the list items + + ```html + + ``` + +* Make a list item for every item in the array + +```javascript +const render = () => { + console.log('render everything in the list'); + console.log('list: ', list); + $('ul').empty(); + list.forEach((item) => { + $('ul').append('
  • ' + item + '
  • '); + }); +} +``` + +![](https://i.imgur.com/vjQ2Bu9.png) + +* Add an event listener to each item that calls on one single event handler + +```javascript +list.forEach((item) => { + const $li = $('
  • ' + item + '
  • '); + $li.on('click', doNonsense); + $('ul').append($li); +}); +``` + +```javascript +const doNonsense = (event) => { + console.log('item clicked: ', event.currentTarget); + $(event.currentTarget).css('background-color', 'red'); +} +``` diff --git a/jquery/README.md b/jquery/README.md deleted file mode 100644 index e69de29..0000000