diff --git a/2-dynamic-rendering/0-introduction.md b/2-dynamic-rendering/0-introduction.md index be59e26..bba72b3 100644 --- a/2-dynamic-rendering/0-introduction.md +++ b/2-dynamic-rendering/0-introduction.md @@ -16,5 +16,5 @@ Upon completion of this module you will understand the following: - Knowledge of JavaScript - Familiarity with Vue.js and directives - [Git](https://git-scm.com/) -- A code editor, such as [Visual Studio Code](https://code.visualstudio.com) +- [Visual Studio Code](https://code.visualstudio.com) - [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) extension diff --git a/3-data-events/0-introduction.md b/3-data-events/0-introduction.md index 7443c30..73ddd09 100644 --- a/3-data-events/0-introduction.md +++ b/3-data-events/0-introduction.md @@ -1,4 +1,16 @@ -- event handlers -- updating state -- forms -- computed properties?? \ No newline at end of file +Users typically modify data in a web application through a form. Since Vue.js is about working with dynamic data, it has a robust mechanism for binding data to forms. We can also manage events, performing different operations when a user clicks on a button or otherwise interacts with the page. And we even have the ability to add in values which are computed dynamically, allowing us to minimize the amount repeated code. + +In this module you will learn how to: + +- bind model data to a form +- add event handlers +- create computed values + +Prerequisites + +- Knowledge of HTML and CSS +- Knowledge of JavaScript +- Familiarity with Vue.js and directives +- [Git](https://git-scm.com/) +- [Visual Studio Code](https://code.visualstudio.com) + - [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) extension diff --git a/3-data-events/0-overview.md b/3-data-events/0-overview.md deleted file mode 100644 index 183cf84..0000000 --- a/3-data-events/0-overview.md +++ /dev/null @@ -1,16 +0,0 @@ -In this lesson we demonstrate how to work with data in Vue. We'll cover capture event handlers (such as clicking a button or hovering their mouse over an object on a webpage), working with properties and using a special Vue affordance called v-bind to build dynamic forms. - -## Learning Objectives - -Upon completion of this module you will: - -- Use an expression to calculate a value -- Set up a listener for an event -- Trigger application logic when the event occurs by: - - Changing inline data properties for implementing simple logic - - Creating a method that can be used to implement more complex logic - -If you completed the prior exercises, your HTML file should look like the image below when viewed in a browser. You can continue to build upon your own files, or you can use the the files in our [starting code](link). - -![Screenshot showing the HTML page with a selected produce image on the left and 4 thumbnail images below it. Product name and description are displayed on the right, with two paragraphs of text. Below this are unordered lists for Passenger Rates and Group Discounts](../media/m05-start.png) -- Change the selected product image when a thumbnail image is clicked diff --git a/3-data-events/1-updating-state.md b/3-data-events/1-updating-state.md deleted file mode 100644 index e69de29..0000000 diff --git a/3-data-events/2-forms.md b/3-data-events/2-forms.md new file mode 100644 index 0000000..dd7d25b --- /dev/null +++ b/3-data-events/2-forms.md @@ -0,0 +1,70 @@ +The data returned by the `data()` function in a Vue app or component is generically referred to as state. State is any information your application needs to track to perform the necessary operations. Users typically modify state through HTML forms. Vue.js allows us to bind data to a form, allowing users to update state. + +## v-model + +The `v-model` directive creates a *two-way* binding between an HTML control and the associated data. This means whenever the value is updated in the form it is updated inside your application's state. `v-model` supports binding to any form control, including checkboxes, textboxes and dropdown lists. + +> ![NOTE] +> `v-bind` creates a one-way binding, meaning any changes the user might make in the form would not be stored in state. + +For all of our examples below, we will use the following Vue application: + +```javascript +Vue.createApp({ + data() { + return { + name: 'Cheryl', + status: -1, + active: true, + benefitsSelected: 'yes', + statusList: [ + 'full-time', + 'part-time', + 'contractor' + ] + } + } +}) +``` + +## Binding to textboxes + +To bind to a textbox, you use the `v-model` directive. + +```html + +``` + +The `name` property will be updated whenever the textbox value changes. If you wish to use a `textarea` instead, the syntax is the same; you use `v-bind="name"` just as before. + +## Binding to checkboxes + +Typically Boolean values are bound to checkboxes, as they allow for the option to be toggled. To bind the `active` option we can use `v-model` as we've done before: + +```html + Is active +``` + +However, there may be times when the toggle isn't a Boolean value, but maybe two choices such as *yes*/*no*. In this case, we can use `true-value` and `false-value` to indicate the associated value for the checkbox being checked (true) or unchecked (false). + +```html + Benefits selected: {{ benefitsSelected }} +``` + +## Dropdown lists + +Dropdown lists are created in HTML by using `select` to create the list, and `option` to add options. The `select` tag stores the selected value of the dropdown list, so we will use it to bind to our model. To create the list of `option`s, we will use `v-for` to loop through the array. + +Let's say we want to create a dropdown list for the `statusIndex` in our model. We bind the model to the select tag by using `v-model`. + +We create the list of options by using `v-for`, which loops through a list of items. Because we want to set the value to be the index of the item in the array rather than the value, we use `v-for(status, index) in statusList`, which will provide the index for each item. We then set the `:value` of each option to the `index`, and display `status` as the option for the user. + +```html + diff --git a/3-data-events/3-exercise-forms.md b/3-data-events/3-exercise-forms.md new file mode 100644 index 0000000..a3b8b6c --- /dev/null +++ b/3-data-events/3-exercise-forms.md @@ -0,0 +1,88 @@ +Let's update a fictitious application for allowing people to book cruises into space. We will add a form to allow someone to book a trip to the moon. + +## Exploring the starter code + +The starter application already contains the core data model we will use. The `product` has information about the cruise itself, including the list of available `cabins`. The `booking` object is what we will use to store the options the user selects for their reservation. You can see the setup inside **index.js**. + +## Create the form + +Let's create the form the user will use to setup their reservation. + +1. Inside Visual Studio Code, open *index.html* +1. Below the comment which reads `TODO: Add booking form`, add the following HTML + + ```html + +
+

Book now!

+
+ + +
+
+ + +
+
+ + + +
+
+ ``` + +## Breaking down the code + +Let's walk through HTML code you added to the page. + +### form element + +```html +
+``` + +The `form` element is a normal HTML form element. The key attribute we have added is `v-show`, which allows you to toggle the display of an item in Vue.js. If `booking.completed` is false we will display the form (making note of the `!` at the beginning of our string), otherwise we will hide it. + +### select element for cabin + +```html + +``` + +We display the list of available cabins by using a `select` element. We want to bind the selected value, which will be the index, to `booking.cabinIndex`. The list of available cabins is in `product.cabins`, so we use `v-for` to create the list of options for the dropdown. We set the `value` of each one to the `index`, and create a display of the `name` of the cabin and its `price`. + +### textarea for notes + +```html + +``` + + We bind the `booking.notes` option to a `textarea`. We set the size by setting the `rows` attribute to *3*. + + ### The todo comment + + You will notice we added a `TODO` comment for ourselves to add in a button. We will see how to create event handlers a little later in this module. We want to make sure we know where to place it when the time comes. + + > ![NOTE] + > `TODO` comments are a great way to make notes in your code of tasks you need to complete in the future. + + ## Test the results + + Let's see our updated page! + + 1. Save all files by clicking *File* > *Save all* + 1. Ensure *Live Server* is running by pressing *Ctl-Shift-P* (or *Cmd-Shift-P* on a Mac), typing *Live Server* in the command pallet, and selecting *Live Server: Open with Live Server* + 1. Open your browser and navigate to **http://localhost:5500** + 1. The page now displays + + ![Screenshot of the newly created form](media/form-created.png) + +You have now bound Vue data to a form. diff --git a/3-data-events/3-forms-and-v-bind.md b/3-data-events/3-forms-and-v-bind.md deleted file mode 100644 index 9ec2fd8..0000000 --- a/3-data-events/3-forms-and-v-bind.md +++ /dev/null @@ -1,324 +0,0 @@ -## Forms - -Your HTML interface should look similar to the one shown in the screenshot below. In this section we will add a form to the "Food Preferences" component that is located at the bottom left side of the screen. - -![Screenshot showing the HTML page with a selected product image on the left and 4 thumbnail images below it. The first thumbnail from the left is highlighted with a yellow background. Product name and description are displayed on the right. Two components are located at the bottom left of the screen: "Food Preferences" and "Welcome Back to the Galaxy!"](../media/m09_start.png) -- The "Room Service Fee" in the Food Preferences panel reads **No charge** if the passenger has booked a cruise at the rate for "First class with sleeping berth" (i.e., when `berth` property is `true`). - - It will read **$24.99** when the `berth` property is `false`. -- If the passenger has previously booked a cruitse with Relecloud Galaxy Tours (i.e., `previous` is `true`), the message in the second box will invite the user to fill out a cruise review form that will be added in this training module. - - When `previous` is `false` the second box will instead inform users that "Comments are Welcome!" - -## Create form and data properties - -In this section you will create a `` tag in the **FoodPrefsForm.js** file, which is located under the **components** folder. To bind the form elements to your data, you will also enter `data()` properties in the same file for the data that will be generated when the form is submitted. - -- Add the `` element content in the **FoodPrefsForm.js** file below the comment that reads `/* TODO: Add element below last

tag */`. - - The `` element will go below the paragraph that reads "Please fill out this form to let us know your food preferences." -- Add new `data()` properties for the form data that will be generated so we can bind these form elements to the data in our Vue application. The `data()` option should be entered below the comment that reads `/* TODO: Add form data properties and methods */`. - - Note that the name of each data property must match the name of the `id` for each input field on the form. - -```javascript -... - template: - /* TODO: Add element below last

tag */ - /*html*/ - `

-

Food Preferences

-

Room Service Fee{{ roomService }}

-

Please fill out this form to let us know your food preferences.

- - -

Submit food preferences

- - - -
- - - -
- - - - - - -

- - - -
- - - -
`, -/* TODO: Add form data properties and methods */ - data() { - return { - passenger: '', - allergies: '', - allergydesc: '', - glutenfree: '', - vegan: '', - } - }, -... -``` - -## Use v-model to create two-way binding from template to data - -Now we need to create a two-way binding between our template and the data in the form we just created. On each form element we add the `v-model` directive, using the same `id` as the element in our `v-model` directive. For example, the tag `` becomes ``. - -- Add the `v-model` directive to each form element below the comment that reads `/* TODO: Add
element below last

tag */`. -- The code in the `template` section of **FoodPrefsForm.js** should now look like the code snippet shown here. - -```javascript -... - template: - /* TODO: Add element below last

tag */ - /*html*/ - `

-

Food Preferences

-

Room Service Fee{{ roomService }}

-

Please fill out this form to let us know your food preferences.

- - -

Submit food preferences

- - - -
- - - -
- - - - - - -

- - - -
- - - -
`, -... -``` - -## Add a listener to the form to execute an event - -We need to add a `listener` to the `
` tag in **FoodPrefsForm.js** so that when the user clicks the `Submit` button the form will capture the event and execute a method. We will use `@submit.prevent="onSubmit"` for the listener and place it in the opening `` tag. The **prevent** modifier keeps the browser from refreshing the page so that the user experience remains seemless. - -- Add a listener to the opening `` tag below the comment that reads `/* TODO: Add element below last

tag */`. -- Add a trigger to the listener so it will execute a method named `onSubmit`. - -```javascript -... - template: - /* TODO: Add element below last

tag */ - /*html*/ - `

-

Food Preferences

-

Room Service Fee{{ roomService }}

-

Please fill out this form to let us know your food preferences.

- - -... -``` - -## Emit the event - -Now we need to create the method `onSubmit` to define actions that will be performed when the event occurs, but we have a new problem to address. You already know how to use a `prop` in a `component` to pull down data that is available in the application template for use in your component. We can think of the template as the "parent" component. Now we need to push data "up" from the child component, in this case **FoodPrefsForm.js**, to make our form data available to the parent or to other child components within our Vue application. We can accomplish this using `$emit`. - -We will emit our event by assigning it an event name. Then we add a listener for that event in our template, or in any other component that needs to receive information about this event. The listener can, in turn, execute another method to perform specific operations with the data it receives from our form event. - -- Create the `onSubmit` method in **FoodPrefsForm.js** for capturing form data and storing it in data properties below the comment that reads `/* TODO: Add methods */`. - - The method will create a `foodprefanswers` object that will capture the data submitted in the form. - - Emit a `review-submitted` event that passes the data contained in `foodprefanswers` "up" to the HTML interface. - - Clear out the form fields so the form can be re-used after the data has been transmitted. - -```javascript -... -/* TODO: Add methods */ - methods: { - onSubmit() { - let foodprefanswers = { - passenger: this.passenger, - allergies: this.allergies, - allergydesc: this.allergydesc, - glutenfree: this.glutenfree, - vegan: this.vegan, - } - - this.$emit('foodpref-submitted', foodprefanswers); - - this.passenger = ''; - this.allergies = ''; - this.allergydesc = ''; - this.glutenfree = ''; - this.vegan = ''; - - }, - }, -... -``` - -## Import the form data into the HTML template - -We have already added the **FoodPrefsForm.js** component to the bottom of our **index.html** file by specifying the location of the source script, which is located in the components directory, as shown in the snippet below. - -```html -... - - -... -``` - -We also previously added the content of the `foodprefs-form` component by adding the `` tag to the template. The form works now, but nothing happens when we click the `Submit` button because our application does not yet have access to the data. - -## Listen for the emitted form data in the template - -We need to create a `listener` in the Vue template to receive the data emitted from the `` in this `component`. We will add this listener to the `` tag where it is displayed in the **index.html** file. Then we need to create the `addFoodpref` method in our **main.js** Vue application. - -- In **index.html** add a listener `@foodpref-submitted` to the `` tag below the comment that reads ``. - - The listener will execute a method named `addFoodpref`. - -```html -... - - -... -``` - -Now we modify the **main.js** application file to create an array data property and a method that will push the data elements into that array when data is emitted from the form that resides in our component. - -- Add an array data property to **main.js** below the comment that reads `//TODO: Create array property`. - -```javascript -... -berth: true, -previous: true, -//TODO: Add array property -foodprefs: [], -... -``` - -- Create a method `addFoodpref` below the comment that reads `//TODO: Create method to push data into array`. - -```javascript -... -//TODO: Create method to push data into array -addFoodpref(foodpref) { - this.foodprefs.push(foodpref); -}, -... -``` - -The form works now, as shown in the image below. However, when we click the `Submit` button the data will disappear because the form is cleared out after data is submitted to the Vue application. In order to see the data that was generated and stored in our data properties, we will create a component that displays the passenger's Food Preferences. - -![Screenshot showing the HTML page with a selected product image on the left and 4 thumbnail images below it. The first thumbnail from the left is highlighted with a yellow background. Product name and description are displayed on the right. Two components are shown at the bottom left of the screen: "Food Preferences" and "Welcome Back to the Galaxy!" The "Food Preferences" form is filled out with sample data that is ready to be submitted.](../media/m09_Food-Pref-Form.png) - -## Display the form data in the template - -Create a component named **FoodPrefsList.js** to display the data that is generated when a Food Preferences form is submitted. Make sure you include a prop to pull the data arraty "down" into this component from the template. - -- Create a **foodprefs** `prop` at the top of the component that is defined as type `Array`. -- Add the `html` elements that will be displayed in the template. - -```javascript -... -app.component('foodpref-list', { - props: { - foodprefs: { - type: Array, - required: true - } - }, - template: - /*html*/ - `` -}) -... -``` - -Now we will add the **FoodPrefsList.js** component to the **index.html** template. We want to display this new component only when the passenger has submitted a Food Preferences form. We will use the `v-bind` shorthand to tell Vue to cycle through the data in the `foodprefs` array. - -- Specify the location of the **FoodPrefsList.js** component by specifying the source script below the comment that reads ``. -- Add the content of the `foodpref-list` component to the template display by adding the `` tags below the comment that reads ``. - - Use `v-if` to set the component to display only when there is data in the `foodprefs` array (i.e., the `length` of the array is greater than 0). - -```html -... - - -... - - -... -``` - -The form works now and the HTML interface displays the form data when the `Submit` button is clicked, as shown in the image below. The form is reset (form fields cleared out) at the end of the `onSubmit` event. - -![Screenshot showing the HTML page with a selected product image on the left and 4 thumbnail images below it. The first thumbnail from the left is highlighted with a yellow background. Product name and description are displayed on the right. Two components are shown at the bottom left of the screen. The first component highlighted with a light yellow background contains the sample data that was submitted in the form. The form fields are now cleared in the "Food Preferences" form.](../media/m09_Food-Pref-Form_submitted.png) - -## Form Validation - -For legal reasons we have decided that we want to add some basic form validation to ensure that users fill out all fields within our "Food Preferences" form. Even if a passenger selects "No" in response to the question "Do you have food allergies?", we want them to clarify that in the "Describe allergies" field by specifying "None". - -We can accomplish this by adding a simple `if` statement at the beginning of our `onSubmit()` method. We essentially list all fields in the form and declare that if the first field is empty, **or** (`||`) the second field is empty, and so on...an alert should pop up to inform the user that the form is incomplete. This `if` statement will be checked by the Vue application when the user clicks the `Submit` button. -- Add an `if` statement on the first line below the `onSubmit() {` method below the comment that reads `/* TODO: Add methods */`. - -```javascript -... - /* TODO: Add methods */ - methods: { - onSubmit() { - if (this.passenger === '' || this.allergies === '' || this.allergydesc === '' || this.glutenfree === '' || this.vegan === '') { - alert('Form is incomplete. Please fill out every field.') - return - } - let foodprefanswers = { -... -``` - -When a user fills out the form, but one or more fields are empty when they click the `Submit` button, the browser will pop up an alert message as shown in the image below. - -![Screenshot showing the HTML page with a selected product image on the left and 4 thumbnail images below it. The first thumbnail from the left is highlighted with a yellow background. Product name and description are displayed on the right. Two components are shown at the bottom left of the screen. The first component highlighted with a light yellow background contains the sample data that was submitted in the form. The form fields are now cleared in the "Food Preferences" form.](../media/m09_Food-Pref-Form_alert.png) -- The Vue application performs a validation check on the data fields in the form "after" the `Submit` button is clicked but "before" executing the `onSubmit` method. diff --git a/3-data-events/4-event-handlers.md b/3-data-events/4-event-handlers.md new file mode 100644 index 0000000..57ba355 --- /dev/null +++ b/3-data-events/4-event-handlers.md @@ -0,0 +1,34 @@ +Events are actions which we know can occur in our application but we don't necessary know when. For example, if you have a button on a page you know it's likely the user will click on it, but the timing is unknown. Handling events is a key component to creating any web application. We will explore how Vue.js allows you to manage events. + +## v-on directive and @ + +Vue.js provides a directive called `v-on` which can be bound to any event, such as `v-on:click`. However, since handling events is a core task Vue.js also provides the `@` shortcut for any event. To bind a click event you can use `@click` instead. + +## Creating event handlers + +You can create event handlers by adding functions to the `methods` field in a Vue application or component. `methods` is just like `data()`, only instead of returning state objects it maintains a list of available functions for your application. You can then reference these in your HTML in the same way you would reference other JavaScript functions. The key reason to add functions to the `methods` field is the functions can access any registered data. + +When adding a method to a Vue app or component, `this` points to the active instance. Any data available to the active instance, such as `name` in our example below, is accessible from `this`. + +To create a method which would display the `name` when called, we could add it like this: + +```javascript +const app = Vue.createApp({ + data() { + return { + name: 'Cheryl' + } + }, + + methods: { + displayName() { + console.log(this.name); + } + } +}); +``` + +We can then execute the function when a button is clicked by setting it to the `@click` attribute: + +```html + diff --git a/3-data-events/4-module-summary.md b/3-data-events/4-module-summary.md deleted file mode 100644 index 8299a3b..0000000 --- a/3-data-events/4-module-summary.md +++ /dev/null @@ -1,9 +0,0 @@ -In this module you learned how to manage events that a user can trigger through actions like clicking a button or hovering over an item in your HTML interface. We dmonstrated how to set up a listener for an event, then trigger application logic in one of two ways: - - changing inline data properties for implementing simple logic - - creating a method that can be used to implement more complex logic. - -## Coding Challenge - -Now it's your turn! Armed with the information presented in this module, you should now be able to perform the following task on your own. - -- Create a new button that decrements the value of the cart object \ No newline at end of file diff --git a/3-data-events/5-exercies-event-handlers.md b/3-data-events/5-exercies-event-handlers.md new file mode 100644 index 0000000..c8ddfbf --- /dev/null +++ b/3-data-events/5-exercies-event-handlers.md @@ -0,0 +1,46 @@ +Let's update our application to add in an event handler for a newly created button on our form. The button will toggle the `booking.completed` flag which will update our display. + +## Add the function + +We will start by adding to the Vue application. + +1. Inside Visual Studio Code, open *index.js* +1. Below the comment which reads `TODO: Add methods`, add the following code to create the `bookCabin` function, which will be our event handler: + + ```javascript + // TODO: Add methods + methods: { + bookCabin() { + this.booking.completed = true; + } + } + ``` + + Notice how `this` is bound to our current application and provides access to the `booking` object from our data. + +## Add the button to the form + +Let's add the button to our form. + +1. Inside Visual Studio Code, open *index.html* +1. Below the comment which reads `TODO: Add button later`, add the following HTML to create our button: + + ```html + + + ``` + + Notice the `@click` attribute is bound to the `bookCabin` function we created earlier. + +## Test the page + +Let's test our updated page! + +1. Save all files by clicking *File* > *Save all* +1. Ensure *Live Server* is running by pressing *Ctl-Shift-P* (or *Cmd-Shift-P* on a Mac), typing *Live Server* in the command pallet, and selecting *Live Server: Open with Live Server* +1. Open your browser and navigate to **http://localhost:5500** +1. The page now displays with the button +1. Fill out the form and click the button +1. Notice the form disappears from the page + +You have now configured an event handler in Vue. diff --git a/3-data-events/5-exercise-data-events.md b/3-data-events/5-exercise-data-events.md deleted file mode 100644 index e69de29..0000000 diff --git a/3-data-events/6-computed-properties.md b/3-data-events/6-computed-properties.md new file mode 100644 index 0000000..15d6934 --- /dev/null +++ b/3-data-events/6-computed-properties.md @@ -0,0 +1,25 @@ +By using the handlebars syntax (`{{ }}`), we are able to display values and inject JavaScript into our HTML. While this is powerful, it can lead to confusing or repetitive code. You can use computed properties in Vue to offload calculations and other forms of dynamic strings. + +## Creating a computed property + +Much in the same way methods are added under a `methods` field, computed properties are added to the `computed` field. A computed property is a function which returns a value. Just like a method from before, a computed property is able to access the active instance of Vue by using `this`. + +You can use computed properties to combine `firstName` and `lastName` into a `fullName` property, perform lookups in an array to return the correct value, or anything else which might be dynamic. + +Creating the `fullName` example would look like this: + +```javascript +const app = Vue.createApp({ + data() { + return { + firstName: 'Cheryl', + lastName: 'Smith' + } + }, + computed: { + fullName() { + return `${lastName}, ${firstName}` + } + }, +}); + diff --git a/3-data-events/7-exercise-computed-properties.md b/3-data-events/7-exercise-computed-properties.md new file mode 100644 index 0000000..2aca479 --- /dev/null +++ b/3-data-events/7-exercise-computed-properties.md @@ -0,0 +1,61 @@ +Let's create a computed property to display out the information about the selected cabin. We will also add in the necessary HTML to display it on the page. + +## Add the computed property + +Let's add the computed property to create a string to be displayed for the selected cabin. + +1. Inside Visual Studio Code, open *index.js* +1. Below the comment which reads `TODO: Add computed values`, add the following JavaScript to create the computed value + + ```javascript + // TODO: Add completed values + computed: { + bookingCabinDisplay() { + const cabin = this.product.cabins[this.booking.cabinIndex]; + return `${cabin.name}: $ ${cabin.price.toLocaleString('en-US')}` + } + }, + ``` + + Notice how we are able to use `this` to access the `product.cabins`, and `booking.cabinIndex` to find the cabin the user selected. We then create the display string by using the ECMAScript template. + +## Add the display to the page + +Let's add the display to our page. + +1. Inside Visual Studio Code, open *index.html* +1. Below the line which reads `TODO: Add success display`, add the following HTML to display the booking: + + ```html + +
+

+ You are on your way! +

+
+
Booking details:
+
{{ bookingCabinDisplay }}
+
Notes: {{ booking.notes }}
+
+
+ ``` + + Notice how we are using `v-show` to display when `booking.completed` is set to true, which we setup earlier with our button. Also notice how we are able to read `bookingCabinDisplay` like we would any other string value inside Vue to display it to the user. + +## Test the page + +Let's see our page in action! + +1. Save all files by clicking *File* > *Save all* +1. Ensure *Live Server* is running by pressing *Ctl-Shift-P* (or *Cmd-Shift-P* on a Mac), typing *Live Server* in the command pallet, and selecting *Live Server: Open with Live Server* +1. Open your browser and navigate to **http://localhost:5500** +1. The page now displays +1. Fill out the form + + ![The form completed with business class selected and window seat please as the text](media/form-completed.png) + +1. Click the button and notice the display + + ![The display updated with business class and the price, and the note of window seat please](media/booking-display.png) + +You have now added a computed property to a Vue application. diff --git a/3-data-events/8-summary.md b/3-data-events/8-summary.md new file mode 100644 index 0000000..5d33ec3 --- /dev/null +++ b/3-data-events/8-summary.md @@ -0,0 +1 @@ +In this module we explored how to allow our users to interact with Vue data. We started by creating a form and binding data to the form. We then setup an event handler, and configured it so a button click would call it. We finished by adding a computed property to minimize the amount of JavaScript code required in our HTML. diff --git a/3-data-events/media/booking-display.png b/3-data-events/media/booking-display.png new file mode 100644 index 0000000..3372418 Binary files /dev/null and b/3-data-events/media/booking-display.png differ diff --git a/3-data-events/media/form-completed.png b/3-data-events/media/form-completed.png new file mode 100644 index 0000000..1024720 Binary files /dev/null and b/3-data-events/media/form-completed.png differ diff --git a/3-data-events/media/form-created.png b/3-data-events/media/form-created.png new file mode 100644 index 0000000..a7a34d8 Binary files /dev/null and b/3-data-events/media/form-created.png differ diff --git a/3-data-events/media/liveserver_golive.png b/3-data-events/media/liveserver_golive.png deleted file mode 100644 index c4d9271..0000000 Binary files a/3-data-events/media/liveserver_golive.png and /dev/null differ diff --git a/3-data-events/media/liveserver_port.png b/3-data-events/media/liveserver_port.png deleted file mode 100644 index adbc30d..0000000 Binary files a/3-data-events/media/liveserver_port.png and /dev/null differ diff --git a/3-data-events/media/m05-start.png b/3-data-events/media/m05-start.png deleted file mode 100644 index f047349..0000000 Binary files a/3-data-events/media/m05-start.png and /dev/null differ diff --git a/3-data-events/media/m07-alien-spaceship.png b/3-data-events/media/m07-alien-spaceship.png deleted file mode 100644 index aeccf8e..0000000 Binary files a/3-data-events/media/m07-alien-spaceship.png and /dev/null differ diff --git a/3-data-events/media/m07-asteroid-fireworks.png b/3-data-events/media/m07-asteroid-fireworks.png deleted file mode 100644 index fa13145..0000000 Binary files a/3-data-events/media/m07-asteroid-fireworks.png and /dev/null differ diff --git a/3-data-events/media/m07-start.png b/3-data-events/media/m07-start.png deleted file mode 100644 index 2efeb60..0000000 Binary files a/3-data-events/media/m07-start.png and /dev/null differ diff --git a/3-data-events/media/m08-comp-food-prefs.png b/3-data-events/media/m08-comp-food-prefs.png deleted file mode 100644 index 293e2ee..0000000 Binary files a/3-data-events/media/m08-comp-food-prefs.png and /dev/null differ diff --git a/3-data-events/media/m08-components.png b/3-data-events/media/m08-components.png deleted file mode 100644 index 6edc8eb..0000000 Binary files a/3-data-events/media/m08-components.png and /dev/null differ diff --git a/3-data-events/media/m08-es-6-string-html.png b/3-data-events/media/m08-es-6-string-html.png deleted file mode 100644 index 19e313a..0000000 Binary files a/3-data-events/media/m08-es-6-string-html.png and /dev/null differ diff --git a/3-data-events/media/m08-no-sleeping-berth.png b/3-data-events/media/m08-no-sleeping-berth.png deleted file mode 100644 index 75d5f87..0000000 Binary files a/3-data-events/media/m08-no-sleeping-berth.png and /dev/null differ diff --git a/3-data-events/media/m08-sleeping-berth.png b/3-data-events/media/m08-sleeping-berth.png deleted file mode 100644 index 783d397..0000000 Binary files a/3-data-events/media/m08-sleeping-berth.png and /dev/null differ diff --git a/3-data-events/media/m08-start.png b/3-data-events/media/m08-start.png deleted file mode 100644 index f8f1214..0000000 Binary files a/3-data-events/media/m08-start.png and /dev/null differ diff --git a/3-data-events/media/m09_Food-Pref-Form.png b/3-data-events/media/m09_Food-Pref-Form.png deleted file mode 100644 index 3719467..0000000 Binary files a/3-data-events/media/m09_Food-Pref-Form.png and /dev/null differ diff --git a/3-data-events/media/m09_Food-Pref-Form_alert.png b/3-data-events/media/m09_Food-Pref-Form_alert.png deleted file mode 100644 index 4cbfab4..0000000 Binary files a/3-data-events/media/m09_Food-Pref-Form_alert.png and /dev/null differ diff --git a/3-data-events/media/m09_Food-Pref-Form_submitted.png b/3-data-events/media/m09_Food-Pref-Form_submitted.png deleted file mode 100644 index 65fb690..0000000 Binary files a/3-data-events/media/m09_Food-Pref-Form_submitted.png and /dev/null differ diff --git a/3-data-events/media/m09_start.png b/3-data-events/media/m09_start.png deleted file mode 100644 index b8d38a9..0000000 Binary files a/3-data-events/media/m09_start.png and /dev/null differ diff --git a/3-data-events/media/thumbnails_cart_button.png b/3-data-events/media/thumbnails_cart_button.png deleted file mode 100644 index 259a7ca..0000000 Binary files a/3-data-events/media/thumbnails_cart_button.png and /dev/null differ diff --git a/3-data-events/media/vscode_liveserver.png b/3-data-events/media/vscode_liveserver.png deleted file mode 100644 index e0e2f12..0000000 Binary files a/3-data-events/media/vscode_liveserver.png and /dev/null differ diff --git a/4-event-handling/0-overview.md b/4-event-handling/0-overview.md deleted file mode 100644 index e69de29..0000000 diff --git a/4-event-handling/1-event-handling-using-data-properties.md b/4-event-handling/1-event-handling-using-data-properties.md deleted file mode 100644 index 1ca5fb7..0000000 --- a/4-event-handling/1-event-handling-using-data-properties.md +++ /dev/null @@ -1,44 +0,0 @@ -Our sample project is a fictitious travel agency for booking space travel. We want to allow a customer to add a cruise to their cart. We'll do this by creating a section on the page to display the number of items currently in the cart, and then a button for them to add an item. - -## Add the cart display - -Open **index.html** either from the [starter code](link), or your existing project if you are following along from prior modules. - -- Add a `
` for the cart below the comment that reads `TODO: Add cart div` - - Set the `class` for the `div` to **cart** - - Set the text to **Cart ({{ cart }})** - -```html - -
Cart ({{ cart }})
-``` - -`cart` is the variable used to store the number of items currently in the cart. It is stored in the data we registered with Vue.js in the **main.js** file. By using the `{{ }}` syntax (sometimes known as handlebars), we are instructing Vue.js to display the value. - -- Add a `button` to book a cruise below the comment that reads `TODO: Add book cruise button` - - Set the `class` to **button** - - Set the text to **Book a Cruise** - -```html - - -``` - -To see if this value displays accurately, you can temporarily change the value of cart in your **main.js** file and render your HTML page in the browser to see if the cart correctly displays your new value. - -## Add the book cruise button - -Now we need to enable the button to change the value of the art dynamically when the user clicks it. We do this by adding a **listener** that will change the value of cart whenever a click action occurs. This is accomplished in Vue by adding the `v-on` directive to our button element. - -- Add a `button` below the comment that reads `TODO: Add book cruise button` - - Set the `class` to **button** - - Set the `v-on:click` attribute to **cart += 1** - -```html - - -``` - -In the code example above, `v-on` is the Vue directive, `click` is the event we are listening for, and `cart += 1` is the expression we are using to calculate the value of `cart` whenever the `click` event occurs. The expression can be any valid JavaScript or, as we'll see in the next unit, the name of a function. - -After you add the `v-on` directive to the button element in your HTML file, launch it and render it in the browser, you should be able to click the button multiple times and watch the number displayed in the cart object increment by a value of 1 for each click. diff --git a/4-event-handling/2-event-handling-using-methods.md b/4-event-handling/2-event-handling-using-methods.md deleted file mode 100644 index 1eb5f9a..0000000 --- a/4-event-handling/2-event-handling-using-methods.md +++ /dev/null @@ -1,95 +0,0 @@ -## Event handling using methods for more complex logic - -It is likely that we will need to perform additional complex operations with regard to contents of the cart, so trying to track all of the changes and computations using inline properties can become awkward and potentially confusing. In our Vue app we can use a `method` instead of a `data property` to trigger more complex logic operations. - -## Create method to increment value of cart - -Open **index.html** either from the [starter code](link), or your existing project if you are following along from prior modules. - -- Add a `comma` following the curly brace below the comment that reads `//TODO: Add a comma` -- Add a `method` named `addItemToCart` below the comment that reads `//TODO: Increment value of cart` - - Increment the value of cart by 1 - -```javascript - //TODO: Add a comma - }, - //TODO: Increment value of cart - methods: { - addItemToCart() { - this.cart += 1; - } - }, -}) -``` - ->[!NOTE] ->Note that the punctuation structure when defining a method is distinctly different from the structure for defining a data property. - -## Apply method to button - -Now change the button in your HTML file to use the `addToCart` method instead of the data expression used previously. Notice that we are still using the `v-on:click` directive. The name of the method is inserted between quotation marks to replace the mathematical expression we used previously. - -- Add `v-on:click` directive to Book a Cruise button below the comment that reads `TODO: Add item to cart` - -```html - - -``` - -If you render the HTML file now, the cart should behave the same way it did when using the data expression. Clicking the "Book a Cruise" button should increment the number in the cart by 1 every time you click it because the `v-on` directive is still listening for that click event. - -## Shorthand notation for v-on directive - -You should also be aware that Vue allows a shorthand notation when using the `v-on` directive. You can use the "at" symbol (@) in place of `v-on:`, as shown below. - -```html - -``` - -## Change selected product image when thumbnail is clicked - -Now you can make a change that you have probably been waiting to execute. Let's make the selected image change to display a larger image in a thumbnail whenever the thumbnail image is clicked. - -Rather than using a data property for this purpose, we should use a method because in later modules we will want to execute additional actions whenever each thumbnail is clicked (e.g., changing the text in the product description area in addition to changing the selected product image.) For now, add four new methods in your **main.js** file, as shown in the code snippet below. - -Then use the `v-on:click` directive in your **index.html** file to execute the action in the appropriate method when each thumbnail image is clicked. - -- Add 4 methods in **main.js** below the comment `//TODO: Change selected image` - - set `selectedProdImg` path in each method -- Apply `v-on:click` directive in **index.html** below the comment `TODO: Change selected image` - -```javascript -//TODO: Change selected image -featureBookCruise() { - this.selectedProdImg = './assets/images/space-4888643_1284x856.jpg'; -}, -featureAsteroid() { - this.selectedProdImg = './assets/images/asteroid-5737398_1284x856.jpg'; -}, -featureBulletTrain() { - this.selectedProdImg = './assets/images/fantasy-5732286_1284x856.jpg'; -}, -featureAlienShip() { - this.selectedProdImg = './assets/images/spaceship-5730066_1284x856.jpg'; -}, -``` - -```html - -
- - - - -
-``` - -> [!TIP] -> If you want to have this method execute whenever a user hovers the mouse over a thumbnail image you could use the Vue @mouseover directive instead of @click. - -![Screenshot showing the HTML page with a selected produce image on the left and 4 thumbnail images below it. Product name and description are displayed on the right, with two paragraphs of text. Below this are unordered lists for Passenger Rates and Group Discounts](../media/thumbnails_cart_button.png) - -- Change the selected product image when a thumbnail image is clicked -- Increment the value of cart when "Book a Cruise" button is clicked - -When testing your **index.html** file in the browser, it may seem like the method is not executing properly if you click the first thumbnail image on the far left. That's because this thumbnail is for the "Book a Cruise to the Moon" feature, which is displayed by default when the page initially loads. Try clicking any other thumbnail, and then click the first thumbnail again to set the selected image back to the default image. diff --git a/4-event-handling/3-exercise-event-handling.md b/4-event-handling/3-exercise-event-handling.md deleted file mode 100644 index e69de29..0000000 diff --git a/5-CLI-components-properties/1-vue-cli.md b/5-CLI-components-properties/1-vue-cli.md index 6cdd130..cffb5f2 100644 --- a/5-CLI-components-properties/1-vue-cli.md +++ b/5-CLI-components-properties/1-vue-cli.md @@ -1,6 +1,7 @@ This section demonstrates how to use the Vue CLI to build a starter project that provides a skeleton framework that you can use to rapidly deploy a Vue application. In the next section we will demonstrate how to build a starter project using the Vue graphical user interface (UI). Some of the advantages of using the CLI to create a Vue project include the statements listed below. The CLI: + - Selects the libraries that your project will use. - Configures Webpack, so that all JavaScript files, CSS files and other dependencies get properly bundled together and optimized for deployment. This can reduce loading speed for your application. - Allows you to use single-file `.vue` components, `TypeScript`, `SCSS`, `Pug` and the latest versions of `ECMAScript`. @@ -13,8 +14,6 @@ In order to use Vue CLI, you will need to run `npm`, which is the package manage ```bash node -v -``` -```bash npm -v ``` @@ -38,9 +37,11 @@ npm install -g @vue/cli On a Windows computer these files will likely be located at: `C:\Program Files\nodejs\node_modules\npm`. On a Mac computer these files will likely be located at: `/usr/local/lib/node_modules/@vue/.` + ## Create a project After installation of the Vue CLI, you can create your project in two different ways: + - using commands in a terminal - using the Vue UI diff --git a/5-CLI-components-properties/2-vue-spa-intro.md b/5-CLI-components-properties/2-vue-spa-intro.md new file mode 100644 index 0000000..635443b --- /dev/null +++ b/5-CLI-components-properties/2-vue-spa-intro.md @@ -0,0 +1,31 @@ +You've used the CLI to create a basic Vue single file application. This application also uses Vue components so you have the basic framework in place to build a Vue app. This is the beauty of the CLI: it does all the foundational work for you so you can focus on building your application. + +In this and subsequent topics, we'll be developing a single-page application (SPA) using Vue. If you're not familar with the concept of a SPA, the model essentially rebuilds a single page with updated data from a server or based on user entry--thus the name single *page* application. In traditional web design, updated information would be sent to the user in a new page. This Wikipedia page has a good introduction to single-page applications if you want to read more: https://en.wikipedia.org/wiki/Single-page_application. + +## Vue SPAs + +### Main Application + +The CLI will install all the files you need for a single-page application. When the scripts are finished running, your folder structure should look something like this: + +![Screenshot showing the File Explorer on a Windows computer. The Explorer window shows the file structure of the application the command line interface installed. ](media/Vue-SPA_01.png) + +The main files for the application are in the `src` folder. If you open that folder, you'll see the following files: + +![Screenshot showing the File Explorer on a Windows computer. The Explorer window shows the contents of the src folder. ](media/Vue-SPA_02.png) + +The entry point code for your JavaScript application is in `main.js` and in this file you import the Vue libraries and the main Vue app file called `App.vue`. Notice the `.vue` extension on this (and other) files. We'll talk more about this file type in the next topic. + +The `App.vue` file is of particular importance in this model as it not only harnesses the main functionality of the application but also demonstrates routing in Vue--a primary feature that gives SPAs their power. You learned about Vue routing earlier in this course. + +Note that this application cannot be consumed natively on the web as is. It has to be 'built' which you learned about in the topic on the CLI. A tool like the Vue builder, Webpack, or Snowpack handles creating all the files needed so a web server like Node.js can serve the files to the user over the internet. + +### Other Files + +In the `views` folder you'll see two other `.vue` files: `Home.vue` and `About.vue` which contain the code and content for those repsective pages (though if you look inside `Home.vue` you'll notice it loads `HelloWorld.vue` which contains the main body content of the home page). In Vue, these types of files--files with the `.vue` extension--are called "components." When the user requests these components, the Vue router loads them into the viewport of the application without having to redirect the user to a different page. This decreases load time for the user and helps create the "application" experience in this web application. + +The folder structure of this application is very intentional. The builder and router looks for specific files in specific folders. While these can be changed with configuration files, the basic structure of this application is what the builder expects. + +## Conclusion + +Now that you have a basic understanding of how a Vue SPA is structured, we can take a look at `.vue` files themselves so you can understand how to write your own and start builing more powerful Vue applications. \ No newline at end of file diff --git a/5-CLI-components-properties/3-vue-spa.md b/5-CLI-components-properties/3-vue-spa.md new file mode 100644 index 0000000..53dcfb8 --- /dev/null +++ b/5-CLI-components-properties/3-vue-spa.md @@ -0,0 +1,32 @@ +The previous overview gave you an explanation of what a Single File Application is and why you would use them. Let's now turn to the structure of the application model itself in order to get a better technical understanding of the SPA architecture. + +Using File Explorer (or Finder on the Mac), browse to the root directory of the project you created using the CLI and open the `src` folder. Inside, you'll see a file called `App.vue` which is the primary Vue file for this application. Open this file in your code editor. + +You should see two main sections in this file: a `