|
1 |
| -# Conditional Rendering |
| 1 | +# Listening to Events |
2 | 2 |
|
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. |
4 | 4 |
|
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 `@`: |
66 | 6 |
|
67 | 7 | ```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 | +/> |
98 | 13 | ```
|
99 | 14 |
|
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`). |
0 commit comments