Level Up Your HTML: A Playful Introduction to Alpine. js | Stephan Haewß | Skillshare
Search

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Level Up Your HTML: A Playful Introduction to Alpine. js

teacher avatar Stephan Haewß

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Introduction and Overview

      2:12

    • 2.

      Why and how?

      3:10

    • 3.

      First project

      3:52

    • 4.

      Integrate Alpine JS

      6:05

    • 5.

      Counting up with a button

      7:25

    • 6.

      Quiztime

      3:17

    • 7.

      Refactoring

      4:39

    • 8.

      Rendering answers

      4:41

    • 9.

      More on loops

      8:18

    • 10.

      Let the user input the correct answer

      4:12

    • 11.

      Checking the answer

      3:58

    • 12.

      Output correct or wrong in HTML

      4:14

    • 13.

      Next button and x show

      4:32

    • 14.

      Open the end dialog

      7:45

    • 15.

      Counting points

      5:01

    • 16.

      Improving the evaluation

      4:04

    • 17.

      Restarting the game

      5:40

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

5

Students

--

Projects

About This Class

Learn the most important fundamentals of Alpine.js through a mini-game.

Ready to take your web development to the next level? In this course, you'll learn everything you need to know about Alpine.js to create dynamic and engaging user interfaces. Whether you're just starting out or have some experience, this course is perfect for you. I'll guide you step-by-step through the fundamentals of Alpine.js and show you how to add interactive elements to your web pages with just a few lines of code. You'll learn how to bind data, handle events, create components, and more. Course content:

  • Introduction to Alpine.js: What is Alpine.js and why should you use it?

  • Installation and configuration: How to set up Alpine.js in your project.

  • Basics: x-data, x-text, x-on, x-for, and other important directives.

  • Data binding: How to synchronize data between your HTML and JavaScript.

  • Events: How to react to user interactions.

  • Practical examples: Let's build a small quiz game together that you can expand upon.

Who is this class for?

  • Beginners: Are you new to web development and want to create your first interactive projects?

  • Advanced: Do you want to enhance your existing web projects with dynamic elements?

  • Anyone who wants to achieve results quickly and effectively: Alpine.js is the perfect choice for you.

Meet Your Teacher

Related Skills

Development Web Development
Level: All Levels

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction and Overview: Hello, and welcome to my course. Let's dive right in with an overview of the course and why you should even bother with alpine dot js. Why pin dot js? That's a quick question to answer. Why do we use scripts in webpages to bring static web pages to life? Without scripts, a webpage is usually not very interactive, not very dynamic, and not very user friendly. So the goal is to create interactive elements, have a dynamic state, have data binding so that changes in the data are immediately visible in the HTML, improve the user experience and simply be able to program in HTML, in this case, with the help of alpine Jaz because it is actually possible to use Alpine Jaz exclusively in HTML. Although we won't do that here entirely in this course, it is possible and to make small things on the web page dynamic, it's a great way to quickly and easily breathe life into web pages. What is alpine Gs? Alpine Gs is a lightweight JavaScript framework. As I said, minimal code is the motto here, meaning you can achieve a lot with very little code and you can extend the HML functionality directly in the HML code using alpine Js attributes and then ultimately also mini scripts that you can then write directly into the attributes. What can you expect in this course? In this course will cover the basics of alpine dot js. Since this is a short course, more advanced topics won't be covered, but you learn how to define components in Alpine js enable data binding or synchronization of states from JavaScript to HTML. Then of course, the dynamic showing and hiding of elements and naturally also processing of user inputs, which is, of course, essential to ensure appropriate interactivity. That's pretty much it for what to expect here. As I said, a short concise course, but here you learn the basics of Alpine JS and how you can start making your web pages more interactive, more dynamic, and all that with a relatively little effort. 2. Why and how?: In this video, we're going to take a closer look at Alpine JS, and we'll do that directly on the alpine dot js website. You can find it at this address alpinejs dot Dev. Here you see the logo and a brief description, your lightweight JavaScript framework and the G Started button. But let's take a closer look at this here. What is Alpine GS all about? Well, to put it simply, it's a new lightweight framework, JavaScript framework, but the special thing about it becomes clear in this short HTML section. The script is included. It's just a JavaScript file that you can get from this address or from other places also. You can also download it from here and put it on your own server. But the important thing is, once you have done that and included it here, you can use attributes like this here in HTML. That's pretty cool because you can essentially operate within HTML only. We won't do this exclusively in this course because there are practical reasons why you might not want to write everything in these attributes or at least because it's often nicer to outsource this to actual script file. Are various arguments for this, including that it's easier to format and edit. Auto completion is also available in the corresponding script files and not necessarily here in the HTML. You can also write the whole thing in typescript, transpilot and include it here via Script tag while still using these alpine attributes. We'll look at that too. Important thing here are these attributes. This is a shorthand for event handles, for example, and you can simply write them as attributes on any element in HML. Then you can write JavaScript code within those attributes. You can also do this with the onclick attribute. For example, it exists in normal HTML. You can write JavaScript expressions or code also there. But the special thing here is that you can store a state or data here that you can then access and you can easily implement two way data binding this. Look at how that works in the next videos, but here you can already see how to program with alpine dot js. You have to set these attributes. I can already tell you that this X data is what is crucial for marking a component or element as an alpine Jaz component. Inside, you can then specify an object. This object is then available as a state inside this component. This makes the whole thing an alpine Jazz component. Not as versatile as Rx or view JS, but for limited interactivity and dynamics, you can integrate alpine JS very easily and you can even implement more complex things with it. If you're interested in the documentation or how to get started, you can read it on this web page, but we'll go through it in our project anyway. We're building a small quiz app that a user can complete. There will be a small evaluation at the end, and it's basically an interactive application where user input is evaluated and things happen accordingly, which are then rendered in the HTML. We start that in the next video. 3. First project: Going to start by creating a new project using NPM create IT. You should now go to a terminal. I'm in the terminal within a Visual Studio code in the parent directory, where we want to create our project. A subdirectory will be created here and the new project will reside within that. As a prerequisite, you'll naturally need no Jazz, of course, which I've already mentioned before, and you need to install that beforehand, of course. Anna, I have Visual study code here and you can use that or any other IDE you prefer. That's entirely up to you. I'll be using Visual study code here in this course, and I'll demonstrate everything using this IDE. Let's get started. I'm in the terminal, as I said, in the parentactry, and we now type in NPM Create VT. If you have no Jazz installed, this should already work. You might be asked if you want to install a certain package. I've already done that, so it's not necessary for me. Therefore, I'll be asked directly for the project name. If you're prompted to install a package, just say yes and you will get to this point too. Name this first project alpine quiz, and that will be our first project, a small quiz game using alpine JS. Now we can choose which framework we want to use. Alpine isn't listed here, so we'll just choose vanilla, which means just plain JavaScript without a framework, and then we'll add alpine later. We don't want to use typescript here either, so just choose JavaScript here. I'm going to use only JavaScript throughout this course. Okay, that's it. The wizard is complete and now we just need to do what is listed here. CD alpine quiz to navigate into the directory, and then we can just run NPM install. This will install all the node modules we need. There aren't many, since we're not using a framework, it mainly installs T and the VT def server. Now we're finished. Let's quickly take a look at what was created, Alpine quiz here, the folder. Here we have all the node modules, and if you look inside package Jason, we can see that there isn't much in it. As I said, def dependencies only contains VT here. We don't have any dependencies at all, meaning at runtime, we are currently completely independent. We'll add alpine later, but for now we just have VT as the DF dependency here. That's not so important for you right now. It's just for development and so we have a server for testing purposes. Speaking of testing, you can now enter the last command listed here NPM or Run the Def and that would start our server or def server here. Will be accessible at this address and I'll switch over to the browser. You can also click Command or Control here. Command click on Mac and on Windows, it is Control click. Here we have the demo page with a button that counts up when you click on it. We don't need this functionality, so we'll delete everything here. Let's have a look at index HTML. Here, this first script main dot js is loaded as Type module. That's also important. Here's an ES six module. We can remove that for now because for our first project, we don't need module makes it easier to define global functions that can be called than in HTML. Let's remove the type module for now. Then we go into main dot JS, delete everything in here. We don't need it anymore and counter JS, we can also delete here. We'll implement everything in Alpine Js. Good. Now we have cleaned up here and that's our starting point and in the next video, we'll include alpine Js using a Script tag. 4. Integrate Alpine JS: As promised, we're now going to integrate alpine jazz. For the first time, we'll accomplish this by using a script tag, which I'd like to place here at the top within the head. Right in between these head tags, I paste it in. Now we also need the source for alpine where we can obtain it. It's actually quite simple. We just refer to the Alpine Js website and here we'll find out how to accomplish this. For example, I can just copy the first line here directly and then paste it here in our HTML. Here we have it, so we have everything that we need, and of course, you can use HDS here or you can leave that out, but since you're likely to use TPS, anyway, you can write it out explicitly, otherwise, for HTTP pages, you'd use HDP, or you leave it as is. What's important, however, is this defer attribute which you must include here. I ensures that the entire script is parsed and loaded without blocking the page from rendering, which means it can run in the background. Basically, you only need to copy the script tag from the Alpine JS website and paste it here and that's it. You're essentially done. Now, how can we actually use Alpine in our app? This happens through the X attributes which don't really comply with the HTML standard because for custom attributes, you'd normally use data dash and then your custom attributes. Like this data dash and then something you come up with, however, in all modern browsers, this isn't a problem and that's why we can simply use these X or X minus attributes with p can see that I have auto completion here and there are a lot of attributes here that we can use and we will cover them during the s course, of course. First thing we have to do is specify this element as an alpine component. For that, I use X data. X data indicates that starting here, there is an alpine component and we can also specify more specifically, we can define JavaScript expressions within here. For this example, we'll keep it simple and use JSON or more accurately a Javascript object. Within here, as I mentioned, you can use JavaScript expressions. For example, an object literal. To start as simple as possible, we will create a counter here. I'll write count and set it to the initial value zero. We'll essentially recreate the demo project that we have seen and this counter will be increased using Alpine Gs and also displayed using Alpine. This we also need a button. For example, we create a button here and add a plus sign and we'll add something to display the value such as a div that will just show the value. We've indicated our div with the ID app is an alpine component, and I've included some data here. This data can be used within the component. This will be a form of data binding so that I can say, for instance, that this div shows the current value of count. We do that? That starts again with X, of course. Everything in alpine involves attributes and mainly X attributes. There's a shortcut option that we won't be using right now here for some of the attributes, we'll simply use the attribute text here, so X text and within here, we'll use count. This may feel like magic, but I will also explain how it works. First, we only need to know this here I specify the data to be used the property of the data that I've specified, I define my state here in X data. I can say in the X text attribute that we want to display this in the text of the DIF. In other words, inner text of the DIF will be set to whatever value is in count and that refers to what's in the X data attribute. Now I could not only add an object literal here, but I could also add a function call that would return the object. For instance, Get data could be called if that was a global function and it could then return this object here. It's also an option. We will also use that later. But for now, we just write directly here the Javascript object into the attribute. Here in X text, we are also specifying JavaScript. We are specifying what to display in inner text. For example, I can use one plus two and the text content would then be three. Let's try that out. We're not using X data here. As you can see, it now shows three instead of zero because we are no longer using the context of X data. Here, nothing happens when I click the button because we haven't done anything for this. We don't want to show a one plus two here. We want to show the value of the counter. Therefore, we can change that to count again. This way, the value in X text will reference the value in X data. Either I write the object literal or I call a function that will return the data for me here in X data. Now we see that it doesn't show three anymore, but zero and that corresponds to the initial value of count. If I specify different numbers such as two, it will now display two. We're taking note that with X data, we specify the basis of data we want to use and whatever is underneath this can use this data. I have essentially set the context for the expressions here. In the simplest case, in X text, I just use the property of the data object and Alpine displays it in the text of the element. Now, we only need to make it that when we press on the button, we are incrementing the counter here and that's what we do in the next video. 5. Counting up with a button: Have now achieved the displaying of our state here in this DIV. Here it displays a two as if I would write the two in here, but only that it works via the alpine data binding mechanism. I have this data binding here that specifies via this X text attribute that the state should be used here. The state is specified in this X data attribute, and then here in count it is used for the text. I could, of course, add another property here, for example, count two and set it to zero. Then I can set text to count two here, if we tried it in the browser, then you see that here. The zero is shown, so the value of count two. If I change it back to count, then it will be two again. We don't need count two here, so I delete it and we'll start again here from zero with count. We just want to count from zero. What we want to do now is that when the user clicks on the button, the counter should simply be incremented by one. Works by using an X attribute again, of course, and this time we will use X minus on here. We will use the long form here. There's also a short form, and I'll show that later, but first the long form X on, and then here it's already suggesting a colon and after the colon, I can say, which event I want to handle here. In our case here, this is a button, so I handle the click event, of course. After that comes on equals, and then within that, I can write JavaScript and I should write something that will increment the counter. How do we do that? We have already used the state here with just writing count and here we can do the same. Write count and then we access the state and here we can set it to a new value. Count equals count plus one. This is, of course, the long form. You can also use shorter ways, but let's try this first. We click on the button. I accidentally remove the plus sign here, but that's okay for now. Try to click the button anyway. Then we see that the counter is incremented each time I click the button. Each time I click the button, the counter is incremented and the display here is also updated. Let me quickly fix this button here. Now we should see the plus sign here again in the button. It's still a little bit small the button here with a plus sign only, I could write maybe something like ink, that should increase the button size. Out again and this time it completely works and the button is bigger. We have our functionality here and as promised the short form, this is quite long as an attribute, so we can write that shorter. Now I write this X on click differently. This X on colon, we can leave out. Instead, we can write an at, and that's how this actually works. Here's the proof. We start again at zero and I can increase it with this button. Here we can also, of course, make it shorter because it's Java script so we can write it like this, for example, plus equals one or even shorter with count plus plus. That works as well. This is like pretending that count is a global variable and that is the magic of this Alpine data binding mechanism here. Internally, that works in alpine most likely by setting a specific context here. There are several possibilities in JavaScript to do this. I haven't looked it up, but for example, you can embed the whole thing in a function call and then count would be a parameter that is passed here. Then you can, for example, use a proxy object. You can also work with a keyword width, which sets the context of the code in a block. However it works in detail in principle, Alpine takes this string here, evaluates it probably with new function. I can briefly show this here in the debugger in the Def tools so you can create a new function object in JavaScript. You don't already know it with new so with this new, you can create new objects. Of course, function is the constructor for functions and with this constructor, you can specify a parameter, and in this parameter, you can provide the code that should be executed inside the function. For example, I can write here an alert, so alert, hello, for example, I sign this to the variable, the global variable fun. As you can see, this fun is a function object and you can also see the code that is inside this function. Of course, I can also call this function that I have created, and then of course, there will be this alert that I've written in there. Here, this alert hello, it's just working like a normal function. Similar in alpine, this is evaluated. What we write here in this at click attribute is evaluated during runtime. How exactly in detail Alpine is doing this, we won't need to know here. But what we need to know is X minus data, we're setting the context and then we can access this context in the alpine attributes like we do, for example, in objects with this, but we don't have to write this here in the HTML. This is doing alpine for us so we can just write, for example, here, count and refer to this context that is set in X data with I can not only access the value of the context variables, but I can also actually change it here and that's what we are doing here. Then the data binding is taking over and is refreshing the display here of this count property in this div and setting the inner text of this dif. Now we actually created our first interactive application with Alpine GS. It's just a simple counter for now, but that's basically the new hello world for frameworks anyway. If you have managed this here, then you basically have data binding in Alpine GS up and running, and that is what we actually want here. Basically, we want a state here that is automatically rendered and always updated when something changes. Unlike other frameworks, you don't have to work with special functions here, with setters or Getters function or anything else. You can just write JavaScript here inside the attributes and you don't even have to use this here. Instead, this works automatically inside the dometre. Here at the top in the uppermost component, I specify the data structure, the object that should be used here and below that, I can then simply access the properties like that. First application, so to speak, but we won't continue this application, meaning we won't be implementing a second counter or reset for the counter or anything like that here. But we will start with another application with a short and simple quiz where the player has to answer questions and then switch to the next question and answers this and then at the end, there will be an evaluation. We start that in the next video. 6. Quiztime: Now starting our mini quiz using alpine JS. I've slightly modified our small counterexample, but it's still fundamentally the same. I've just renamed some variables. Count is now called current question number and the code has been updated accordingly here. Similarly, this click event operates the same way as before, but now it references current question number. The button label has also been updated to next question. Apart from these changes, everything else remains the same. So what are we aiming to do here? Essentially, the goal is to present multiple questions to the user where they must select the correct answer for each. At the end, the answers will be evaluated. To achieve this, we need a way to track the current question number as an index for the questions and their answers. For this, we've set up current question number, which represents the current question being answered. Initially, this point to the first question with the index of zero. Next, we need an array to hold the questions. There are possible answers and the correct answer, of course. I'll start by creating an array named questions here. Each element in this array will be an object. For instance, the first question could be, what is three times three. A minor issue arises here because I'm already using double quotes for the strings, so I need to switch to single quotes inside the object. However, we'll address this issue later in a way that eliminates it entirely. Let's write the first question. What is three times three straightforward question that most elementary school students could solve. For now, I'll skip defining the possible answers here and focus on displaying the current question. Below the question number, I create a div to display the question text using X text here. I want this to dynamically show the question based on the current question number index. So questions and then current question number as the index. Let's add another question to make the quiz more interesting. For example, what is four times 11? That should be manageable also. When the user clicks next question, the counter will be incremented and the displayed question should then update. Let's test this functionality. At first glance, the counter still works, but the displayed text shows object object. This happens because we haven't specified which property of the object we want to display. To fix this, we need to access the question property here. And then this should be fixed. After making this adjustment, the quiz works as expected. The first question, what is three times three is displayed, clicking next question, updates it to what is four times 11. However, if we click next question, again, we encounter an error because there is no third question in the approach works, but it gets more complicated as we add more questions and more code. Writing everything directly into the HTML becomes cumbersome, especially when dealing with quotation marks. To simplify it, we'll switch to using JavaScript. We'll define a function in main Dogs to return the questions as an object and refactor our code accordingly. 7. Refactoring: In this video, we'll do a little refactoring, as I've already mentioned. Inside here, we have a rather large object in this attribute and it's not ideal to write in HTML such a large object because you always have to be careful that, for example, the quotation marks are correct. This is why we are going to replace this with a function call and this function call will return this object. That's why I'm cutting it out here now and then using a function call maybe get game state, of course, I need to define this function now and we'll do that in main dot JS, which is currently empty. So just function and that will be a global function, of course, because we are not including this as a module. Let me show you quickly here. This script tag has no type module, so this is why it's integrated like a normal script file. Everything I write in here is global. This is the object and we can now simply return that from this function. Game stage and my formatter has already made this a bit nicer here and I'm simply returning this object. What is noticeable, for example, my formata also has rewritten these quotes accordingly, so no more single quotes but double quotes. But of course, you can also use single quotes here if you since we're here in a normal JavaScript file, this is no problem. You can use double quotes or single quotes. Also a big advantage, I can use my formatter here and everything that I have normally in JavaScript. For example, I could also write this in typescript and then transpile this file to Javascript. I can comfortably here at the answers and this whole object becomes even more extensive, so it's good that we have it here in a normal JavaScript. Answer will be the wrong one. I will write ten here and then the next one will be the correct one, which we also have to mark here in this object. But first, let's get all the answers here. The correct answer is nine, and then the third answer will be 33. Now for the first question, we have the answers and for the second question, we can do the same and we will change the answers here. Accordingly, of course, this time it will probably be the first one that is right. We just take the first one that is the correct one and then we add two wrong one. 111 is false, and also 33 is false. Okay. So now we have expanded the whole thing a bit so that we have the answers also, and I want to render it here. So below that, there will be the answers, and I also want to do something here. For the question, I write the number here before the question. So we have the call question number. So I will use two string here. To make the convert the number into a string. Then I also have to increase, of course, the number before I do that. Current question number plus one and then two string, and then dot and space and then the question text. Now we have finished the refactoring in get game state and that should still work. Let's test it, and we also here the count question number output. We can remove that. We no longer need that because we have the question number in front of the question. Next question, and we have the second question. What is four times 11? So very nice, it's still working as before, and I'll remove this div. As I said. We don't need that anymore. Again, what did I do here? Current question number is initially zero plus one is one, and then we have the dot and space and then the question text. For the refactoring, we outsourced, so to speak, this whole object definition here into a function in our main dot JS. In this function, we just return this object and this way, we can use normal JavaScript in a normal JavaScript file and we can get the data here by calling this function side the X data, we can also use window dot get game state because it's a global function. This will also be on the global object, the Window object in the browser. Then we also have the answers here now. We haven't used them yet. We just wrote them here into the objects. But in the next video, we will output them in HL. 8. Rendering answers: Now we want to display and render our answers here. And for that, we first need the option to display something at all below this question that we have here. I would say that we will show only one answer here, the first answer for testing. I write this Diffie with X text, and for X text, I'll write questions, current question number, and then answers. That's the name of our array with the answers. And then I would just take the first one here, and then inside, we have the text of the answer. Now we can copy this for the second answer and below the third. Now all three answers should appear below. I've put letters in front of each answer so you would enter AB or C here, or maybe later on, you probably enter 109 or 33. We have to see about that. But here, the three answers are already listed and when I click next question, then I have the three other answers that belong to the second question. Quite nice, but I'd say it's not quite optimal that we have to list all three here. What would be nice if we had something like four for each or map or something like that so that we are independent of the number of answers in each question. Could be a question where there are four answers or only two, and then we would have a problem here, and that's why we want to do it differently. Does Alpine have something like that, like a loop? Yes, it does, and it looks like this. I'll just copy it because it's a little too much to type and it's done via the template element. Template is an HTML element that is not rendered at and we use it to implement our loop. This all works here, of course, with an X attribute, so X minus four, and within that, we write JavaScript in principle. So we have the answers in questions, court question number, dot answers and dot answers is the array. So we have here answer in and then the answers array and in JavaScript we can then actually make a corresponding four loop. So if you would use standard Javascript here, we could write four, answer in answers, and then do something like that, and that would be the loop body. Alpine, it is like this. I only need to write this here X four, and then here I only need answer in questions and then dot answers, so the array that belongs to the current question. Then I would have my loop body here and I'll do that by writing my div in here. This div here, it will be multiplied, so to speak. I have a loop that multiplies this dif for me so I can output it multiple times and of course, as often as this loop runs. How can I access what is, for example, the answer text inside this? I can just use answer I would do in a four loop in the loop body, I could then just use answer here and then simply write answer dot text, and the whole thing is then the text for this div. Of course, this div will be output as often as there are elements in this array. The important thing here is X four, and this way of writing it, answer in answers so that can be any array here. Let's test it and we can see that it works just like the fixed output of these three divs here and only that now it is through the loop I could now add another answer here so that we can see that we have some benefit from using the loop. Here I simply add another answer. Let's say D 15, which is of course, false. A is the correct answer. Let's have a look. This is the first question that has three answers, the second question then has four answers, and this works the same. In the code, we didn't have to change anything so that all works by changing it here in the HTML. The important thing is this template element, you have to use it for the X four and this attribute, of course, X four and the way of writing it like this. Answer in questions. Answers. As I said, any array can be here, so it can also call a function that returns an array or whatever. Here an identifier that must be valid, of course, for example, here answer in this case, and then it works and these dips are then output as often into the dome as this array has. Otherwise, we didn't have to change anything, only this has been addited here and with that, we can then output our answers here. Again, the important thing is X four and this way of writing it. 9. More on loops: This video, I will further explain loops building on the previous example. I clarify some crucial conditions and attributes here. First, two key conditions for these loops, the X four attribute must be on a template element, as I said before, not on others. You cannot use a div and X four together, that won't work. This is one requirement. Another one is only one root element is allowed inside the loop, so two or more elements directly inside the template element are not allowed. If you want to do something like that, then you can put a div around these two other divs. For example, maybe you want to specify another property of answer, for instance, correct or correct answer. This would indicate the correct answer, but I won't use it here. It's just an example. I have two properties to output here, so I need a single root element inside. I must not have two or more elements at the same level that's not allowed and will cause a what else should you consider? There are two other ways to use this. You can also specify an object instead of the array. For example, you could use answers at index zero. This is an object, or you could use this questions at court question number, which would output the properties of this question object. This is not exactly how it works, but there's another way to do this. If you already know JavaScript destructuring, you will understand. It's about destructuring the returned object into two parts. This returns something containing the property name and the property value. Question, colored question number is, of course, an object. Let's have a look at that. Here are our questions and this object is in the first entry, and this is the object from the second entry in questions. We first get this object and we can then destructure it into its components using this syntax here. First thing we get here is the value of this property. For example, question is the first property and the value is this string here. The first thing I get here as answer in this case is this string. Second property is answers. This is an array containing objects. If I use prop name as the second property, it should be correct. This means I would get question and answers as the property. Rename answer, that would be, let's just call it value. This is the property name of the object, and this is the value. Let's see what happens. We have questions and answers here. These are the property names. Check again in main dot js. This object is in the first question. It has the properties question and answers. That's what we output here, the property names question and answers. If we want to output the values, we can also do this. Instead of prop name, I output value. Then as the output, we have first this question the value of question and the value of answers is an array. This is the output of it, not very helpful. But in principle, this is correct. This is this array and this is how it is displayed. The two string of this array is what you saw. As I mentioned, this isn't useful here, not in this case, so I'll undo this, but you can use this syntax here also with arrays to get the current index of the loop. We iterate through answers in this loop, each was an object containing text. We output this to the div with X text. But if you want indexing, so one, two, three before this answer text, we can do the same as with objects. The first here is answer still. This remains the same. This is the value of this array entry and the second is the index. We can also use this here. For example, index plus dot, I need single quotes here, of course. A space and then answer text, and actually, we need to increment index by one here. Let's see how this looks. It works one, two, three. It's a bit awkward having first, second question. Here and then the answers also use first, second, third. This could be confusing. Therefore, let's indent this and remove the ABC numbering. First, again, about the index, this is how you get the index when iterating. If you need it, you can use the parenthesis here. The similarity to Javascript ends here. This syntax here doesn't exist in JavaScript. But in alpine, this is how you get the index. JavaScript four of loop also provides the index, but there you'll need square brackets slightly different. So don't get confused for alpine, use this syntax here. First, the array element. Second the index. Similar to a for each loop, let me show you. A simple array of numbers, I can call for each on it. This is an array method. I need to provide a callback here and the first parameter is the current array element. Let's just console log the element here. If I need the index also, it is provided as the second parameter of the callback. Let's just output the index first and then the element, and this is separated by a space. Let's see the output, so one, two, four, and before that, I have the index here, 012. It's very similar to this alpine syntax. First, the current element in the loop and second, the index, and then follows the in and the array or also, as you have seen an object. In case of the object, the index is the property name and the value is then the first parameter here. I hope this is not too confusing. We need the index here also because we want this numbering here before the answer. Let's remove the letters here. Let's indent the answers a bit. We can do this in several ways. I'm setting the style here, specifically margin left, I would say. Let's set that to let's say ten pixels. Let's check it. Still not very much indented, so we can do a bit more here. Let's change that to 20 and now I would say it's okay like also adjust the vertical spacing a bit. Let's put margin bottom here. A 20 pixels looks a little bit better, but also the button should have a spacing. Let's put margin top here on the button and that looks okay. What is nice is also that the numbering here is automatic, so we don't have to put the letters in front of the answers. We are able to do this because we also get the index here with this syntax from the one more thing for lists or arrays that can change order or have deletions to prevent side effects, use a key. Here you can set the key with this attribute. Colon key. If you know react, you can also set the key prop there and this helps Alpine identify the entry. Here you can set something like an ID, or in our case, we can take the index here for the key. We can check what effect this has on the dom if we look at this div here, we see there's only this attribute colon key. It is not used as an attribute on the divs here inside this container. It's just used internally helping alpine identify and correctly manage items, especially here in these loops. Using keys is crucial, particularly with dynamic lists where order might change or items are deleted. While the index works, consider using existing IDs maybe from the database, something like that. If there would be an answer dot ID, you could use that here, but we don't have that, so we're using the index. 10. Let the user input the correct answer: Before adding the input, I'd like to refactor using a flex layout to avoid using margin top here. I set display to flex, you're unfamiliar with flexbox simply follow along. We use Flexbox here to easily create spacing with a gap property. Gap 20 pixels, the gap property defines the space between the direct child elements. Therefore, we need to set flex direction to column, otherwise it would be row, which is horizontal. We have display flex flex direction column and a gap of 20 pixels. This creates a 20 pixel space between each child element. To group these elements, let's wrap them in a div and here we have the button. Let's remove the unnecessary margins here and then check if everything works as expected here, and I think that's it. Let's see if this works. The button is a little bit too wide here. This is because we're using flex here and the default is to stretch in the other direction. But that's easy to fix. We set the width of the button here to, let's say, maybe 60 pixels here. So that looks a little bit too small, so 100 pixels. Yeah, that's okay. Instead of next question, we should probably label it something else like commit, answer, something like that because the answer will be recorded and checked. But let's first add a div for the input field. This div will also respect the gap within the flex layout. Inside this div we'll create a label for the input field. It's good practice to always label form elements. Let's call this label correct answer. Now let's add the input field and set its width to 120 pixels. Looks okay, but to improve the layout, let's also make the label of flex container with flex direction column here. Display flex, so that label and input field are arranged in vertical direction. I think that's okay. The user can now enter the correct answer and instead of next question, let's use a more neutral label like, Okay, we need to adjust the event handler here to check the answer, but we'll do that later. But now let's focus on retrieving the user's input. Alpine jazz, we use the X model attribute to bind the input fields value to a data property. We can use X model with input, select, and also text area elements. Here I write the property of X data, which should be bound here to this value that is entered here. Let's call it current answer. That's a good name. Current answer, and then I would say, let's also enter it in X data here with an initial value. So we set current answer here to an empty string. Then we can see immediately that this also works here with this data binding with X model, I will simply make another div here and there I will simply set X text again to current answer. I enter some text here and we can see the data binding is working. Whatever I type here in the input field is reflected in this div where I set X text this current answer. Whenever something changes in the input field, then current answer is updated and also this div is notified or Alpine is notified that there's a change and it reflects it into this DIF here. Now in the click handler of the button, I can also access this current answer and I log it here. If I click Okay, then you see that this is locked out into the console. Still also the index to the question array is also incremented, so we get to the next question here. That is still need to remove that. But for now, we have shown that here I can access this current answer that was input here in the input field and now I can evaluate the current answer and see if this is really the correct answer or wrong answer, and this will do in the next video. 11. Checking the answer: This video, we want to verify the answer. Here in this click handler, this is where it will happen. Right now we only have the console log and the incrementing of the current question number. We will remove this now and instead I call a method or a function and this function will be called check answer. I can write it like this or I can also call it here, so that's the same. Where do we have to write this method or this function right here in our game state object. Here we also have our variables, so to speak, current answer, or state variables here, and the questions now I simply add this function here, check answer, but just do it above here. We can then choose the syntax accordingly as it works for object literals, you don't need to use function or arrow functions or something like that. Write it like that. Simply the name brackets with parameters, we don't have any here now. How can we check the answer here? I simply write if this dot current answer, this is how we access the current answer state here equals and of course, we have to know what the correct answer is, and I'll take first this dot questions and then the current question number, of course, then I have the current question object. This question at this current question number dot and then correct answer index. This is something we don't have at the moment, so I have to insert it here. Answer index is in this case, for the first question, the second answer is the correct one. Quick refactoring here, this is a little bit too long, so I'll take this and make an index variable here. I have this correct answer index, and then correct answer is this dot. For that, I need the answers array, so I will also save the question object here in a constant. The question is this, and then I can refactor this Question, correct answer index, and then here I can take question dot answers with the correct index here. This will be the correct answer and I don't need this second variable here. This is the final version here, and now I can check this current answer equals correct answer, and in this case, I just put an alert here. Correct. In the else case, I can use also an alert with the term wrong. Here we check if the current answer that the user input is it equal to the correct answer the correct answer comes from this correct answer index into the array of answers. Of course, we have to set the correct answer index for each question, and the second question has the correct answer index of zero because the first answer is the correct one. Let's try this. We have the first question. I enter nine and the answer is wrong. That's not correct. Let's see what the problem is here. We set a breakpoint. Let's check if we have the correct question here. Yes, I think that's correct. Yes. Let's see what the correct answer is. This current answer is nine, but here we have an object, correct answer is an object. We have forgotten to put the dot text there. Let's change that here, correct answer, dot text, and now it should work, correct, then we have the wrong answer is also correctly evaluated. But I would say we don't display this as an alert here, but we have to display it inside the HTML. Also the player needs to go to the next question once this answer is committed and this we will implement in the next video. 12. Output correct or wrong in HTML: This video, we want to get rid of the alerts. We have now indicated at the moment that the question was answered as an alert here, and that's not very nice because everything is blocked then. So we want to get rid of this here and then output the whole thing correspondingly in HTML. To do this, we add another div below this, and into this div, we want to write something, a message, and we know how to do that. I said X text to message. This is a state that we need to define, of course. It's not existing at the moment, so we add it just here and initially this will be an empty string. Nothing is displayed at first, and when we have then determined whether the answer is correct or wrong, we can simply set this to this string here. This dot message equals correct in this case. So be careful to use this dot message here, not only message. This is how we have to do it here in JavaScript. If you put it in the attribute in HML, you don't have to write this dot, but just message. For the other case, this is just the same with wrong as the string, and it should already work. Let's check it. So wrong answer, correct. And now the correct answer and correct is displayed. So this works, but the problem is I can still enter a different answer here, so we have to disable this and there is a corresponding attribute in HTML, so we can write input disabled here. Let's put it here, disabled. This attribute makes sure that nothing more can be written into this input field. Let's see how this looks. I cannot enter anything here anymore. I cannot set the focus in to this field. I cannot type anything. Of course, it doesn't make sense to have that disabled from the beginning, so we have to control that now through alpine. For that, we can use X minus bind and this binds an attribute of this element to a data binding expression to specify which attribute we have to put a colon here, this is also what is suggested here and there after the colon, we have to put the attribute, in this case, disabled. We need, of course, to set this to a Javascript expression. In this case, if this Javascript expression is true, then this attribute will be present on this element and if the expression is false, then this attribute won't be there. What do I have to write here now? I would say we just add a property and then we can just say input disabled and set this in our method. The initial value should be false. Let's put it here, input disabled, set to false because the user has to enter data here at first, and then when we check the current answer, if it's correct, after that, we can set this input disable to true and after that, the user cannot input anything into the input field anymore. Let's check this. So I put in the correct answer, and here we see that this is disabled now. So this works. We can also see that here disabled, the attribute is present on the input element and it is set to disable to the string disabled. Of course, we also have this X bind disabled, which defines the data binding. So this expression then evaluates to true, and then Alpine Js is adding this attribute here with the value disabled. That's what we wanted to achieve. We wanted this input field to be disabled. That means that here I can use two or false, at least with disabled to indicate whether it is there or not. Now here we have to switch this button to be the next button that goes to the next question after we press the OK button, then there should be a next question button here. I think the easiest way to do this is to add a second button and if this answer is committed, then we show the new button and we hide the old button here. This is what we do in the next video. 13. Next button and x show: This video, we're going to focus on displaying the next button. To do this, let's duplicate this button here we already have I simply copy this and paste it here again. This will be the next button. Of course, it won't check the answer here, instead, we can think of a new method. This method will be called next to simply move on to the next question. We can leave the rest as it is for now. Now we need to show either one button or the other by default. It's this one, the Okay button, and then O is clicked, then we have to hide it and show the new for that, alpine has a great attribute that of course, starts with X and it's called X minus show. X minus how does exactly what it says. It shows this element or it hides this element depending on what the expression that we said here is evaluated to. If the expression evaluates to true, this element is shown and if it evaluates to false, it is not similarly need to add a new property to our state and I'll just call it show next button. If show next button is false, then o is displayed and the next button is, of course, not displayed. Here we have to change it to show next button. I show if show next button is true. That means if we change this from false, which will be the initial value to true, then this will disappear and the other button will be displayed. We just need to add this show next button property to our data to our state. We can simply do that here. The initial value will be false, and then we check the answer here and we have to set this dog show next button to true. Then at least this alternating display of the buttons should work. Let's test this. I'll enter the correct value here, press and we see that the next button is indeed displayed. But click on this now, we'll get an error because the next function is not yet defined. No problem. We can simply add it here below check answer. Let's create a next method, which will just increment. We did this before in check answer, but we will do it now in the next method. Current question number should be incremented by one. We can do it this way. This is the shortest or maybe plus equals one is also a valid method, or this is the long version here, can also do it like that. I will leave it like this plus equals one. This will increment current question number by. So let's check if this works. So correct answer. Okay. And then we have the next button, and if I click on the next button, we will have the second question. So that works, very nice. But I have to reset this here, so this correct answer field needs to be empty again and it also should be enabled, not disabled. So here, you have to do a reset show next button should be false again, and also this input disabled should be also false. So message should be reset to an empty string. Let's check this next. So we haven't reset this input field value, but still we can enter here the second answer, this should work. And now, if we click on next again, this should give us the error again because there's no next question in the array. Okay, so let's reset this current answer. Here we have it, current answer, and then this dot cart answer should be an empty string. Also, there was this div that we don't need anymore. So this here, we don't need that because we have the other div that displays the message, so we can erase it and let's check again, correct answer and also correct answer and then this works as expected and also the error here is expected. If next was clicked on the last question, we need to go to the evaluation and not to the next question. Also, we need to track the points that the user is getting for the correct answer. So maybe the first question is a little bit easier than the second question, so there should be more points for the second question. And then in the evaluation, we will summarize the points there. And depending on the number of points, there will be a rating of the user's ability. 14. Open the end dialog: This video will focus on opening the dialogue that displays the evaluation. There are several ways to create such a dialogue. Of course, there's the HTML dialogue element, but we won't use that here because it's a bit more complicated to use that with alpine Jaz. The reason is that you have to open and close this dialogue element with a method call and it is possible with alpine to do that, but it is easier to do it without that. We use a div here or rather two divs. These are two nested divs, this outer one is basically the entire screen. It will fill it and at the same time it's also the backdrop, so it will be a slightly transparent gray background color. Inside here is another div that contains the actual dialogue. We'll see what that looks like soon. For now, I will put an H one tag in here and write result for now. The outer div, we need to display it somehow and for that, we already have X show, which we know. I would say we simply call this open dialogue. A new property that we need to add to our data. So here, open dialog will be, of course, false initially because the dialog shouldn't be there when you start the game. We want to show the dialog if the user clicks on the next button and there's no more questions. So here I have inserted a new condition. So let's check if this is correct. This current question number greater or equal to this questions dot length minus one, the minus one was missing here before. I think this should be correct. With the last question, current question number is one, and then we have greater or equal to questions length is two minus one is one, then this will return here. That is correct. We can do this open dialog equals true and this should open then or show the dialog let's try this. I'm giving the wrong answers here. It doesn't matter. Now we have the next and then the dialog is shown. It's only H one here, it's not centered and it's not visible as a dialogue, but the mechanism behind that, the logic is correct. We need to position this above every other element here, so we need to put that position fixed, something like that. Also that index should be a very high value, something like a 1,000. That will be the outer diff and it also gets a transparent background because it functions as a backdrop. The inner div here is the real dialog content which contains our text and the result evaluation. Styles, there are quite a few here and that's why I won't type them in here, but I copy them here. Maybe here at the end of the body, it doesn't really matter where you put it. The rules here will be found everywhere. I have the class or the rule for the class dialog here and for the class dialog content. Now we have to assign it here, of course, accordingly to the DIFS. The first one will be of class dialog and the inner one is of class dialog. Ten. So let's have another look at the styles here. So position fixed, as I said, top and left to zero width and height to 100%, so it fills the screen. Background is then this transparent black, so it looks like a bit grayish and translucent. Then display flex and justify content align items. Center ensures that the child inside is displayed centered, of course. Also important that dialogues are displayed centered on the screen. That index, as I said, also set to something very high 1,000 here, that should be enough. Dialogue content is nothing special in itself, so we've set border radius to eight here and Max with 2500, so what gain any bigger than that. Otherwise, it's 90% of the width. Why 90%? Because you want to see a bit of the background on the left and the right. Let's try it out. Answer it wrong and now we have the dialog and this looks okay. Here, the content is just this H one. We will of course change that now, but the rest looks quite okay, I would say. Of course, we need something to close the dialog a button, something like this, but I think the rest looks like a dialogue. For closing the dialog, we can, for example, set a click handler here on the background. No problem. We have already set a click handler before, and here we can just set open dialog to falls, which will then close the dialogue, of course. I would also put a button here. A click handler, and I will do the same here. As open dialog equals false. So let's try this. If I click here on the button. Oh, there's no text inside the button, but anyway, but click outside, it works. If I click the button, it also closes. So that is working, but the problem is, if I click here on the results H one, it will also close, and that is, of course, not what we want. We can do the following. We can also add a click handler here. Here at click and we have this dollar event, which by the way also exist without the dollar, which is a global variable. T Windowt event is the current event object, but we also have this dollar event which comes from Alpine. Use dollar event here because Alpine is providing it, dollar event, I can do various things here on event, for example, I could do prevent default here, but I can also do stop propagation. This is what I'm going to do here. I call the method stop propagation on event on dollar event, and let's see if this works. So I can now click on the button and it closes, and I can click on the background and it closes. But if I click on result here on the content, it doesn't close and that's what we wanted. The stop propagation is effectively preventing this event from going to the auto Diff and then causing the closing of the dialog. This is stopping the event from pro if you write it like that, we don't have the possibility to get parameters here. If you use add event listener, then you will get this event with your callback as a parameter. But here we use this dollar event that Alpine is providing us. You can also leave the dollar and use the global event, but we are programming here in Alpine, we use dollar. Wise, this is the same object. We can also call here this stop propagation, which is effectively stopping the event to other click handlers here that will close the dialog so the dialog is not closed because the event is not getting to the other event handlers. Well, as I said, this is normal Javascript, normal Dom event handling here, no difference to the normal event object. So the dialogue is closing and opening this works, and now we can put our evaluation here. So what percentage of the maximum points, for example, the user or the player has achieved that we can put here and depending on what percentage there will be a rating, maybe a math genius or go back to school, something like this. For that, we need to count the points, of course, for the answers, and this we will do in the next video. 15. Counting points: Now let's talk about counting points. We want to have an evaluation at the end, of course, we need points for that when the player has answered a question, they should get the points credited to them. We also want to be able to assign different point values to each question. So first we need to assign points to our game state object. Here are the questions and for each question, there are also points. I will start here with the first question, there are, let's say, five points. The second question is a little bit more difficult, so we get ten points from answering it correctly. Now we need to go to the location where it's determined whether the question has been answered correctly, and that's in our check answer method at this point here. Here we have determined that the answer is correct and we have to increase our points here. We need a total score, so we create another property here called total points. It starts, of course, with zero and then it's incremented accordingly, so we can simply increment this dot total points by what? Well, we need the question, which we already have here. We got it from up there. So question dot points will be added here. Then we need to display the number of total points at the end and of course, the evaluation, but first the number open our dialog here at next and we see that we've reached the last question. Then we do next, we open the dialog and something is displayed there accordingly. The result and here on this div, we can put a span in here, total points and then after that, we can put another span there and then X minus text. Our alpine attribute here to bind the text to a property in our object in our data object and here we can simply take total points and to be sure we can also call two string here so that this is really a string, not a number, but it would also work without now let's see if that works. Let's enter the correct answer here so we can get points, correct next and then we'll enter the wrong one and that's wrong. Total points is five. And here we can see that the button doesn't have the right text yet, but the score is correct. This case is fine and we can now answer both questions correctly, first one and the second 144, and then we have 15 as the total points. That is also working. So let's quickly fix the button here. We can simply write close in here. So now we have that two total points we have as well, and now we can also make an evaluation. So for example, we can add an evaluation message here as a property, for example, and then display it in the dialog via data binding. So here is result message, and initially this is empty, of course, and here we will do our evaluation what do we write here? I'd say result message equals perfect and we only output that, of course, if we really reach the full score. I total points equals 15 in this case. If it's below that, we could write something like go back to math class, maybe not very polite, but I think that's okay and we will refine that a little bit in the next video. For now, this is our evaluation. Either it is perfect or you have to go back to math class. Let's try it. Nine and 44 is the perfect score then and we have total points but no message. We have to, of course, do the data binding here on this BIF here. We add another BIF inside this and this will be bound to our result message so that we can see the evaluation let's try again nine and 44. Now this time we have perfect as a message and now we do it wrong, two times wrong, and then we go back to math class. After total points, we can insert a white space at this point, and now we try it again and the result is looking good. It's not very detailed here at the moment, but it already works. The points are counted and then we of course still have to make sure that the evaluation is also a bit smarter at the moment, we're doing this with fixed 15 points, and we actually have to calculate total, the maximum total points because if we add another question here, it doesn't match the 15 anymore and we actually have to calculate everything first. So how many points are there in total, and then we can maybe assume a percentage of that. So if you have 100%, then this case is perfect, and if you have less than ten or something like that, then go back to math class. And then something in between and this will do in the next video. 16. Improving the evaluation: All right, let's improve the evaluation a bit. First, we want to get rid of this magic number here, 15. It's not pretty, especially if you add more questions. We need the total number of possible points here, not the players, total points, of course, but the maximum achievable score. So we can simply write perfect score here. We need to calculate that and we can do this by using reduce on this dot questions, we'll get a question, let's call it Q and then we'll return Q dot points. Of course, we also need the previous value in reduce previous comma Q, and then we simply take Q dot points plus previous, we've calculated the sum here. There are other ways to do this. I've done it with reduce here, so we simply get the sum of all points. That's the perfect score and then we can simply say perfect score equals total points, and then we actually output perfect here. Then we can also says let's say 50% or more, then we'll say something like not bad. We need to divide this dot total points by perfect score, and we'd better extract that into a constant. Let's calculate that here and this will be called percentage. If percentage equals one, then it's a perfect score. If percentage is below, no is above 0.5, then it's not bad and else go back to math class. Before we try it out, I see a mistake here. We can't do that like this. We need an initial value here because otherwise previous would be a question. That means a question object and we can't add that, of course, we use the initial value of zero here. Then it's Q dot points plus zero, and from then on previous will always be a number. Now it should work. Let's try it out. Let's answer the first question correctly, the second question correctly, and I should get a not bad here. Exactly this is what is displayed. I'll do it the other way around. The first one is correct, nine and the second one is too hard for me, I answer it incorrectly and I go back to math class. That's because I have less than 50% points and that's obviously too bad. Let's test the perfect score also. Here we have it also working. The advantage of doing it this way is that we can simply add questions here. If I add a third question here, if it points, then I automatically have the correct evaluation here. Percentage would also be meaningful and then I can simply leave this evaluation as it is no matter how many questions I more than half of the maximum achievable points, then it's not bad. I answer everything correctly, it's always perfect and otherwise, I get this message here. That's basically it for our mini game here, of course, we can make some improvements. For example, we can add a restart here because at the end of the game, we have the problem that can't restart unless we reload the page, which isn't very nice. We can add a button here that appears when the dialog is closed or we can simply restart the game directly in the dialog when it is closed. I think that makes the most sense maybe. Instead of close, we can say restart and when you click on it, you see this again and we do that in the next video. Then I'd say that's it for our first mini game here. So alpine concepts have been introduced it's by no means all of them, and I haven't gone into every detail either, but we'll do that in the next videos of the complete course. From the next section on, we'll cover the different features of alpine individually then, and I'll go into more detail about the many things you can consider. But here, you've already seen how it works roughly and how you can render data binding and your app state here and also how to process inputs, which works very well in our miniga. 17. Restarting the game: So the last feature we want to add to our game is restarting it and that will simply involve resetting all our properties to their initial values. This means I can create a method here called reset and then simply copy these properties here that need to be reset. Of course, I always have to write this in front of them and the syntax isn't quite right yet, but I'll do that now and basically just a bit of manual work. I'll fast forward this a bit. Now we should have it and that's basically the complete reset of all our properties, our states here. Otherwise, we still have the questions, but that's essentially something that doesn't change. It's just data that simply has to be there at the beginning and won't change. This here is essentially our state can change and the rest are methods that we just leave as they are. Now we need to call Reset, of course, we can do that in HTML basically where we close the dialog at the moment. Actually, we don't really need to close the dialog explicitly here, but it's enough to simply call this dot reset. I wouldn't write close, of course, but new game and then let's try this. It doesn't matter what I enter here, result, and then new game, and nothing happens. We check the deaf tools to console, and here we have made the mistake to call this dot reset and it should be only reset. Once again, let's try it next then new game and this time it works. Now we have the first question again. That's correct. We have unlocked everything here and then we can simply enter the correct answer and here too, and then we see 15 points, perfect score and this works and I can reset the game again. Of course, it's a bit boring just these two questions here. We could of course also proceed to ask other questions and then do rounds like that, that would be the first round. Then comes the second round with other questions. If you were too bad, you would have to repeat the round again maybe make it a bit more comprehensive like that, but we don't want to do that here. Instead, we just end after the first round and you can simply try again by restarting. We could also add a high score here that then is saved with two questions, of course, it's a bit silly, but if you had 100 questions or something like that in different rounds, then it would make sense. Have a high score here. You could save the high score in local storage, for example, that will be still there after reloading the page then. Let's go through it again. We can see it very well in index HTML. What we used, we used X minus text to do the data binding to the properties and of course, the most important thing here is how to define components. That means how to actually activate alpine on a component on a sub tree and we did that here with the X data attribute. That's the most important thing. With that, you activate alpine, so to speak, for this div here, in this case, for this element and all elements below. This here is the activation and there you can use these other attributes like X text or X four, this loop that's almost advanced, I would say here. Of course, input with X model. That's also very important to activate the two way data binding for input elements like in the input here and also in select and text area. Then we also have X binds, which binds any attributes to the properties that we have stored in the state and we also have X show, which shows an element or hides an element depending on whether true or false is returned in this Javascript expression. Of course, important here in all of these X attributes, you can then access the context here that was set with X data without having to write a prefix like this or something in front of it, but you can simply pretend that these are local or global variables just like we do here with Show Next button. We also looked at these event handlers, which is, of course, very important for interactions. When you click on the button, when the user clicks on the button, then this code that is in here is executed. In here, you simply have JavaScript, but you can, of course, also call methods and we did that here. This is our game state and it's all basically normal Javascript. There's no alpine in it, so it's simply an object that we return here in this function. This object, we can simply access the properties that we defined here with this dot and then the property and Alpine JS then uses this object here for the data binding and for all these connect here. I think it's very remarkable that we can simply return a completely normal object here in contrast to other frameworks that also offer something like data binding and manage our state here like that. There's really no special ingredients here. It's just very normal Javascript and you can of course also use normal JavaScript functions like reduce, for example, and you can access all the properties in the normal way with this. That means you could of course also use class here and create an object with new. That's possible. I didn't do it here, but it's also necessary from my point of view here, you can of course, do it. That's up to you because this part here really is completely just normal Javascript. There are a few Alpine GS functions, but for the basic functionality, everything works with normal plain Javascript.