Skip to content

Commit 5cc2524

Browse files
NataliaTepluhinayyx990803
authored andcommitted
feat: split lesson 2 onto 3 lessons
1 parent 8e0e5b7 commit 5cc2524

14 files changed

+277
-165
lines changed
+2-27
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Handling User Input
1+
# Binding Dynamic Attributes
22

33
Let's make our example more interactive! What if we could allow user to change `colorsNumber` from the UI? To implement this, we need to start with adding an `<input>` field to our component template
44

@@ -10,33 +10,8 @@ Let's make our example more interactive! What if we could allow user to change `
1010
</div>
1111
```
1212

13-
Now, we have to provide some initial value to our input, and we want to display `colorsNumber` there. In Vue, we can use a _dynamic binding_ to provide a value:
13+
Now, we have to provide some initial value to our input, and we want to display `colorsNumber` there. In Vue, we can use a `v-bind` directive or its shorthand `:` to bind the component reactive property to the element attribute:
1414

1515
```html
1616
<input type="number" :value="colorsNumber" />
1717
```
18-
19-
However, when we change the number in the input field, we don't see any changes on `Number of colors` in the template 🤔. It happens because we only have _one-way binding_ now, displaying reactive property in the input field but not _changing_ it on user input. Let's listen to the `input` DOM event on the `<input>` field and update `colorsNumber` on it:
20-
21-
```html
22-
<input
23-
type="number"
24-
:value="colorsNumber"
25-
@input="colorsNumber = $event.target.value"
26-
/>
27-
```
28-
29-
Now we created a _two-way binding_: we update `input` field on reactive property change and vice versa. Vue.js has a `v-model` directive to make two-way binding less verbose. Let's replace out `:value` and `@input` with it:
30-
31-
```html
32-
<input type="number" v-model="colorsNumber" />
33-
```
34-
35-
Now, we can choose how many colors we'll have in our guessing game! As a last touch, let's add a label to our input field and set up minimum and maximum for it:
36-
37-
```html
38-
<label for="colors">
39-
Enter number of colors and press Enter:
40-
<input id="colors" type="number" v-model="colorsNumber" min="2" max="10" />
41-
</label>
42-
```

src/tutorial/src/step-3/App/style.css

-28
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,3 @@ input {
2626
background-color: teal;
2727
transition: background 0.5s;
2828
}
29-
30-
nav {
31-
display: flex;
32-
height: 30px;
33-
justify-content: space-between;
34-
align-items: center;
35-
padding: 0 20px;
36-
background-color: white;
37-
color: teal;
38-
font-size: 16px;
39-
text-transform: uppercase;
40-
}
41-
42-
nav button {
43-
text-transform: uppercase;
44-
padding: 0 8px;
45-
height: 100%;
46-
font-size: 16px;
47-
background-color: white;
48-
border: none;
49-
cursor: pointer;
50-
color: teal;
51-
}
52-
53-
nav button:hover {
54-
background-color: teal;
55-
color: white;
56-
}

src/tutorial/src/step-3/App/template.html

+1-4
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
<div class="panel">
33
<h1>Guess the Color</h1>
44
<h2>Number of colors: {{ colorsNumber }}</h2>
5-
<label for="colors">
6-
Enter number of colors and press Enter:
7-
<input id="colors" type="number" v-model="colorsNumber" min="2" max="10" />
8-
</label>
5+
<input type="number" :value="colorsNumber"/>
96
</div>
107
</main>
+9-106
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,15 @@
1-
# Conditional Rendering
1+
# Listening to Events
22

3-
Now, when we have defined how many colors we will show in the game, it's time to actually make our game start. For now, we want to have two states:
3+
Now we can see that `colorsNumber` is displayed on the input field. However, when we change the number in the input, we don't see any changes on `Number of colors` in the template 🤔. It happens because we only have _one-way binding_ now, displaying reactive property in the input field but not _changing_ it on user input.
44

5-
- game is not started: we are displaying our input field so user can define the number of colors to guess;
6-
- game is started: for now, we want to hide the input field and we want to display a text "Game is started".
7-
8-
Let's start with creating one more reactive property - `gameStarted`:
9-
10-
<div class="composition-api">
11-
12-
```js{2}
13-
const colorsNumber = ref(3)
14-
const gameStarted = ref(false)
15-
```
16-
17-
</div>
18-
19-
<div class="options-api">
20-
21-
```js{4}
22-
data() {
23-
return {
24-
colorsNumber: 3,
25-
gameStarted: false
26-
}
27-
}
28-
```
29-
30-
</div>
31-
32-
Now, we can add a new section to our component template:
33-
34-
```html{4}
35-
<div class="panel">
36-
<!-- header content -->
37-
</div>
38-
<section class="flex" v-if="gameStarted">Game is started</section>
39-
```
40-
41-
Try to change `gameStarted` to `true` and you will see a text rendered below the header.
42-
43-
Let's start our game as soon as user submits the form with pressing <kbd>Enter</kbd> on the input field. To make this more semantic, let's wrap our input in `<form>` tag:
44-
45-
```html
46-
<form>
47-
<label for="colors">
48-
Enter number of colors and press Enter:
49-
<input id="colors" type="number" v-model="colorsNumber" />
50-
</label>
51-
</form>
52-
```
53-
54-
Form with the single input will be submitted on <kbd>Enter</kbd> press automatically. We only need to listen to the form's submit event:
55-
56-
```html
57-
<form @submit="gameStarted = true">
58-
<label for="colors">
59-
Enter number of colors and press Enter:
60-
<input id="colors" type="number" v-model="colorsNumber" />
61-
</label>
62-
</form>
63-
```
64-
65-
However, if we leave it like this, page will refresh and no text will be shown. The reason is we need to _prevent a default form submit event_ and make our change instead. In JavaScript, it's done with `event.preventDefault()` method; in Vue.js we have an event modifier `.prevent` that does the same under the hood.
5+
To make this change, we need to listen to the `input` DOM event on the `<input>` field and update `colorsNumber` on it. This can be done with Vue's `v-on` directive or its shorthand `@`:
666

677
```html
68-
<form @submit.prevent="gameStarted = true">
69-
<label for="colors">
70-
Enter number of colors and press Enter:
71-
<input id="colors" type="number" v-model="colorsNumber" />
72-
</label>
73-
</form>
74-
```
75-
76-
Now, whenever user enter a number in the input field and presses <kbd>Enter</kbd>, we can see that game is started.
77-
78-
The last thing we want to implement in this lesson is hiding the input field when the game is already started and showing a button `Change colors number`. Clicking on the button will set the game to "not-started" and show the input again. First, let's add the button to our template:
79-
80-
```html{1-3}
81-
<nav>
82-
<button @click="gameStarted = false">Change squares number</button>
83-
</nav>
84-
<form @submit.prevent="gameStarted = true">
85-
<label for="colors">
86-
Enter number of colors and press Enter:
87-
<input id="colors" type="number" v-model="colorsNumber" />
88-
</label>
89-
</form>
90-
```
91-
92-
Now, let's display the `<nav>` conditionally when game is started:
93-
94-
```html{1-3}
95-
<nav v-if="gameStarted">
96-
<button @click="gameStarted = false">Change squares number</button>
97-
</nav>
8+
<input
9+
type="number"
10+
:value="colorsNumber"
11+
@input="colorsNumber = $event.target.value"
12+
/>
9813
```
9914

100-
Just like you can use `if...else` in JavaScript, you can use `v-if` and `v-else` in Vue. So when `gameStarted` is `true`, we're displaying `<nav>`, else we're displaying the form:
101-
102-
```html
103-
<nav v-if="gameStarted">
104-
<button @click="gameStarted = false">Change squares number</button>
105-
</nav>
106-
<form v-else @submit.prevent="gameStarted = true">
107-
<label for="colors">
108-
Enter number of colors and press Enter:
109-
<input id="colors" type="number" v-model="colorsNumber" />
110-
</label>
111-
</form>
112-
```
15+
`$event` is the HTML native [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event)(in our case it's `input`).
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { ref } from 'vue'
2+
3+
export default {
4+
name: 'App',
5+
setup() {
6+
const colorsNumber = ref(3)
7+
8+
return { colorsNumber }
9+
}
10+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default {
2+
name: 'App',
3+
data() {
4+
return {
5+
colorsNumber: 3
6+
}
7+
}
8+
}

src/tutorial/src/step-4/App/style.css

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
* {
2+
margin: 0;
3+
padding: 0;
4+
}
5+
6+
#app {
7+
font-family: Avenir, Helvetica, Arial, sans-serif;
8+
-webkit-font-smoothing: antialiased;
9+
-moz-osx-font-smoothing: grayscale;
10+
text-align: center;
11+
color: #2c3e50;
12+
}
13+
14+
label {
15+
font-size: 18px;
16+
}
17+
18+
input {
19+
font-size: 18px;
20+
padding-left: 5px;
21+
width: 35px;
22+
}
23+
24+
.panel {
25+
color: white;
26+
background-color: teal;
27+
transition: background 0.5s;
28+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<main>
2+
<div class="panel">
3+
<h1>Guess the Color</h1>
4+
<h2>Number of colors: {{ colorsNumber }}</h2>
5+
<label for="colors">
6+
Enter number of colors and press Enter:
7+
<input id="colors" type="number" v-model="colorsNumber" min="2" max="10" />
8+
</label>
9+
</div>
10+
</main>
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Two-Way Binding
2+
3+
In the previous step we created a _two-way binding_: we update `input` field on reactive property change and vice versa. Vue.js has a `v-model` directive to make two-way binding less verbose. Let's replace out `:value` and `@input` with it:
4+
5+
```html
6+
<input type="number" v-model="colorsNumber" />
7+
```
8+
9+
Now, we can choose how many colors we'll have in our guessing game! As a last touch, let's add a label to our input field and set up minimum and maximum for it:
10+
11+
```html
12+
<label for="colors">
13+
Enter number of colors and press Enter:
14+
<input id="colors" type="number" v-model="colorsNumber" min="2" max="10" />
15+
</label>
16+
```
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { ref } from 'vue'
2+
3+
export default {
4+
name: 'App',
5+
setup() {
6+
const colorsNumber = ref(3)
7+
8+
return { colorsNumber }
9+
}
10+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default {
2+
name: 'App',
3+
data() {
4+
return {
5+
colorsNumber: 3
6+
}
7+
}
8+
}

src/tutorial/src/step-n/App/style.css

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
* {
2+
margin: 0;
3+
padding: 0;
4+
}
5+
6+
#app {
7+
font-family: Avenir, Helvetica, Arial, sans-serif;
8+
-webkit-font-smoothing: antialiased;
9+
-moz-osx-font-smoothing: grayscale;
10+
text-align: center;
11+
color: #2c3e50;
12+
}
13+
14+
label {
15+
font-size: 18px;
16+
}
17+
18+
input {
19+
font-size: 18px;
20+
padding-left: 5px;
21+
width: 35px;
22+
}
23+
24+
.panel {
25+
color: white;
26+
background-color: teal;
27+
transition: background 0.5s;
28+
}
29+
30+
nav {
31+
display: flex;
32+
height: 30px;
33+
justify-content: space-between;
34+
align-items: center;
35+
padding: 0 20px;
36+
background-color: white;
37+
color: teal;
38+
font-size: 16px;
39+
text-transform: uppercase;
40+
}
41+
42+
nav button {
43+
text-transform: uppercase;
44+
padding: 0 8px;
45+
height: 100%;
46+
font-size: 16px;
47+
background-color: white;
48+
border: none;
49+
cursor: pointer;
50+
color: teal;
51+
}
52+
53+
nav button:hover {
54+
background-color: teal;
55+
color: white;
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<main>
2+
<div class="panel">
3+
<h1>Guess the Color</h1>
4+
<h2>Number of colors: {{ colorsNumber }}</h2>
5+
<input type="number" :value="colorsNumber" @input="colorsNumber = $event.target.value" />
6+
</div>
7+
</main>

0 commit comments

Comments
 (0)