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.