Welcome to the course. My name is Gwen,
and I'm a software developer. Here is the itinerary for today. Part One will start in the
browser to get a feel for the syntax. And part two will be on a local computer building
apps as you regularly what. Along the way, we'll cover different bits of the view API so you
can get started right away. First, let's define what view is. On a basic level. It's a front end
jQuery, since it gives you specific recommended patterns for code organization. Although it did
borrow a lot of good ideas from jQuery, Angular, React, and others. It's usually not found in
the wild by itself, you'll see it used with lots of other libraries and combined to make
sort of a framework and alternative to react, Angular, and others. And we'll cover many of
these libraries today. So let's get straight into it. I'm here my browser at JS fiddle dotnet
is just another place to put front end code.
And I'm going to try hello world. So this is if I was
just writing a plain HTML or jQuery application, I might put something like this. So how do I attach
this to the view instance? Here, I've reloaded the view library. So I can just choose it from
frameworks and extensions, I'm just pulling in the latest version. And from that library, I have a
view instance. So I can instantiate it like this, and then pass it an object of options. The only
required option I have to set is element. So which element in the DOM do I want to attach my view
instance to going to attach it to route.
And then of course, I need to have a root element with ID
of root here. So now my view instance is attached to this div in the DOM. If I run it, of course, it
doesn't do anything different. So let's make it do something different. There's also a data object
I can use. And I can populate this with variables to use in the DOM. So I can say data greeting.
Hello view. Now how do I put this in the DOM view has something called double mustache mustache
So anything inside of this inside of these double curly braces view looks at a more parse
And so I'm going to render the contents of the variable, we run this again, changes to
Hello view. Another important concept in view is data binding view uses two way data binding
through a directive called v model. On an input, when I put v model, it binds it to a variable in
the data object that I give it.
So in this case, I'm telling Vue to bind this value of the input
to the greeting variable from data. If I run this, everything inside of my input is the same as
the greeting variable. And then if I change it, it live updates. extremely simple. The model
is something called a directive. There are a lot of directives in view, and they're used to
interact with the DOM.
Let's look at another common directive. V if V f evaluates an expression
to a boolean value, either true or false. So let's start with something that we know is true. So if
one equals one, you're telling view to display this div and render it to the page? Yep. So this
isn't so useful, it's usually used in combination with data attributes here. So let's make a new
data variable, we're going to call it count. So if count equals one, then display this diff to the
screen. So put my changes to count equals zero. And of course, it won't display to the screen.
Now there are other directives that you can chain called v. Else if and V else just like an if else
statement. So let me change these. Orange, just different values red.
Let's say if count equals
two. So this is pretty self explanatory. If count is one, nope, if count is to render this, anything
out, other than that render v else. So if I put two, it's going to render red, and so on. Now, the
thing to note about vi if these divs, if they're not true, they don't get rendered to the DOM at
Now, this might be the behavior you want, and many times it is view also has another directive,
called v show. So let's call this the show. There, we'll just do the same thing. If count equals
one, change Capital One, run, and it's green. Now, this time if count is two, of course, nothing
displays here. But it's actually still being rendered to the DOM, just with display none set in
the CSS. Have you look in here to kind of dig in, but you can see that there's a div with green
inside this our same div up here. And it's set to style display none. So it's still in the DOM
here. And so sometimes you want to use v if and sometimes you want to use v show, it depends
on what you're doing in the application. And if you need better performance if you're constantly
adding and removing things from the DOM.
So let's look at some more directives. I've already typed
this out to save some time, it's just an input with a submit button. You click it it alerts. And
also an email variable that is bound through the V model directive to the what's entered into the
input. To view has this directive called v. Bind, a V bind can take an HTML attribute, like
will say is less than two. So what this does is the regular HTML attribute disabled with disabled
length, and the button will be disabled only if the email length is less than two.
If it's greater
than two, then the button will be enabled. So let's run this. And you can see I can't click on
it, it's disabled. But if I type something here, now it's enabled again. So you can do this on
many different attributes, not just disabled. And there's also a shorthand, which is what
you'll usually see in view applications. So it will be just whatever HTML attribute preceded
by a colon and that's shortcut for saying v bind colon because it's so common in view. Now, another
use for V bind that's common is to dynamically add classes. So, Stu colon, the shorthand for V bind
Last. And then there's two different ways of doing it, I'm going to start with the first syntax,
which is called object syntax.
So I'm going to dynamically had this read class. And I'm going
to say, if the email dot length is less than two, I want to have a border, a red border around this
input box. So let me run that. And I have a red border. And as soon as I get past two, or I get
two or greater, then I don't. So that's how you can dynamically toggle classes. So there's another
syntax used if you want to toggle in between two different classes, which is array syntax. So we
than two, then we're going to use the class red, and if it's greater than or equal to two, will
be the class green. So let me run this. And we had the class red. And now it toggles back and
forth in between green.
There are several other directives in view, these are a bit less common,
but I just want to mention some of them. So we already know that we can put variables in the DOM
using the double mustehsan mustache syntax. If I run this, I can type and it shows up, I can
actually do the same thing using a directive called v text. When you put a paragraph tag, the
text equals email, and then just close the tag. So if you're used to jQuery, you'll be used to the
dot text that it uses to put text inside of an HTML element.
This is doing the exact same thing.
So if I run this, it does the same thing as using double curly brace. There's also the HTML, which
will parse it and we'll just put text inside. But it will parse it as HTML, similar to the dot html
and jQuery. So if I type stuff in, it does the exact same thing. But I can also type in HTML
tags. And it parses it as HTML. So what if you want to render something just once a static HTML?
Well view has another directive called v once, say once and put the email in here. Just to compare,
I'm going to copy this and put it outside of the ones.
So let me start with something initially
here. So as I update this, it only changes in the second one because it's frozen and just set as
the static HTML of whatever it was initially. The second one will still display and update as you
change the V model for that variable. So let's look at looping and view. I'm just going to clean
this up real quick. of all of this. And let's make a list an ordered list. No I. And the directive
to handle looping in the DOM and view is called v four. So let me come down here and get something
to actually loop through, which is an array of cats have already written. Paste it there. And
the syntax for this will be you need to take care of a cat's and you're gonna say, item in
then during every iteration of the loop, you'll have access to the cat variable which will be
Per index in the array.
So I'm just going to put cat here and run this again. And it comes out with
all the different cats in the array. So of course, in the first iteration, it displays in Li element
with the first cat inside, which is kick cat, at index zero, and then it moves the loop
moves to index one, and then index two, and so on, and so on. And if you look, in the dev
tools, you can see it has the full array there. Now, you can also do this with objects, of course,
these are just simple objects with one key value pair each. So now cat would equal this object with
the name inside. So to display the cat's name, now, I'd have to do cat dot name. Run it,
and I get all my cats. Great. So there's more we can do with looping. And there's
more we'll get to later when we're looking at local applications. But that's pretty much
how it works. So let's look at functions. Now, what if we wanted to add a new item to this array.
So I'm just gonna add something similar to what there was before with an input.
The model was new
cat, button. So I'll add a function to the button in a second. Let me run this, and it renders my
static HTML. That's good. Let me add this new cat. So this is modeling my new cat that I'm going
to add to this list. So I need some kind of a function to add it for me. And I can do that with
a directive called v on on click, so when I click this button, I want it to perform an action. In
this case, I want it to run the function ad Kitty, which we're about to make. So the data object is
just four variables. So to put a function here, I need to add one called methods. And this is
another object with functions inside. So add Kitty, oops, and Kitty, which is a function. And
I'm going to need to push a cat on to this array to add it to this array.
So I can access any
any data variable inside of a method by doing by using this. So this dot, cats will access my
cats array in data here. So this cats dot push, and then I want to push my new cat and my new cat,
I also have access to this. So I can say this dot new cat and I have the new cat's name. Of course,
this would work if we had just a plain array, but we actually have an array of objects. So I'm
going to put this inside of an object and then say, name is this dot new cat. So this will push
another object on to this array. So let me see if this works. ran it. Let me add and I can't press
Enter right now.
But when I click the button, it adds it pushes on to my array perfect. Of course
it's kind of annoying to click Add every time. So what if I want it to respond to an enter as I'm
typing, so I can quickly add more kitties. I can actually add another event with V on again but in
this case I want v on key up and then equals add kitty so I want to run the function add kitty on
kiya. So let's run this and see What it does. So unfortunately, though, I didn't tell it which key
up. So any key that I press is just adding a new cap for each one, which isn't the functionality
that I want.
So I can modify this key up by saying key up dot Enter. And we run that their key up
dot enter. So I have to hit Enter, and it adds it to the array, which is perfect. Unfortunately,
it's not really the functionality that we want to leave the same cat in the input box. So how do
we clear the input box, we can just set new cat, this, that new cat equals an empty string. We've
already pushed the new new cat so we don't need it anymore.
And this new cat is fine to be emptied
again. So let's run this. There. And now MTS, ready for more cats. So there's many more events,
and modifiers that you can chain on to events. For example, view has an API for chaining things
on to the click event, you could do dot prevent, which means prevent default. And you can also do
stop for stop propagation. Basically all of the common things you might do, that are associated
with that type of event, which is super useful. I want to show one more shortcut here. And this is
what you'll normally see in a view application, instead of V on because it's so commonly used,
they have a shortcut to just do at. So at click, and then you can do this with any type of event
anywhere you would use vi on. So you can say key up. Let me just show that this still works.
And it works fine. Both ways work, this is just adding a shortcut to it. So let's say you want to
update something that's rendering to the DOM view has something called filters.
So I'm just going
to write a simple filter to illustrate what it does. And I'll come down here after methods, I
can add another object. And this one is similar to methods. It's an object of functions. And I'm
going to put the function capitalize function and actually a value here and I'll return the value
and then it will pipe it to this capitalized function, which is a filter. So it doesn't change
the actual value stored in the view state here in the data property. So all of these names will
still be lowercase, but just the display on the DOM will be piped through this capitalize
function. And it will come out value that to uppercase. So if we run this. So I actually
misspelled filters here and the add ins. And there you go. It filters through the capitalized so
you can also pipe these.
So I'm going to add one more catify. And I'll make another filter here.
function value. And I'll return the value plus y. So run that and it returns y on the end. If I
piped it the other way the y would be capitalized. Really this isn't used that often in view. In my
experience, it's just a good thing to know about for when the need arises. Another set of methods
in view for updating what's seen on the DOM, or the computed methods.
So let me get rid of
filters real quick. And this filters block here and I'm going to add compute instead. And I'm
going to use the same and scroll down. And I'm going to use the same method. So let's get a fi,
cat name, function. This time the function doesn't have to take anything. So let's say if this dot
new cat, which is our cat name that's entered in in this input box. So if that the length of that
is greater than one, I'm going to return this stock cat name plus y. And let's display this in
Killer filename. I'll put a break after. So you probably noticed the connection, that view
whenever it sees a variable. Inside of the double curly braces, it looks down here at the data
property, and the methods and the filters and the computed and tries to find a match for it. So
let's run this. There we go. And as I type, well, it's adding the Y for computed but it's coming up
with undefined. And that's because I misspelled the variable. So I put new cat there and run
it again. And that should work. So later on, you'll be using computed a lot when you deal with
view x. It's also extremely useful. If you have a lot of logic in the DOM, let's say you're doing
a lot of computation or updating inside of this block, then you could clean it up, take all of the
logic outside of the DOM here, put it inside of a computed property and then just display it in
the DOM like we're doing.
So let's say you want to update something that's rendering to the DOM
view has something called filters. So I'm just going to write a simple filter to illustrate what
it does. And I'll come down here after methods, I can add another object. And this one is similar
to methods. It's an object of functions. And I'm going to put the function capitalize function and
actually a value here and I'll return the value, but I'm going to change it to upper case view,
function, which is a filter.
So it doesn't change the actual value stored in the view
state here in the data property. So all of these names will still be lowercase, but just
the display on the DOM will be piped through this capitalize function. And it will come
out value that to uppercase, so if we run this so I actually misspelled filters here and
add an s. And there you go. It filters through the capitalized You can also pipe these. So I'm
going to add one more catify and I'll make another filter here.
Function value. Then I'll return the
value plus y. So run that and it returns y on the end. If I piped it the other way the y would be
capitalized. Really this isn't used that often in view. In my experience, it's just a good thing
to know about for when the need arises. Let's talk about custom components. Vue has a component
architecture that lets you reuse bits of code, just like most modern, single page application
frameworks. So let's illustrate this, I'm going to create a new component using view component.
And I'm just going to call it catalyst. And then I pass it an object of options. That's it, there's
a template. And I'm just going to do a multi line string with. So for right now, and actually, a
list should be inside of you.
How does this work? Close this, I will have to attach it to my view
instance. So I'm going to say, component. And then given an array of components, components, same is
catalyst. Now let's add catalyst to the DOM. So to add any custom component that you make, you can
just add it by its name. and run it and you can see cat down here, you can also pass in logic
and variables. So let's pass in our cats array and display the array through the component.
The way to accept variables in a component is through something called props. I'm going to pass
in the cats array, I'm going to say props. Cats, actually this array.
And I'm going to pass
in cats. And then here, I can use a V for the for cats. And then display it has to be cat
name. So here I actually have to pass in cats. So I'm passing in cats. But if you remember
here, I have to add v bind for the shortcut, which is just the colon. Because if I don't add
that, it's just going to treat cats as a string, when it gets passed into the component, instead of
is set to the array of cats. And if I run this, again, it's the same array. And it adds on
together. So the idea of having components is that they're reusable modular pieces.
when you're developing view locally vcli breeds a really nice project with you with a modular
architecture that kind of handles this under the hood for you. To wrap up here, I just want to talk
quickly about view lifecycle methods, view will trigger certain functions to run, which can be
very useful when you're developing an application. So I have four functions here created, mounted,
updated and destroyed, and they're just logging things. I'm going to run this. And if I look at
the console, it shows created when the component is created, and when it's mounted to the DOM, it
runs mounted. Now it's been updated, because the state in the data object has been updated.
for destroyed, it's a bit harder, because in the small applications, instance, never leaves
the DOM is destroyed. So I'm going to take a function to call destroy. So I'm basically setting
a timer for five seconds. And after five seconds, it's going to call app dot destroy, because the
view instance is set equal to the app variable. So this will destroy it.
Let me run this again.
So I see created, mounted and then destroyed. This also means I won't be able to update anything
here because it will be just statically rendered HTML as it is, is no longer connected to view.
There are many other functions that run including before Or mounted before destroyed. And I
think they're very well drawn out in the view documentation, so Vue js.org, the version two
guide. And if you look at the lifecycle diagram section, it shows you exactly when each function
is going to be run during the lifecycle of the component. So this is a really good reference.
And you'll be using these a lot as you develop applications. Next, we're going to go over how to
start developing applications with vcli locally. To create a Vue JS application, we're going
to start with the command line interface. So if you come to see ally dot view, J s.org. And
click on getting started. Over here on the left, there's a link for installation.
And it prompts
you to npm install dash G, view COI globally. So if you copy this command and come over to your
terminal, you can enter this and install view COI, I've already done this. So I'm just going to check
my version. My version is 3.1 point one. So now I'm going to create a view app, I can do this with
the view create command. So view space create. And then whatever I want to name my application,
which in this case, I'm going to call it quiz. So it takes me through a series of prompts. So if
you'll notice the last one, manually select so you can select routing, testing, linting, etc. The
default gives you just Babel and es lint and is a pretty basic site. on top. This is a template
I created, which I'm going to talk about how to do later. So for right now, we're just going to
pick the default to get started and see how it works. It's installing all the dependencies, this
will take a few minutes. And it creates a folder for you called quiz with your view application
Now, it also tells me how to run the application. So I can move into the quiz, folder
NPM, run serve. And it's going to run my view application on port 8080. I'm going to copy this,
go to my browser. And it gives me a boilerplate application. Let's open up our application and see
the code. I'm going to be opening up in VS code, which is a free code editor. And you can see
by default, it gives you a few config files, package dot JSON, which is where you reference all
of the code that you didn't write any third party libraries.
And then the meat of the application
is in the source directory. And this is where your j s gets rendered or your view gets rendered
to the page. So you can see it's creating a new view instance. So it's like we did before the
syntax is a little bit different. But it's doing the exact same thing. It's mounting it to a DOM
element with the ID of app. If you're wondering where your HTML file is, it's in the public
directory, you can see your index dot HTML and view is doing quite a few things under the hood
that you can't see.
So it auto injects your script files. So it creates a bundle out of your
main j s and all of these different view files, it bundles them all together, and then it injects
a script into your HTML file for you. That's one of the really nice things about using view, c li,
you have all of this boilerplate and setup done for you like Webpack, and Babel. So you can just
start building right away. If you want to look at the view scripts, these are the different scripts
that view is calling to run your application locally or to build it for production or to lint
it for you. So let's look at the application. From the main j s. It's importing this app dot
view file, which is the entry point of the view application. If you look at app dot view, you can
see that it puts a template. This isn't created by view. This is part of the html5 standard, but
it puts it in the same file with a script tag, and also a style tag.
How view works is when
you're building an application locally, you create many different files, each with their own template
that ah, tml. So in that way, you can divide up your application into components, and then put
them all together. They're all bundled into this main dot j s and render to the page. So here's the
first project we're going to be building. It's a quiz application that keeps track of the number of
total questions you have answered and the number you got correct.
The questions are pulled in from
an API, and displayed along with the answers. The only user actions are to select an answer, click
Submit. And you also have the option of resetting the count of questions to zero. When you choose
an incorrect answer, the color of the answer will turn red once you hit submit, and the correct
answer will turn green. If you get it correct, it will only show the correct answer that you
selected. Back in our quiz app, let's start making components. First, I'm going to delete
this hello world dot view which will not need and create two new components header dot view and
question box dot view which is wearable display the question answers and the submit button. Inside
of components, the only required element is to have a template tag for HTML. You don't really
need a script tag or a style tag.
So I'm just going to put some dummy text in here. Question
box. And I'm going to copy this for the header component. And just put a header here. So the app
component is still expecting hello world. So I'm going to put our new components in here. Instead,
I say header. And how header. To be able to use the component in the template section. I need to
add header here. It's comma, and then question box. And now I can get rid of the hello world and
And I'm going to add the header here. As well as the question box. All right, let me run
this NPM run serve. In the browser, we can see we have both components header and question box.
So before I update any of the components anymore, I'm going to install a third party library called
bootstrap view. bootstrap view has a lot of built in components and CSS already written. So we don't
have to worry about styling. If you're interested to see more, you can go to their docks or see
all the components that they offer, like buttons, different form elements, and they're rather nice
layout and grid system, which we will be using. So to get started. I'm going to go back, get started
and copy this command.
It wants me to npm install, view, bootstrap view and bootstrap. So I only
need bootstrap view in bootstrap. I'm going to go ahead and copy it. Go to my terminal. Let me close
this and get rid of you. Alright, now that that's installed, I can add it to my project in my main
when you create view apps using the vcli this will be in the main js file. Get add import bootstrap
view, I like to do my relative dependencies last. And I'm calling view dot use bootstrap view.
to take the CSS and import it. We import bootstrap CSS. And now I can start using These built in
bootstrap components. So let's use view bootstrap in the header component, I'm actually going to go
over to the view bootstrap docs and find the nav. And the header is not going to be a real nav in
But just for styling purposes, I'm going to go ahead and use this. When I switch
to two spaces here for consistency, put a wrapper div. Okay, someone that attach classes to it
later. Also, now, I only want two items in here. I want to have the name of the application to be
something like fancy quiz app. And then a counter for the number of correct versus total questions.
So I'm just going to hard code this right now. And replace these with variables. Once I have that
part of the app working. Let me see how this looks. Let's run the app again.
And now it's
now in the browser. Awesome. Well, the problem is these are links because it thinks it's an ER
view, bootstrap thinks we're making a navbar. So I'm just going to go ahead and disable these.
Set of active here I'm going to put, disable, and disabled. And then for the logo, I just want
to differentiate the style a little bit.
So I'm going to make it bold. Also, to offset the header.
I'm just going to add tabs here. And this should auto restart. Yeah, this auto restarts in here. So
I'll go to my browser tabs added this line here. And then I have my logo and the counter. So the
header component is done for right now. Let's move to the question box and go ahead and get that set
up. So the question box is going to use another view bootstrap component called the jumbotron,
which is basically a page element that sets itself out of the page like this, I'm actually going to
copy this code with the enclosing div, switch back to my code editor and paste it here. Just like
before, I want to have two spaces. indent here, just to know I always like to have this wrapper
div around components. Because I like to make container classes for when I use sass or CSS. So
I would put something like question box container here. And then reference this class to style
this whole component. So this is a pretty plain jumbotron.
We'll see it in our app. And it's not
exactly what we want, because we want a question and then answers below it. So in the jumbotron
docs, we can actually use templates inside that will make the component look more like this. So I
can put the question on top, then list the answers and have the submit button at the bottom.
submit button is another view bootstrap element for buttons. Notice, it's perfectly fine to have
more templates inside of the parent template, which is your component. And you'll see libraries
doing this using something called slots that we'll talk about later. But for right now, I'm just
going to copy these, go back to my component. And I'm going to put this inside. So let's see
what this looks like. Not too bad. I am going to remove the header. Because we already have a logo
on the page. And we just need to put the question here. So this will be our question. And then our
list of answers will go somewhere here as well as a submit button and a button once you've submitted
to navigate to the next question.
Let's see what that looks like. So we'll also have to get rid of
these which we don't want. Now let's see what this one looks like. Perfect question list of answers
a grid to kind of prevent these questions or the question box from going fullscreen.
So layout and
grid system. See the examples of how you can lay out a page With different containers in rows and
columns. For this, I don't have different rows. So I'm just going to use, I'm just going to use
the basic one here. Go back to my code editor. And I'm going to go to here. And I want this to
wrap the question box component. So get rid of the extra two columns, enter, and then just copy this
paste. And then in this column, I'm going to tell it. So on a small screen, or anything larger than
a small screen, I want to take up half the page, which is six, because bootstrap basically gives
you 12 vertical columns. So if you want half the page, you can do six, offset, offset equals three.
And let me show you what this is doing. So I'll inspect element here.
And the jumbotron in the
question box container is taking up six columns. So if I hover over this, you can kind of see that
the yellow part is a three column offset from the left. And the extra white padding on the far left
is from the container. So putting it inside a bootstrap container just automatically centers an
element on the page and gives it a little bit of padding on either side. So inside the container,
we have 12 columns, we're using six and offsetting by three. Great now let's jump into the API for
the questions and start pulling some actual data for the application. Open tdb.com is a quiz API
that we can pull questions from. They give you a lot of nice options. Like you can browse through
questions, you can submit your own questions, because these are all user submitted questions.
And they also have a pretty nice API. by filling out this information, we can actually generate an
API URL to pull questions from. So I think pulling 10 questions is good.
Any category, I'm just going
to select the animals difficulty any is fine. Any type multiple choice, just so the UI is the same
for every question. Default encoding is fine. So now it generates me this API URL. I'm going to go
put it in my browser. And I can see every time I make a request to this API, it pulls 10 questions
about animals? I think one kind of confusing thing with working with this API is that instead of
putting all of these in one array, they put the correct answers separate from all of the incorrect
answers, which is fine, because we're just going to take the correct answer with the incorrect
answers, write a function to shuffle them all together, and then match up the correct answer
based off of what the user selects.
And of course, every time you hit this API, it's going to come up
with a different series of random questions that it pulls. Let's put the API in our application
now. So I'm in my app component now. And I'm just going to add a function to pull in the questions
and answers from the API. So if you remember when we were in the browser, using GS fiddle, we
covered something called lifecycle methods, which are functions that get called automatically by
view as components either get created or mounted or destroyed, etc. So we're going to use one
called mounted here can be a function. And in it, we're going to use the standard fetch API, which
is a web standard and doesn't need a library to be imported.
So I'm going to paste our questions API
endpoint. And then I'm going to pass an object, an options object with the method to get from
this. Now, that's all I really need. But I'm going to add a dot then and take the response. So
never say in the response, when you use an arrow function here and say, just let's console dot log,
this response in JSON format, JSON. Alright, let's see what this does. Let's run this. By the way,
don't mind any of this orange text that says which git branch I'm on and I'm trying to put different
parts of this tutorial on different brain I'm going to do NPM, run serve again. Nope, we have
It's a linting error.
So I'm actually going to add this to my package dot JSON. And all of my linting
config is right here. So I'm going to add this as a rule here. And say no console. Try to remember,
this is just for demo purposes. If I were actually building an application, I would probably want to
have a warning or an error there, just so I would remember to remove all of those extra console
dot logs. Anyways, it's running now. So I'm going to check it out in the browser. Of course,
nothing is different right now. But if I look in the console, may refresh. And I'm actually getting
a promise back, which is good, it means I'm getting the data back. But we can't see it right
now. Because I have to update my promise chain. So let me go back to the code.
And app file, I'm
just going to return this turn response dot JSON. And I'm going to change in chain another dot then.
So I'll just say it's JSON data. And let me wrap this, this so it's more clear. And then here is
actually where I want to be able to access the data from my application. So I'm going to create
doesn't look like I have a data method yet. So I'm going to create a data function and add a comma.
And I'm going to return an object, oops, object. Now, if you notice, this is a little bit different
from how we did it in the browser. The reason this is different has to do with some more complex
So we're not going to talk about those. But it's basically required when
you're making this type of single page application with a bunch of different components that instead
of just making a data object, you return an object from within the data function. So it's a minor
change. So here, I want to add a questions array, which will be empty at first, and can be populated
from the questions from the API. So here, I don't need to return anything. But I want to set
the questions, this questions array to equal the questions we get back from the API.
So I'm going
to set this dot questions equal to the data we get back from the API dot results. Because if
you remember, the API gives us back two things. It gives us a response code, and then a results
array. And the results array is where all 10 of the questions we are pulling back are located.
I can save this, I am still running all test it in the browser, and you can't see it yet. So to
inspect the data on our components, we actually need something called Vue JS dev tools. So if you
google view, Dev Tools, this is the GitHub repo, if you scroll down, you can see they have
a Chrome extension, a Firefox extension, which I'm using Firefox right now, if you're using
something else, or you just want a standalone app, that's fine, too.
They all have pretty much
the same functionality. So I already have it installed. And it comes up on my dev tools as
view. One of the things I love about view is that it has all its dev tools in one place, we're gonna
get into view x and different things later. Some other libraries, you have different dev tools for
different things that you're doing. So under app, I can see all of the components imported into
app, the child components, I can also click on app and I can see any data variables associated
with that component. Under questions I can see, we have all 10 questions that we pulled from the
API. And it's in the same format that the API showed us with the incorrect answers, and then the
single correct answer by itself. So the next step here is to display the question to the screen.
So let's go back to our code.
I'm back in the app component. And I'm want to be able to display the
question from this question box component. So I'm going to have to pass it from the app component
to that one. And I want to pass just the question that we're on. So as you're clicking next through
questions, I just want the question box component to know about the current question. So I'm
going to keep in index of the question here, which We'll start at zero. And then view
lets me pass data variables and methods to my child components by using v bind with custom
attributes. So I can say, the question I want to pass equals my questions array and the index. So
just the current question that we're on, and then eventually we'll be able to click next, and this
index will increment.
So question one, Question two, etc. Now, if you remember the structure of
our data, off of each question of each question. So this is one question this object, we have the
correct answer incorrect answer and the question, so we have to get the question text off by using
question. So let's do that in the question box. So I'm going to come here. And remember the double
mustache syntax to use variables. So I'm going to do question which is passed from the parent
component. And then I have to do dot question. So maybe it would be more clear if I did. Let me
change this to, I guess, current question.
To make it more clear, and then I have to go and change
it in the parent component there. So you can give this any name, but it's going to be the same name
in the child. But that's not the only thing. In order for this question to display properly in the
child component, we not only have to reference it in the HTML, but we have to pass it through the
now, I'm just going to give it the key props, which isn't another object. And I'll put a current
question which is also an object datatype that I received from the parent. So any variables,
whether it's a data property, or a method that I'm passing from app to question, in order for it
to display in the HTML, I have to reference it in props and say, Hey, I'm receiving this particular
named variable from the parent, and you reference it the same way you would a data variable.
you have your component state, which would be local to this component in data. So this is local
to the app dot view component. And then you can also have props, which is any variable passed from
another component to this component, and you use them the exact same way in the HTML. So let's see
if this is working. NPM, run serve again. So it built and now let me check in my browser. There we
go. And it's showing one of my animal questions, zero question. I can check this. If I go down
here into my view dev tools.
I'm inspecting the question box component. And looking at the
props, I see, I get the current question object, which has the question a carnivorous animal eat
flesh, the same thing we're seeing on the screen. And if I go to my app component, I can look at my
index, which is zero. So if I edit this and say, one, then it actually changes the question
that I'm passing to the question box component, because now it's at the first index instead of at
the zero index. So if I go back to question box, you can see the question is changed. So let's
set up the navigation between questions this next button without having to go into the view dev
tools to change the index.
Back in my app dot view component, after data, I'm going to create
another object called methods. And in here, I want a method to increment my index value to so
I can navigate through the questions. So I'm going to call it next. As a function. This is basically
a shorthand syntax for having a key of next and a value as a function. But I can just write it like
I can refer to as this dot index in my method, and increment it by one. So this dot index plus
plus, and that will take the current value of this index and data and add one to it every time
the next method is called. So I'm also going to want to pass the next method into the question
box. So the same way I did with current question, I'm going to pass in the next function, and then
go to question box and receive it here.
In my next button, I'm going to spread this out, I'm going
to add an app click method, and then call the next function on click. And of course, down here,
I have to receive that prop. So I'll say next, which is also a function. So now when I click
the Next button, it should increment the value by one by calling the next function in app dot
view, and then app dot view should pass down the next question in the list. So let's see if this
works. View is still running. And let me go to the browser. So I have my zero index right now. And
something's not working correctly. It says current question is undefined at question box.
me go in here and see it's still at index zero, of course, because we're getting an error.
And here, I have the next function and current question. So everything looks okay in our data.
And I think we're not quite getting the best error message. So I'm going to check in another browser,
copy this, go to Chrome. And now I can check in the Chrome Dev Tools. And here it's saying cannot
read property question of undefined. So let's go to the question box component and see what it's
talking about. Oops. is in question box. It says, cannot read property question of undefined. So
that means current question is undefined. But when we look at the dev tools, it's defined.
that means for a brief moment, when this component is mounting, it's still waiting for the data to
come from this component. And we can see that I'm just going to add a lifecycle hook here. And I'm
just going to console dot log, this dot current question, Ben back in the browser, I'm gonna
refresh this. And it's undefined. But in the dev tools, it is defined. So that means right when the
component mounts, it's still undefined. And it's a moment later when the questions come back from
the server, and it goes into the state in this component, and then it gets passed to the question
box component. So an easy thing to do would be not to render the question box component until these
questions are defined. So wait until we fetch the questions and save them in the component state
until we render this component. So I'm going to add a V if directive. And I'm going to say V if
questions dot length.
So if the array is empty, then the length will be zero, which is a false e
value. So the question box won't render. But as soon as the questions come back from the server,
the question length will not be equal to zero. And so question dot length will be truthy. And
question box will render. So let's see if this fixes the error. Refresh. Let me go to the
console. And now there's no error. Of course, we're still getting our lock.
But it fixed
the error, because now for the brief moment in time question box is not rendering without the
data available to it. And now we're able to also navigate between questions, just as we would
expect, with the next function incrementing the index. Of course, there are still problems
because when the index gets to 10, it'll throw an error because that's past the length of the
questions right, and we'll fix that in a minute. Back in the question box component, let's add the
list of answers here instead of the dummy text. So if you remember our data's Structure had a list of
the three incorrect answers and then the correct one separately. So to display all four answers, we
just need to put the four answers together. So as a temporary solution, let's use a computed method.
So I have an object of computed methods. And I'm going to call it answers. So I basically have to
take current question from props, and the array of incorrect answers.
And I'm actually going to
assign this to a new array, I'm going to say let answers equal question that incorrect answers. And
what I'm doing here is making a copy of the array instead of referencing the same array. And now I'm
going to need to take answers this answers array, and append or push the correct answer onto the
end. So take current question that correct answer and push that onto the array. And of course, this
is the array that I want to return. So I'll just return that. So I should have all four of my
answers in this array now. And for right now, I will just replace it in here with a V four.
going to do V for vehicles and answer in answers, which is going to reference our computed answers.
And here, it's going to complain, because for any V for loop, I'm going to need a key attribute. So
view requires this for accessing these elements in the DOM. So I can do a V bind key. And usually,
you want to do something unique. Here, we kind of know all of the answer, or each answer is
going to be unique.
So each paragraph tag that is created in this for loop is going to have a unique
key, which will be equal to the answer. Usually, if you're doing this in an actual application,
you'll want to use some kind of unique identifier, or view also gives you the option here of
getting the index in the array. So you could call it index, and then use index here as your
unique identifier. And I guess I'll just leave it like that for now. Now, if we were to look at
this right now, we would see four empty paragraph tags. So I'm going to put the answer text inside
with double curly braces. Save that now I'll test it in the browser, go here, refresh. Looks like
I'm getting an error. What error Am I getting? Seems like a similar error to before getting
current question is not defined.
Oh, so I actually referenced current question incorrectly. If you
look here, I'm referencing current question. But that's assuming that it would be inaccessible
variable, actually, because it's a prop. I need to access it through this current question. And I'm
going to have to do this current question correct answer as well. So this should fix the problem.
And actually, anytime you want to access a prop or a data variable in another function, whether
it's a method or computed, or anything else, you have to do this dot the name of your variable.
So I'll save that.
See if that fixed it. And yes, it is fixed. These are just old aerosol refresh.
So it is fixed. But we're getting just the numbers of the answer and not the answer text. So there's
actually another mistake here. And it was in how I returned answers. So I'm going to pre push answers
here, push the correct answer onto the array. And now I will return answers. And that should fix the
problem. Yep. And now we're getting the correct looping through our answers. And they're all
for displaying if we go to the next next next, and is displaying all their answers. Now, we
actually want this to look a bit more like a list and also make it clickable for the users. So I'm
going to go to View bootstrap again. components, bootstrap view. And I'm going to go down to should
be a list group. Here's it, here it is. And we want to display it like this. This will make it
easy for a user to hover and click on an element. So this is pretty easy.
I'm just going to copy
this list group here. Since this is exactly what I want it to look like. Go back to my code and
I'm going to paste the list group in here. These, tab them over. And I'll get rid of all except one.
Now I want the list group on the outside, and I want to loop through and make a bunch of these
items. I'm going to put this on another line, put this over format at nice. And now I can copy paste
the loop before loop, and also copy this and then put the answer inside instead of the dummy text.
And that should work. Let me save that and see how it looks in the browser, go here. And it works
just fine. So I don't really like how the buttons and everything rubbing up against each other and
then up against the answers. So if I look in my dev tools, I can refer to these with the class
list group or list group item. So I'm going to copy this class, go back to the application and
just add a style tag to the bottom.
Any view component can have a style tag in it. And there
are different options you can use for styling. I'm just going to use default CSS. You can also
use sass, if you want to. I'm also going to denote that these styles are scoped, meaning they won't
be global styles, they will only affect styling in this component. And I'm going to paste the class
that I copied and say that for the list group, I want to have a margin, let's say margin, bottom
of 15 pixels. Save that, see how it looks. And there's a little bit of padding. Now for the
buttons, I'm going to put a sideways margin, and I'm going to reference these as btn from the
button class. So I'll put margin, I'll just make the top and bottom zero, and then left and right.
Maybe I'll give it five pixels. Save that. Now it looks a little bit better spaced out. So now
to make the buttons clickable. Let's go back to the question box component. And I want to add
an add click function here.
So at click equals a new function, I'm going to create called select
answer. And I'm actually going to pass it the index of the answer that was selected. And I'll
go down and create this function under methods an object and selected answer. And then I'm just
going to log out the index here. Let me test this in the browser. See if it works. And it does.
So I have the correct index of the answer I'm selecting, the next thing is to save the Select
index on the component. So I'm going to create a function here and return an object of our data
variables. And the first one, I'm going to say is selected index. And for right now just set it
to null. And now down here in the selected index method, I'm going to say this dot selected index
equals index. And we can see this in the view dev tools.
Go back to the browser. Gonna refresh,
go to the View dev tools. And in question box, I can see selected indexes No. Okay, so I tried
refreshing. And let me click again. And again, and for some reason, this state here isn't updating.
But if I hit refresh, in my view dev tools, then the state updates to the correct number. And
now if I click on this first one here, and click refresh, now the state updates to zero. So for
some reason, the view Dev Tools aren't updating but our function is working correctly. There are
still a few more steps to do to be able to get our answers working correctly. And first of all,
there's no visual feedback to the user to let them know to first click on an answer or that they've
selected an answer. So let's first create a hover style. And I'm going to go below here, copy this.
And say list group item. Hover, hover state.
So when the user hovers over it, I want to just
change the background color slightly. Right now the background on the answers is white, I believe.
So let me change it to a shade of gray. If FFF is white, maybe I'll do E. And see how that looks.
Now when you hover over it, you can see that it's a clickable item. Another thing I should add is
changing the cursor to a pointer. And now when I hover, I can see that I have this little clickable
hand. Unfortunately, when I click, let me click on Neanderthals. And I still have to refresh this.
It's selecting the index in the data, but the user has no feedback here as to which answer they've
selected, or if the application is even working. So let's fix this by adding selected classes.
in the code, I'm going to add two more classes here. One is for a selected answer. And I'm going
to give this background color. Let's just say blue for right now. Background color blue, and then
correct answer. When the answer is correct. We're going to give it a background color of green. And
one more when the answer is incorrect. I'll give it a background color of red. In order to add
these classes into the code, we're going to use one of our data variables selected index, which
should be set to the user selected index when they click on an answer.
And we need to add a V bind
property here and bind and bind a CSS class to this. So we're going to put class equals, and then
it's going to be an array, we're actually going to add things to this later on. But for right now,
I'm just going to do selected index. If it equals index, then we're going to use a ternary. And I'm
going to say, let's give it the class selected, selected. And if it's not, then we'll give it just
an empty string, no class, save this. And then in the browser, we try selecting a class. And it's
not quite working, when we look at the console.
If I refresh, then it does work. Unfortunately, it's
a really dark, ugly color. So let's just change it to maybe a light blue, may go down selected could
be light blue. Let's do light green, back in the browser. Now it looks much better. And then if you
go next? Of course, it's not clearing the answer, which is another bug we're going to have to fix a
second bug is that our answers aren't shuffled. So we actually know that every fourth answer here
is the correct one.
And then on top of that our Submit button doesn't do anything yet. So let's
go back to the code and fix these three things, starting with the answer shuffling. to shuffle the
answers. For every single time that the question changes, I'm going to add something called a watch
method here. It's just like computed or methods in that it takes an object of functions. And in
this object, I can watch for changes to my props, it will run this function when it changes. So
I'm actually going to give it the same name as my current question prop. And then when the
current question changes from the parent, it's going to run this function where we will shuffle
our answers every time. So the first thing I want to do in the function is to set this that selected
index back to no every time the question changes, and then I want to shuffle the answers that
And shuffle answers is going to be another method that I create here. And
I'm going to copy paste this answers array I was creating there. And here, I'm going to put
this that current question dot correct answer. So I have them all in an array, all four answers.
Now I could do this with a for loop and some randomization. But there's actually a really nice
helper library that I can use for this to help me shuffle an array, and it's called lodash. lodash
to write on your own, and that are common in many projects, like having to shuffle an array. So
I'm going to go to the lodash. github. Right now, we're just going to do NPM, I lodash in
While that's installing, I'm going to go back to the browser. And we're
going to be using a function called shuffle. In the root of the lodash GitHub repo, you can see
that every single utility function in the lodash library is listed here as its own file. So I can
actually go into shuffle j s, and see exactly how it works, what algorithm they're using for the
shuffle. And if I wanted to, I could just borrow this one file and any files that it imports,
instead of importing the whole lodash library, I think it's really nicely laid out in this
fashion. And it's a very good learning experience, if you want to look through some wall written
So it should be done installing. Let me go back to my server NPM run
serve. Now back in my code, I'm going to add the lodash library, I need another data property,
where I'm going to put shuffled answers, this is going to be an array and I'm just gonna call
it shuffled answers. And here, I'll put this dot shuffled answers equals now lodash. The convention
is to import it with an underscore and then use it instead of calling lodash dot shuffle. I would
import it as an underscore here. And so I'm going to do that at the top of the script file, say
import underscore from lodash. actually get rid of this mounted function, and I need to tell it what
array I want shuffled, which in this case is the answers array.
So I do have a typo here. Instead
of saying current question, I'm saying correct question. Just going to fix that. Now, if I look
at the browser, then I'm going to refresh. And let's take a look. So right now we don't have any
shuffled answers. Let's see if when we hit next, we actually get shuffled answers, which you can
see bird is the first element of the array at the zero index, in the regular answers where we're
just appending, the correct answer onto the end. And then in the shuffled answers, bird is the at
the second index, so we can see shuffling works, unfortunately, it only works as we click through
the questions. Also, we can check and see that selection works. And then it does reset after we
click for the next question, which is good. Now, how do we get it to shuffle on the first question,
there are actually two ways we can do this. Let me go back to the code. And the first way is
something that you already know, we can add a mounted lifecycle hook just like we had before.
And then we could call this dot shuffle answers from here.
And that would work that would shuffle
answers on the first component mount. And then every time after that, when the current question
is updated in props, it would shuffle the answers, which is fine, it gets the same functionality,
but there's also another way that might be a little bit better. So I'm just going to show you
in these watch functions. Instead of making them a function. You can make it an object And set
some options on the object. So I'm just going to comment this out real quick and set it to an
And one of the options we have is to set immediate to true. And then we can add a handler.
Oops, which is another function. And then inside of this handler function, we can do the same
things we were doing before, and it will be called like a regular watch function. Get rid of this.
And now let's see if it does, in fact, update and shuffle the questions for the first question
that is shown back in the browser, window refresh. And then check and see if they are shuffled. And
yes, this is great. We do have shuffled answers now. So just to reiterate, what immediate does
is, instead of only running this watch function, when current question updates, it's going to also
run it when current question first gets passed as props.
And then every subsequent time that it
updates, it will also run the handler function again. Here, I'm going to update the submit
button. And to clean it up a little bit, first, take away this H ref that we're not going to use,
and then put it on separate lines, because we're going to add a couple more things here. For right
now, if you remember, there's the V on directive, which I can attach to events like click, so v on
click. And then I want to run a function that I'm going to create called Submit. Answer. And here
I'm going to change this directive to use the shortcut. And now let's create the function submit
answer here. Down in our methods, submit answer, and this will run whenever that button is
clicked. And the first thing we want to do is store whether or not the answer is correct. So
I'm going to create a variable and by default, I'm going to set it to false.
And then if the user
got the correct answer, I'll set it to true. So if this dot selected index equals the correct
index, meaning they got the correct answer, then I'm going to set is correct to true. And
what this is, is correct variable, I need to be able to tell the app component whether or not
the user got it correct. And also let the app component know that the answer was submitted.
Because in the header, we have a counter of the correct answers versus the total answers. And this
information will have to come from question box through the app component and passed as props to
the header. So let me create a new prop from the app. And it's going to be this dot increment. And
I'm going to pass whether or not the user got the answer. Correct. So is correct. And I'm going
to go ahead and add this as a prop here.
It's increment is going to be a function. And now from
the parent component, I need to actually add this function. So let me go ahead and pass it down. And
I have to create the function in methods. Add the increment function with the is correct Boolean.
And here, I need to keep track of two things, the number of total user submissions for answers, and
also the total number that are correct. So first, I'm going to check if it's correct. So if is
correct, I'm going to increment a new data variable for the number of correct. So up here in
data, I'll go ahead and add these. So let's say the number of correct answers set to zero and the
number of total answers that the user has answered also set to zero to start.
And down here, I can
say the number of correct increment that number by one and then the number of total, also increment
that number by one. I forgot that this here. So this DOT number, correct increment by one, this
dot total increment by one. And I want to do one more thing here. And that's pass these two values
to the header component to use. So add it here or use v bind and pass the number of correct. And
also the numb total. Now in the header to receive these props, I'm going to create the script tag,
script and export an object with props.
And I'm going to do props as an array this time, just to
have both different ways. And I'm receiving the number of correct answers from the parent as well
as the number of total answers. And I can put them here with double curly braces. So the number of
correct out of the number of total. Now we changed a lot of things. Let's look in the browser and
see if this works. Let's see what it's complaining about. Seems to be okay, right now. I'm gonna
select an answer, click Submit. Click Next. Now, I'm wondering why it's not incrementing. correct
them total. And it seems to only be incrementing, the number of correct. So let's look back in
the code and see why the total number is not incrementing.
So we have the num total as props,
that should be fine. Let's look in app num totals getting past your num total here. And here. I'm
just doing total. So I'm going to put num total and that should fix the problem. Let me refresh
just in case. Click on and answer. Submit. And now my num total is incrementing. Though we shouldn't
be able to submit a question more than once. Because right now there's nothing stopping us from
continuously submitting, or even submitting before we have selected anything. So really, we should
be disabling the submit button until we make a selection. So let's go ahead and do that. And
I want it to set as disabled if they have not answered the question yet. So I'm going to do v
bind and then the HTML attribute of disabled. And I want this to be true if they haven't answered
the question yet. And false if they have already answered it, and then the button will work. So I
can use one of our data variables, selected index, because it will be no until they've selected an
So I'm going to say selected. index equals No. And let's look in the browser and see if that
works now. So it is disabled, I can't click on it right now. But when I select an answer, it
gets brighter, darker blue. And now when I hover over it, you can see the hand. And now it
selects correctly. And if I scroll up, it will still be incrementing. Two out of seven. Great.
Now let's work on not being able to submit the answer multiple times like we can right now. What
we are doing here, just checking if the selected index is now only accounts for the case where
the user has not answered the question yet. So we're going to have to add another check to see if
the question has already been answered. And if it has then also disabled this. So I'm going to add
another data variable called just answered and set this equal to false. And then up here, I'm going
to say and answered so as long as both of these conditions are met.
And now I'm going to have
to add these to some functions down here. In the Submit answer function, I want to set this.is for
this dot answered equal to true because they've already answered the question if this function is
running, and then in my watch handler, I also want to reset this thought answered, as false for
every question I think actually in the button, I think I'm actually going to have to do
in order here. So if it's No, they haven't selected answer at all.
Or if it already has
been answered in either one of these cases, it should be disabled. Let me save that and then
go to the browser refresh. And then see my button is disabled. Probably not a very good color for
disabled button. Oh, well. And now it's enabled. And I submit, and now it's disabled again, after I
submit, and it counted up and I got the incorrect answer. Now, it would be kind of nice to see which
one is the correct answer, because I know I got an incorrect because of this counter. But I don't
really know which one of the other three was the correct answer, and I can't submit it again. So
let's change that in the styles. Jumping back into the code, let's store the correct answer.
down to my data, I'm going to add another variable called correct index. I'll set that equal to null
initially. And now when I shuffle my answers, meaning when I get a new question, I'm going to
store which one of the answers is correct. I'll go down to my shuffle answers function. And I'll say
this dot correct index equals this dot shuffled, shuffled answers inside the shuffled answers
array. I want to get the index of the correct answer after it's shuffled. So I'm going
And then I'm going to say it's the index
of whatever the correct answer is. So I already have the correct answer stored in this dot current
question dot correct answer. So now this should keep the correct answer. So we still know it, even
though all the answers are shuffled together. So let's see if this is working. Go to the browser
refresh. Now look at my question box. And I have, huh? Well, that's interesting. I must have made
a mistake in typing this out. Let me go and check the code and see what I did actually misspelled
shuffled answers. I left off the s. So now I'm going to save this, go back to the browser
again. And it shows the correct index. Let me go to the next question. And the correct index
changes per question. Unfortunately, as a user, how do I know if what I selected was correct?
There's no way for me to know, it just moves on to the next question.
So let's add some functionality
and styling. So the user can see feedback that the answer is correct or not. And in doing this, we'll
need to make the submit button work as well. If you remember a while back, we made these different
CSS classes selected, correct and incorrect. And so far, we've only used the first one. So let's
use the other two, we show the correct answer as green after they hit submit. And if they selected
the incorrect answer, then that's going to turn from light blue, blue to red. So we're actually
going to make a dynamic class.
And here, I'm going to put this on a separate line. So I'm going to be
adding some stuff, just for the time being here. Actually, I only want this selected class to
appear if the question is not yet answered. So I'm going to add a not answered here and selected
index. And just for a second, I'm going to be nesting ternary statements here, and then I'll
clean it up after. So right now we have the case where it's not answered. And they've selected a
choice. So what about if that case is not correct? So here, I'm going to add a case if it's answered.
And the correct index equals index. In that case, they got it correct. We want to show it as
correct. believe that's the name of our class here. Yeah, correct. And otherwise, I can show it
Has nothing. So let me save that and see how it's working so far. Yep. So that's the correct answer.
And now it shows the correct answer there. It says this, there's going to be another case that we
have to add here, after here, so I'm going to copy this actually.
And it fits not equal to index,
I'm going to say we're going to use the incorrect class. Otherwise, no class. So if it's answered,
and they didn't get the correct answer, then I want it to turn red. So let's see if that works.
Obviously, it didn't work that well, because every incorrect answer is turning red. And I just want
the user selected one to turn red. So back in the code, I'm going to have to add one more check
into this chain. And that will be if selected, index equals index. And this is getting kind of
long. And back in the browser, I mean, refresh. There. And now it correctly shows, of course,
this logic that I wrote is kind of out of hand. And it's definitely messy to do all of this inside
of a class. Just to clean this up. We're going to move all of all of these nested ternary E's into a
method. And we'll call that method. Answer class. And we'll pass it the index, each list group item
So each answer is going to call this method in order to see what class it's going
to have. So I'll go down to methods and add this one on to the end. And answer class, it's going
to be past the index of the answer. And then, just for reference, these are all the nested
Turner's I had up there. I'm going to copy the first one. And first I need to create a variable
called answer class. And set that equal to an empty string of an if statement. So if it's not
answered, but they've selected an answer, then I'm going to set answer class equal to selected.
And I'll just change some offsets here. And if it's answered, and they got the, or the answer
is the correct answer, then in the class for that particular answer is going to be correct.
a final case is if the user answered the question, but they got it incorrect, and we want to make
that red with the incorrect class. So it would be answer class equals incorrect. And then down
here, I'm going to return as answer class. Let me clean this up. And let's see if that still
works. Yes, so the answered is not defined. And that's because again, I forgot to put this
dot answered. So remember, in the template, you can use any of these variables. But if you're
this dot answered, and this dot selected index and this correct index. So this is kind of long.
I'm gonna put this on a few lines.
And that should work. So let me try it in the browser again.
seems to be working. It's selected correctly. Now I can submit, and I got it wrong. So it's red
and green. Try one more question. Submit. Yep, it works perfectly our counter still working. This
is the whole quiz application. The GitHub code will be linked below if you want to take a look.
And you can see that there are different branches so you could look at different parts of the
tutorial in different stages. If you wanted to. Now we're going to build an app that's slightly
more complicated to demonstrate how view routing and view x, which is view state management
system work, it's going to be a basic four screen application.
Its theme is getting cats and dogs to
be adopted. And we're going to be performing basic CRUD operations to get used to state management.
Now, there's a homescreen, two screens, one for cats and one for dogs. And then you can
click on any animal name, either cat or dog, and it will load a screen just for that animal. So
here in the terminal, I'm going to create another view application using view create that I'm going
to call it, adopt pets. If you remember last time, we use the default boilerplate. This time,
we're going to manually select features to manually select, you can go up and down with the
arrow keys, and press spacebar, such as here, I want to select router.
So I press spacebar. I also
want view x. If I wanted to use SAS or something, I would select this one. And then I think I'm
going to leave testing out of this particular application. So that's all I want. I'm going
to hit Enter. And then it asked me a few other questions. History mode for router is literally
a one line change in the router. And I'm going to show you how that works later.
For right now I'm
just going to put Yes, I'm going to pick SAS since it's the most popular CSS preprocessor. And I want
to show you how I include it my applications. For this, I'm just gonna put standard config, although
prettier, and Airbnb have some nice features as well. Either way, all of these are just templates
and starting points. So you can always modify any rules that any of these set for you, I'm just
gonna have it run linting every time I save a file, and this is a personal preference of mine, I
like to have my configuration in their own files, such as my unit testing, config, Babel config, or
my es lint file by itself instead of cluttering up the package dot JSON that can get pretty
Now, if I want to save it as a preset for future projects, I can click I can type y and
it's going to ask me to give it a name, I'm just going to type no here, and then show you the one
I already have. And now it takes a few minutes to build the project. Great, it's done installing.
I'm going to go into IE adopt pets directory and open this in VS code. This is very similar to the
project last time still have the index dot HTML in public. A few differences here are that in the
main j s. Instead of only rendering the app we're setting our store for view x as well as our view
router configuration in our view options. Another difference is you'll notice that here we have a
views directory and a components directory. Now, if you look in the router, you'll notice
that home and about which are the two routes are both views.
So these are the pages of your
applications which are connected to the router, and components are imported into the views
or into each other. So if I look in home, I can see it's importing the Hello World component
hello world dot view. And it's displaying it to the DOM. The idea is that components are reusable
pieces. And each page stands alone as a distinct view in your application. Now if I go back to the
router, there's a lot of things you can do such as lazy loading, or even using multiple components
here. But I'm going to keep it simple for now. So I'm going to take this out of here and import.
now I can set component to just about and get rid of all these comments. And now it's and it renders
exactly the same. It's just a bit easier to read right now. Now the store I'm just going to give
a quick overview. And I'll go in deeper, you're basically creating a new view x store, which is
a global object. So any functions or variables, data, anything that you want to use maybe in
multiple parts of your application. You can store them all here, and then import them into whatever
component you want. And it's like a global object for your application. The first thing I want to
do in this app is create the four pages and link them together. If I look in views I have about
at home, I'm going to go ahead and leave the home component and delete the about one And then
create one called cats dot view, dogs dot view. And the other one I'm just going to call pet dot
And I'll put a boilerplate template here. And I'll do the same thing for dogs. put just a
template here, and one for the pet page. And I'm going to hook these up to the router. Now I've
defined all four routes that I'm going to use in this application, I'm going to update my app
file to link to all four of those pages instead of just home and about duplicate those.
put cats, dogs and the pet page, which eventually is going to be linked through these two pages.
But I'll just leave it for now. Dogs and cats. And let's see how that looks. Okay, it has all
of the links here can go to the different pages, I'm just going to add this pipe in between. Copy
this. There looks much better. Now let me get rid of all this extra stuff on that page, which
is in the home component, importing HelloWorld. And using this image, I'm just going to get rid
of both of these.
And just say home. Get rid of this. And this. And now I'll delete the Hello
World component. Perfect. Now just like before, I want to import view bootstrap to help do
the styling for me and lay out the pages, we're going to go to the browser to bootstrap.
Get started and install it with NPM. Start my server and NPM I bootstrap view. Now back in
my browser, I can copy the import in view.us. And I'll put it in my main.js file. I'll put it
up here with my other library imports. And since I don't have a section for view.us, I'll put it
right there. Now I need to import the CSS as well. So I'll go and grab these links. And put them
here. And that's it. Now that I'm importing view bootstrap, I'm going to use some of their table
components to display the tables of cats and dogs. So if I scroll down here, see they have a table.
And this table looks fine to me.
So I'm going to copy this big table and save it and go back to my
code and include some of these. Now let me start with cats. And here I'm going to add that table
component. And now of course I need the data. So I'll add a script tag to close it and export
default, this object data function and return an object. And now back in the browser and see I
need an array of objects, which I already have in another file. And I'm just going to copy paste
that into my application. So I'll create another folder in source And I'm just going to call it
data. And in data, I'm going to make two files, one file, cats dot j, s. And the other one will
be dogs, dot j s. And I'm going to copy and paste data that I already have here. Here are my
dogs. This is an array of dogs. So I'll do export default, this array, and I have some different
information and metadata about the dogs.
And make close this one. And now I'll add my cats, which is
also a very similar array. I'm going to add them here. And now back in my cat stop view, I'm going
to import cats from at data, slash cats. Now, this app symbol is a shortcut that view COI sets
up for you. And it's a reference to the source directory. So that way, you don't have to do
things like dot dot slash dot dot slash dot, dot and whatnot. So I'm just going to use the shortcut
at. And now I'm going to return cats here. So this is the same if you don't know the shortcut, this
is the same as setting a cat value equal to this cats array that we're importing. But the shorthand
is just to do it like this, since they both have the same name. So now for items, I'm going to
say, cats here. And I'll see how that looks in the browser.
Back in Firefox, if I go to adopt pets,
and refresh, I must have stopped my server. Let me look back at I turn, and yes, I did. So let me
run NPM, run serve again. Great. Now my browser. Alright, it's working. And now I have a cat's
table showing all of my cats, I'm just going to clean this up a little bit. So it doesn't
go all the way to the edges of the page here. And I'm going to add a B container in my app dot
So for this router link, I'm going to wrap it in B container, which is another bootstrap
component provided by view bootstrap. And they'll go back to the browser, refresh. And that looks
much better. As far as the width, I also need a page title. So let me create that real quick. Back
in cats, I'm going to have an h1 here. And say this is just cats for adoption. Alright, that's
good. Not too fancy, but looks fine. Now I'm going to copy paste this and do the same thing for
the dogs tab. And I'll go back here. Go to dogs, I'm going to copy paste this table and the script
tag. And then I just need to change it to dogs. Oops. Hear as well and hear. Great, so those
two pages are looking good. Just to finish up the homepage, I'm going to change this to an h1 as
And I'm going to say adopt a new best friend h1. So that's all of the nitty gritty out of the
way. Now if I go back to my browser, you can see that I have these three pages. But this page is
supposed to be that of an individual cat or dog kind of like seeing his individual profile. So
if I go to cats, for example, then the pet page should be something like cat slash one for the ID
of that cat. So let's learn how to do this through the view router. View router has something called
dynamic route matching. What it does, instead of hard coding the whole route, you actually have
dine namic route variable as part of the route, it's preceded by a colon, and then you can call
the variable, whatever you'd like. And then you can access this variable when you go to that route
in the component associated with the route on the route params object. So let's see what this
would look like in our pet component.
First, I'm going to update the router. And say here under
pets, I'm going to change it to be plural pets, and slash ID for the pet ID. And I'm going to
leave these as they are for right now. Now, let me get rid of the link in the app dot view
file to pets, let me just get rid of that. And now we need our table components to have links to the
pets page for every item. So we'll have to update this table. Since right now it's kind of a black
box. And we're passing in this array of cats to a third party bootstrap component. So let's go to
the bootstrap docs and see how we can turn each cat in the table into a link to that page.
to the browser. And I'm still under the bootstrap component tables. This whole page is pretty big.
So I've skipped down to this format our callback. And basically, what it allows you to do is pass in
a template with a dynamic href. So let's copy this and go back to the code. I'm going to expand
this, close it here and put this inside. Now I want to mention something about slots, because
you're probably going to see this a lot in view, especially if you are using third party
libraries like view bootstrap, or if you are creating your own components for someone else
to use. Now, in bootstraps B table component, it's going to look something like my format or
doesn't like this very much.
So it's going to look like template and then have something exactly
like what we have with maybe a div inside. And it's going to have a bunch of other tags, and
it will have this somewhere slot. So bootstrap is basically telling the component where to put
things that we pass in to the this B table. So it has different slots inside. And if it has
multiple slots, which in this case, it does, it will say name equals name, which will be a
dynamic, because we have lots of different columns that could vary in the table. So bootstrap will
have a slot for each of our columns. And that's how we can pass it in here. If you want to know
more about slots, they're pretty easy. And they're described really well in the view documentation.
And here, I'm just going to replace this with slash pets slash Variable Data dot value. And I'm
going to change this to a router link, not using a tag to router link and a forgotten link here do
link you can use an a tag, I think it's a little better and more consistent to use a router link.
So let me go to the browser and refresh.
And now I have links for all of these. Now, I don't really
want it to have the pet's name, I want the ID. So let me go back and change it. And instead of data
dot value, which will give me the name of the pet, I'm going to do data dot index, which will give
me the index of the row in the array. So let me go back to the browser and try this. And now if I let
me go home. Now if I go and hover over it, I can see the link gives me the index. And if I go here,
you can see in the URL, I have pet slash zero, which is the ID of the pet in the array.
So now I
want to populate this page with the details on the individual pet. So what I could do is take these
pets arrays and import them into my pet component, and then get the index off of the router variable
and just look in the array in this component. But I'm actually going to put all of the pets, dogs
and cats in state and then pull the pet I want from state. So let me go to the store. And this is
a very small project. So I don't need to do this but I just want to show you how I generally set
this up. I make a new folder called store and in store, I make a separate file for everything.
So I have a file for State DOT j s, and one for you tations dot j, s, and then one for actions
dot j s. And now I'll make an index file to tie these together, index dot j s. And I'm going to
take what's in store right now.
Take all of this, copy it, put it in the index file. And now I'm
going to import the other three files. So import state, from state port, he tations from mutations,
import actions from actions. And now I can use the shortcut here. And here, oops, this object and
get rid of that. And now of course, I need these to be actual objects in each file. I'll just for
some of these export a blank object for now. Same thing in mutations save the save this. And now
in state, I'll have a blank object. But I'm also going to be importing the cat and dog data. So I'm
going to import cats from a directory data slash cats. And I'll do the same thing for dogs. Oops
dogs, and dogs. And now on state now this object is the default state of my application. So it's
the data that I'm going to be able to pull into any component that I want. So for right now, I
will have these separate, I'm going to do cats and dogs as separate arrays on my state.
what I can do with this is go into my cat stop view. And instead of importing cats from here, I'm
actually going to import something from view x, called map state. From view x, and down here, I'm
going to use a computed object computed. And the syntax for map state is to use a spread operator
and call the function and pass it an array of the items on state you would like to be able to access
from this component. So here, I want to access cats from state. So I won't actually need this in
my data anymore. And I'm going to get rid of it. So now I can get it directly from my view x store,
I'll get this array. So let me go to the browser, make sure that's working. Go home refresh. Now,
let me go to cats. And it's not working. So I must have an error.
Let me see what error I have
none here. Let me go to the terminal. Now that looks good. So let's check the dev tools and see
if we have a problem with our data there. And in my view, Dev Tools, I can see cats is undefined.
So let me see why it's undefined. If I go to my VS code, it seems like I am mapping the state
correctly from UX.
So let me look and see if it's in the view x dev tools, maybe view x. And
in my base state, I don't have anything in my base state. So let me see why nothing is in my
state. If I go back to VS code, so I'm pulling in the store from here. So I think the only thing
I'll have to do here is just delete this old file, because now it should look at the relative path
store, which is now a directory. And since I'm not specifying a file, it's going to look for
the index.js file. And I'm exporting as default the store from there. So let me go back to the
browser. Refresh. Great, now it's working and I'm getting the appropriate pets. So now I'm going to
do the same thing for dogs.
So I'm going to take this actually the whole computed here and go to
dogs. And I'm going to add that computed object here. And I also need map state to connect the
view x state from the store to this component. And I'm going to map dogs here. And I'll get rid of
dogs in data. Perfect. So now how do I figure out whether it's a dog or a cat in the pet component,
I could set this up a few different ways.
But for right now, I'm just going to put slash cat's here.
And I'm going to turn this into another variable. And because this isn't in my dogs component, I'm
going to copy all of this and come back to dogs. Instead of the end here, I think I missed the
template. Oh, yeah, that's actually important. So I'll come back to this. And I'm going to close
the table here. And I just need to change this to dogs. Now in my router, I'm going to have to
change this to store this species. And then the Id let me just make sure that's working back in the
browser. Now. If I click on one of these, it takes me to the species and then the ID. And now I can
access these from my component. So back in my pet component, I'm going to say this start route,
actually, because of in the template, I don't need this.
So I'll just say route dot, I believe
it's params dot species, and then duplicate this row. And Id. Let me see if that works. So back
in Firefox, and it does work as a species and the ID. Now quick way for me to get to the right
cat in this component is to pull in the cats and dogs from state because this component is its own
view, and is not connected to cats or dogs. So I'm going to copy the script tag here, and then modify
it. I have map state, which I want. And I'm going to add dogs here.
So I can listen to cats and
dogs from here. And I just want to mention real quick that you could do this same thing by saying
cats, adding as a method here, and then returning something like this dot store, dot State DOT cats.
And this is actually the same thing as doing map state here. But you're never going to see this in
an application. This is pretty much the standard syntax. It's shorthand. And it's easier to do,
because sometimes you have a lot of elements on state.
And it's much easier to just use the map
state method. And now I have access to these in my DOM. So what I want to do is find out if it's
a cat or a dog, and then display the information here. So I'm going to make a method for this real
quick. Methods object. I'm going to call it pet, pet. And inside of pet, I'm going to check for
first this species. So I'm going to say that animals equals Actually, I need this here, this
dot route dot params dot species. And now this will either return cats or dogs. And so I want
to access it on my this object. So I'm actually going to pass it in as a variable. If this is
confusing to you, then it's the exact same thing as accessing these arrays off of state.
So I could
do this cat or this dot dogs. But I can also use the bracket syntax and pass in a variable here. So
I could pass in this cats, which is exactly what I'm doing right here. Get rid of that. And now I
have my animals here. And on my animals, I want to see which animal I want to display. I'm just using
an index right now. So it's easy. If I was using an ID, then I would have to search through the
array and find the animal with the correct ID. So for right now, I suppose I'll just say animal, and
then pass the index of the animal which will be route.params.id. So I can do this.route.params.id
here. And that should get the correct animal. And now I'm going to return that animal and I should
be able to use it in my DOM. So let me see if this works. And instead of all of this, I'm just going
to have animal dot name. Go back to my browser, see if I don't have any errors, but I do.
yes, property or method, animal is not defined, of course, because I called it the wrong thing.
So the method is called pet. So I actually have to get rid of animal here. And I'm calling it pet.
And then I'm returning animal from here. So this should return the correct animals name. And let
me check it back out in the browser. And great. So now, if I click on, let's say, kick cat,
it shows up with the correct name. Of course, this is a little bit messy. And I don't want to
be calling the method every single time I want a property off of this animal. So what I can do is
in data, I can put animal and set it equal to an empty object. And then here, instead of methods,
what I could do is put a lifecycle method here. So I can say, for example, when the component is
mounted, get rid of this.
And now I can set this dot animal equal to animal, which will set
animal on my data object, and then appear, I will be able to access animal dot name. And let
me wrap animal dot name in an h1. Let me close my h1. And I'm going to add the animals age here as
well. So animal that age, close the p tag. And I think I have a breed property. So let me just add
that one real quick, too. So animal that breed. Now I'll go back to the browser. Awesome. So these
are old errors, I can just ignore them. Now I have the name of my pet the age in years, and then the
breed. And this works if I have dogs as well. Now, I could probably put something to denote whether
it's a cat or a dog here.
So I think I should take this species. And I'm going to add that in
here. And I'll put it inside parentheses. And then I also want a label for the animals age. So
here's old. And for breed, I'm going to put this, I should have this year to four age, I can put
here and that should look a lot nicer. And now when I go here, I can see I have labels on these.
And I can now see if it's a cat or a dog. Great. So another thing we probably want to do is be
able to edit these animals to add CRUD operations. And that will lead into how to use actions and
mutations in the store. So let's jump back into view x. Let's start by adding the functionality
to be able to add a pet. To do this, we're going to have to append the new pet to the array in
store to one of the arrays.
Now the pattern that you'll generally see for doing this is definitely
not updating state directly. Because that's what mutations are for mutations are there to update
state for you. And generally speaking, you will call it an action that calls a mutation, which
update state. And a lot of the time the actions that you call will be where you're also making API
calls because they're asynchronous. So we're just going to use that pattern of using actions that
call mutations that update state. So in actions, I'm going to add an add pet method. And view gives
me a context object here. And then I can use an argument when I call this function. I'm just going
to call that pet for right now. make this an arrow function. And with context here, it has a couple
MIT method on it.
So I can use commit. And this will call a mutation for me. So I'm going to need
to create a new mutation. And I'm going to call it append, pet. And I'm going to append that
pet with my new pet object that's going to be passed into this function. I want to make a note
here that this is generally not how you will see this being used.
Because context, you only need
the commit method off of it. So you can actually pull that directly off the object here. And this
is generally how you will see commit being used. And remember, this object comes from view x. And
this pet is the custom parameter that we're going to be passing into the function. Now I'm going to
copy this name, append pet, and go into mutations. And I'm going to add a mutation called append
pet. Here, again, we have two parameters. So the first that view x gives us is state. So we have
the application state. And then the second is whatever payload we're passing into this function.
So that would be pet here. And I'm going to make this an arrow function again. And from here, we
can mutate or update state. So I'm going to say, so State DOT whatever species, which is an
array, so I can actually push the new pet onto that array.
To do this, of course, I'm going to
have to pass species into this with pet. So here, I'm going to change this so that I'm passing in an
object with pet, and also the species of the pet. So for shorthand, and because I'm just passing
this straight through, I'm just going to call it my payload, which will have payload dot pet and
payload dot species. And I can pass this payload directly into my append pet mutation. And from
here, I can D structure this and say, species, and pet and state that species, which will be
cat or dog, and I'll push the new pet onto that. And that should append to either our cats or dogs
arrays. So I'm going to do this for cats and dogs at the same time. So I'm going to go to home and
add a button here with a bootstrap class of btn. And I think btn primary to give it some color, I'm
going to say add new pet, and this should toggle and add new pet form.
I'm going to add a methods object and say, toggle pet form. And this dot pet form equals
the opposite of this pet form. And of course, this is going to be a Boolean. So I also need
to add data method and return an object of my data variables. And one of them, of course,
will be pet form, maybe to be more explicit, I should say, Show pet form. So it's obvious
that it's a Boolean. And to start off with, I don't want to show this pet form. So I'm
going to say it's false. And then every time that this method is called, it will toggle the
form from showing. So now we actually need the form. And for that, I'm going to copy of view
bootstrap form. And I'm just going to take this most basic form at the top and then modify it. So
I'll come down here and copy everything in B form up b form. And now back to the code, going to add
that form here.
That looks good. And I have to of course, update all of these functions because
it's not going to run right now. So get rid of at reset, which I'm not going to use now show
pet form. So it will show this pet form if this variable is true. So this button will toggle it.
And I'm going to make a handle submit function for when the user submits this form which will
have Eventually call our action.
Right here, I'll add the handle submit function. And for right
now it's not going to do anything. So let me just fix the rest of my form real quick. We want the
pet's name. First and foremost, we don't need an email address for the pet. So I'll get rid
of that one. And now this example input group, I'm going to say pet's name.
And for the drop
down, I'm going to say, species. And for options, it will just be an array of cats and dogs to
choose from. And that should give me a good drop down menu. I'll add one more form group here,
copy this one, and overwrite the check boxes. And I'll say pets age, enter age here. And type will
be a number. Now here, of course, all of these v models I need to update. So I'm going to make
a new data variable here, I'm going to call it form data. And it's going to be an object that's
going to model all of my different form inputs. So I'm going to have form data dot name, which will
start as an empty string. And I'll just give age a default of zero for right now.
And species, I'm
going to say is no. And let me update these here. So form dot age, formed that species and name
is fine. So also need to update this to form data instead of just form form data and one more
form data. So our form should be functional all the way until submit right now, let me just try it
in the browser, I have the add new pet button. And it's not toggling the form. So let's see in the
Vue JS dev tools, in app in the home component, show pet form, doesn't switch to true ever. So let
me say true here. And it does show the pet form. Now I know where the errors happening, I go back
to my code, I can see that this toggle pet form is never being called. Because I forgot to add it to
the button. So I'm just going to do an add click here.
Say toggle pet form. That should work back
in the browser, refresh. And now it toggles on and off. Great. Let's hook up the submit button. In
in the same way as map state. To do this, we need to add map actions to methods. Now the reason why
we add the actions to the methods and the state to computed is that we are watching for changes to
state. And we're not watching for changes to these static methods. They're just functions for us
to call so that we can get state updated. So now I'm going to pass in an array. And my action was
called add pet. So I'm mapping that to my methods. And now I'm going to call it from handle Submit.
And I can do that by just saying this dot add pet and then passing it the payload. So the payload
is an object that I'm going to create here. So const payload equals this object, and the payload
should have the species and then it will have a pet object with things like the name and age.
to get this information. I'm going to pull it off of data here. So the form data object. And I can
do that by using this syntax. When a pull species age and name off of this that form data and put
this in the wrong spot. So Click this outside of that object. And now here I should be getting all
of my right information, passing it as an object with species and pet as the payload. And then this
will go into the actions here as my custom payload that I'm passing through to a mutation. And the
mutation will have species and pet pulled off payload. So I can update state cats or State DOT
dogs and push the new pet. Let me see if this is working in the browser. refresh this add pet,
add Bosco, and is a cat Smit, okay. So if you notice the page refresh here is pretty quick.
But it's not actually going to submit the form correctly because of that refresh. It's handling
it in the default way when it's supposed to be submitting a form to a server. But of course,
that's not the functionality that we want.
So I'm going to come back here, go to home. And now
for our submit handler, I'm just going to add that prevent. And if you remember, this modifier
is just like calling event dot prevent default, just like you would in a regular function submit
handler. But this is a shortcut that view has. So I'm going to come back to the browser. And now
if I add a new pet, cat, the age is 22. And I'm going to submit this. And I think it's submitted
correctly. But of course, we're not clearing out the form after so there's no feedback, whether or
not it's submitted.
So let's go to cats, and we see a cat is appended to the table. Awesome. Now
I just want to clean it up a bit and clear out the form when I'm done. I'm gonna see, no, it's clear
now. But I wanted to clear right after I submit to give some user feedback. So if I come down here,
I'm going to add something to reset the form after Submit. So I'm gonna say that this start form
data equals an object. And I'm going to reset it to exactly what it was before. These. Okay,
now, let me try to submit another pet. This time, I'm going to submit a dog 12. Submit. And now it's
resetting the form after it's submitted. And let me go to dogs here. And it correctly added the
dog. Of course, there's a lot of other things we could add. But that's basically how view x works
is that you'll call an action from a component and actions are asynchronous. And then from the
action whenever you're done doing what you want to do with the action, you call a mutation, and
then the mutation update state, and then whatever components are listening to state, because
you're mapping the state to a computed function, those components will update in the DOM, where
Now I want to show you real quick how getters work. There is actually another object
that goes into the store. And it's called getters. So getters are like computed properties. But for
your view x store, what does that mean? Perhaps you want to pull state into a component, but you
want to modify what the component receives while you're pulling it. So it won't actually update
state, but it will get back something that you want out of state. For example, we could count how
many animals we have in our arrays in a getter, and then call that getter from everywhere, we
want to get the number of animals. So let's just create that real quick. I need to first create a
getters object and a getters file. And it's the same as the other view x objects. I'm going to
export default in object here, and I'm going to call it animals count, which is a function and
here I'm going to have access to the state and I can do whatever I want with the state before I
return it to a component, another arrow function, and if I want to get the total count of
both cats and dogs, I could say something like state that Cats dot length plus state that
dogs dot length.
And now, to use these getters, I need to put it in one of my components. So I'm
actually going to put this in the home component. And I'm going to put it just above the button. So
I'm going to say, animals count here. Of course, I need to map this. So there's another method
called map getters. And I need this inside the computed, because we're watching for changes on
this. So I'll put map getters here.
And this is using the spread operator as well. So that's a
method with an array, the same format, and that will be animals count, let me make sure I got that
right. Animals count animals count perfect. Let's see if that works in the browser, if I go home,
and I see I have eight, which is exactly how many animals I have, because I have four cats and four
dogs. But of course, pulling this from a getter didn't update state at all, is just modifying
how state is seen by a component. So I can run whatever function I want.
Now, one common thing
that you'll be using getters for is for filtering, so I can say something like get all cats. Now,
to do this, I'm going to need to create another, we're going to need to create another array here.
And this time, I'm going to call it pets. So instead of cats and dogs in separate arrays, I'm
going to give it one array, cats and dogs. If you haven't seen this syntax before, it's basically so
that the array is flat, because if I just put cats and dogs without the three dots behind each, it
would come out being all of the cats in one array, and then all of the dogs in another nested
So this is an easy and nice way to make all of the pets together in one array.
So now that all of the pets are together here, I'm going to need to add what species they are
inside the data to differentiate between the two. So I'm going to add species is cat. I'm going
to copy this and just paste it in all of these. one extra. And I would put this in dogs too. But
just to show the getter example, I'm going to say get all cats will be return State DOT pets, which
will have both cats and dogs in it. And then dot filter, the filter method takes a function,
which will give us each pet one at a time, and allow us to return just the pets we want in
an array. So I'm only going to include the pets in the array where pet sees me pet that species
And now I should be able to use this get all cats getter? Well, once I add state from
my component, and I'm going to do that here. So I'm going to say add another variable, get all
cats. And I don't want to print out all of those objects. So I'm just going to put length to see
how many cats is returned. And of course, I need to add that inside my getters.
Get all cats. And
now I should be able to call this from the DOM and check how many cats are returned versus the
total number of pets. Back in the browser. I see it's getting the correct number of cats versus all
pets. In case you can't see, there are four cats and eight total pets. That's basically how getters
work do used a lot for filtering or making changes to what's going to be rendered on the DOM. You
can do a lot of different things with getters, you could also pass in other getters. So here I could
actually call another getter inside this getter, because view x gives me that as a second argument.
This whole system is pretty simple. Once you've practiced it a little bit Another thing that I
think would be helpful in a production application or as you're building your personal projects,
that is setting up SAS inside of a project. And this is how I generally do it in view. So I add a
folder inside of source slash assets called sass. And then I have an index dot sass file.
And I make
a couple folders inside of my sass directory. So I have my components, and my libraries, and my
global styles, which I usually call base. And then I import all of these files into my index.
So I'll import first libraries, and then base. And then I'll import components here. So inside
of the libraries folder, I might have mixins, or material design or whatever other sass files I
want to import here. I can also import CSS files, I just renamed them dot s CSS, because any valid
CSS can also be used inside of dot SCSS files, which is a type of sass file. I just prefer
to use invented syntax without curly braces, or semi colons. And there are some extra shortcuts
that you get with the indented syntax that I like. So after the libraries, the base files, I'll
generally have something called variables, dot SAS.
And now this underscore is just a
convention in SAS to mean that this file is imported into another file and not compiled as an
individual file. So I have a variables file. And here I might do something like, set my fonts as
a variable. So I could set let's say, main font. And set that equal to I'm not sure how vedika
if that's right, or whatever, Google Font that I've imported, or any other font, and then sans
And do colors and padding and spacing, I'm just going to do maybe a blue color here,
which could be 000034. And then you get the idea, you can put pretty much anything you want to be
able to use in other parts of your application, and then you can just change it in one place.
And this also makes it easy. If you're doing different themes, or letting a user choose their
theme and their application, you just save all the different themes here and then attach them to a
So now that I have some variables here, I can import this into my main sass file. And
within at import, I'll say base slash variables, and I don't need the underscore or the dot SAS on
the end, it's going to look for either dot SAS or dot SCSS files.
And I think this makes the file
look really clean, it's easy to look through a whole list of these. Now in the components,
let me just pull up one component here, let's say a view and my home view. And it starts
out with the class home. But generally, I don't think this is descriptive enough. So I usually
call things like home view container or something like that in my project. And this is a wrapper
class so that I can contain my nested classes, and they don't affect other parts of the application.
Because my global styles will all be in base.
But each component that I make will also have its
own styles. So I'm going to create a new style file for the home component. And then I put this
wrapper class, and then any other classes that I want to affect the home component I'll put nested
inside of here, just so you can see the nesting, I'll put four spaces instead of two, which is
generally what I use whenever I'm doing something like Python or SAS using indented syntax, because
it makes the indentation easier to see. So now I'm just going to say color and use my color variable
that I'm also importing into my index file.
So now in components, I will add import, base slash home
Now I have styles that are specific only to the home component. So how do we get these styles to
apply to the components, you have to import them into the main.js file. So right below where I
have these bootstrap files imported, I'm also going to import from the assets folder, sass, and
index that sass. And now, that should apply all of my sass files to my project. Because if you
remember, when we created this project from the vcli, we chose sass as the preprocessor. So the
vcli, set up all of the sass processing for us, and being able to compile it to CSS and things
like that, which makes it really easy to use sass inside of projects.
So it's complaining about this
app import statement. So let me add components here. And now it's working fine of the the text
is not turning blue. Let me see why that is, if I go to inspect element, it is actually blue.
But it's just so hard to tell, because it's not a very bright color. So let me change that to
a brighter color. If I go into the variables, and I'm just going to change this to any color,
not necessarily blue, just so it shows up.
I have no idea what color this is okay, purple. And it
doesn't affect any other page here. Because I am using a namespace in sass. So it only affects
anything inside of this class, which is specific to the div wrapper around home dot view. So
hopefully that makes sense. I do make usually one of these components for every single of my
component files. And then in global styles, I'll put inside various styles in the base directory.
So that's enough about sass, I just wanted to show you how I usually set up a sass project. This
code will all be online, if you want to see it, I want to change one more thing that feels a
little bit dirty about this project. And that is to pull this table out into its own component. In
my components, I'm just going to create a new file called pet table dot view.
And I'm going to use
this as a table inside both cats and dogs. So to start this, I'm going to just steal this template,
put it here. And to make it unique for each one, we're going to need to pass in some props to this
component from both our cats and dogs views. So I need to have props are my default object. I'm
going to make this an object and say first of all, I think we're going to need a species, which
will be a string. And then here, I can replace this with species. It's gonna be lowercase. And
here I'll replace this with pets because we'll pass either cats or dogs as pets.
And pets will be
in array. And then here I also want to use species to dynamically pass. And I think that's it really,
we just have to import pets table. Let's import it into cats first. So import pets, or pet table.
From at components slash pivot table dot view, and I need to set it as a component I'm going
to use my Dom here, components pet table. Not sure if I mentioned this previously in the
video, but using pet table as a component here, I can do this in two different ways.
I'm going to
get rid of this and I can use it capitalised or view gives me another default way to do it. Which
is kebab case by default to make it more HTML like I could do that. Generally the recommended way
that I've heard from members of the core team and others and also from using it myself, is to
just keep it capitalized. And that lets you see the difference between the custom components that
you create and the other HTML tags like div So I'm going to be passing in this species here. And
I know the species is cats. So I don't have to do anything else to that. And I'm also calling for
the pets or the cats, which I need to pass in.
And I have that array here, mapped through computed.
So I'm going to pass that in using v bind as pets pass in the cats array. Of course, this is kind
of confusing, because these have the same name. But this one is an array because we're using v
bind. So view is looking for a variable. So it's actually pulling this variable cats array off of
computed and sending it in as pets. Now species, we're not using v bind here, so it's just static.
So it's the string cats. And let's see how this works. If we go to the browser, and go to cats,
it's still working the same way.
So I'm going to copy this for dogs. Go here, into the dogs
component, and get rid of all this table stuff here. except we're going to be passing dogs in
for both of these. And then we need to pull in the pet table component from here and also add
that component so that we can use it in the DOM. And I'm going to add it here. And then it should
work still for both cats and dogs refresh.
And it works for dogs just as well. And we can still
see that we have the correct number of both being pulled in. So that's all for this view tutorial.
If you're interested in going further with view, let me know and I might make a more advanced intro
to view in the future. Here are the resources I think are most helpful for getting into view.
First, there's the state of uJs, which is a yearly report put out by ovenu, who's the creator of
view, he gives lots of great talks about how the project and library are evolving every year.
you can find those for free on YouTube. Another resource I highly recommend is somebody who's the
senior view developer called the Jared Wilker, he livestreams. Various tutorials mostly about
view every Thursday night at 7pm. Eastern time in the USA. He's a really great teacher. So I
highly recommend jumping into some of those chats and asking him questions. Then there's one of my
favorite people on the Vue JS core team, Sarah dresner. Now I didn't cover animations in this
tutorial, but she's actually the best person to talk about those types of things. Vue JS has a lot
of great built in animation features. I'm going to link a video of a talk she gave on view animations
that I think is really good. One last thing I recommend for getting into view is checking out
the views on view podcast. You can find it on dev chat TV, or on overcast or any of your other
favorite podcasting applications. Thanks so much for watching this whole tutorial. I know it's kind
of long, but I hope you got something out of it. If you have any questions or feedback from me.
can find me on Twitter at Gwen underscore Faraday, or shoot me an email at Gwen firstname.lastname@example.org. I
also have a YouTube channel called coding with Gwen that I'm going to be starting back up here
soon. And this is kind of a kickoff video for that. So if you are interested in more of these
types of videos, you can check me out there thanks.