Transcripts
1. CoursePromo: Do you want to
build mobile apps? Do you want to target
androids or iPhones? If you'd like to build
your own mobile app, but don't want to
take the time to learn multiple technologies. Then this course is for you. With hot technology
such as ionic, you don't have to ignore
standard web technologies such as HTML, Javascript
and typescript. I'm going to show
you not only how easy it is to build
your own app, but also how fun it can be. Furthermore, you'll
be able to write a single application that works on both
Androids and iPhones. Take a look at these apps. All of them were
developed with ionic. And these are just a few
that I built myself. There are thousands more. In fact, almost 20% of every application is an ionic
app. How amazing is that? Some of the major topics that
will cover in the course include building the UI
with the ionic framework, highlighting the work
that ionic does for you, creating a demo app that looks perfectly at home when
running on iPhones, androids, or even
desktop browsers. I'll show you how to create a native looking experience with ionic components such as menus, cards, action sheets, alerts,
and toast notifications. We'll use a split pane
layout which works as well on a large desktop or tablet
as it does on a small phone. By the end of this
course, you'll see just how simple it can be to build a real world functioning mobile
application with ionic. Now, before beginning
this course, it will help you
for familiar with the basics of web
development using HTML. I don't expect you
to be an expert, and I'll cover the more
complicated topics as we go. If you know how to
create an HTML button or add a click handler,
you should be just fine. So get your app ideas ready and join me on this
fast paced journey to learn how you can
become an expert in mobile app development
with the Ionic framework.
2. Introduction to Ionic: Crafting Your First App: All right. So welcome everyone
to what I hope is the first of many ionic Angular
mobile development workshops. As I've mentioned,
I'm Mike Callahan and looking forward to going through this and building
something with everybody. In the chat, I've
given you these URLs. The first one is the hub link to the project that we will build over the
course of the workshop. So it's everything
completely working, so you can use it
as a reference. The second URL is
a get ub gist with some convenient files so that you don't have to
type everything out if you don't want to. The next two are my
contact information. You should already have that
Michael at Walking River, and my Twitter handle is
at Walking River. Okay. I assume you have
general programming, HTML, and a little
bit of javascript. I'm going to be using
visual studio code. You don't have to, but that's where my
screenshots will be. I'm also a huge fan of angular
essentials by John Papa. It is a collection of extensions that make angular
development easier. There are also a couple of
extensions for ionic snippets. I haven't found those quite as useful as I would
hope they would be. But I find this one to
be absolutely essential. Okay. Do you need
to know angular? It's not necessarily we're not going to spend a
lot of time on angular. The concepts, if
you need something, if it doesn't make sense or
hey, Mike, what is that? Stop me, and we'll go over it. As a general rule, We're going to be using the
following angular isms. So we'll make use of G
four and G directives. We'll make use of angular
separation of concerns. I know there's a
lot of talk lately of smooshing everything
together into a single file. And there's the new Angular
14 experimental support for module free components. I'm going with old school
here. It's angular. So I will have JS file, different CSS file,
different HTML file. If you are so inclined, you're free to combine
them together on your own. These are the
binding expressions that we will probably use, and I don't think we'll get any more complicated than that. The first one is a
text expression. So if you have a variable
called in this case, EXPR on your component, and you want its value
to be in your HTML, you simply surround it
with two curly braces. If it's non text or you simply
prefer the second style. You can put the variable name quotes without
the Carla braces, but you put the name of the thing you're binding
to the attribute of the HTML element in
square brackets. The only time this is important is if the variable
you're binding to is not a sting For example, if you were binding to let's
say the disabled attribute, and you want to
disabled to equal false and you use the first expression
with the curly braces, you would actually be
binding to the string false and that may
or may not actually evaluate to false
at run time because the string false is a
truth evaluate or can be. Finally, the click event there. So I anytime we want
to bind a function on our component to an HTML event. You put the event name in parentheses and the
function you want to call in the quotes. That's about as much
angular, I think as we need. Okay, so we're going to
move through all this. This is my intro angular. Okay. Everyone has the
ionic CLI installed, right? That means you already have the node CLI installed as well. It's probably not critical except that I believe
the Ionic CLI requires Git or at least
assumes you have it. Let's say you already have no G. Everyone is installed on. Yes. If not, NPM
install G at on CLI. Those of you who showed
up early or earlier saw me do it just a little while ago because I
was on an older version. All right. So we are going to build a very basic UI and on. It's going to consist
of a home page, a student Roster page, a student info page,
and a side menu. This is essentially what it
will look like. Excuse me. So this is the
home page. This is where the application
will start. The Roster page when finished
will look like this. It'll be a list of
students in our class. The rooster page is
built with an on list, which is an ionic component, and it has on icons, on buttons, and all sorts of
cool ionic features that we'll implement as we go. The student info
page is where you can it an individual student. This will be ionic forms, a little bit more
into ionic storage. As you can see, we will
get there eventually, integration through capacitor to access the device camera. All right. So let's get straight to building
the application. Wherever that we need
that is short cut. I put the ist link in the chat. It'll also be here on
any slide where we're going to need it or where
it might come in handy. The first thing we
want to do to create an on app is to type
the command on start. Let's go ahead.
Let's just do that. I am not going to use
the app creation wizard. It's cool, but it's
not really necessary. If you want to play
around with it, you're welcome to do so. I'm going to use angular. My name is going to be. I'm going to call
attendance time. I'm going to have a
side menu eventually. But the side menu template gives you a lot of boilerplate
that I don't care for. So my preference is to start
with a blank ionic app. It looks like we're getting
capacitor by default. That's fine. And it's going to go and install all of
this stuff for me. Move that out of the way
there. Don't need to see. Is everybody following
along, okay? Yes. Yes. Thank you. Well, there you go. Now, in order to go
ahead and see this, you simply need to
type ionic serve. I have to be in that application first, I have to
be in the folder. CD into that? Then
I can ionic serve. And as you can see here, ionic serve is really
just delegating a lot of its functionality
to the angular CLI. So I typed ionic serve and the ionic serve went ahead and generated
this command for me. G run, and it automatically
launches my default browser, which in my case is Safari and gives me exactly
what I asked for. A blank application
with a lot of content. Okay. Now, is everyone following along and have you
gotten to this point? Yes. Yes. All right. Almost there. Almost there. All right. I'm going to
move to the next slide. What I wanted to
discuss real quick are the developer tools or the
browser developer tools. If you are on Windows, you simply need to type F 12. If you are on a Mac,
it's Command Option And obviously, it
doesn't look like. Yeah. I'm there. All righty. With the developer tools open? You should be able to. I can never remember
how to do it in Safari. There we go. Enter
responsive design mode. So now I can emulate
different apple devices. If you are not in Safari, no, even if you are in Savi, if you're on I guess any device. I recommend using Chrome or edge for the developer
tools experience. The really cool
thing and you won't see it here. You'll see
it in a little bit. But let me bring
this up in edge. Actually, let me
bring it up here. I've already got it
here, so I can show you what I want to show you. In edge if I tell it, I want a device like
an iPhone 12 Pro. It gives me what
I'm looking for. It gives me the
right resolution. So I can choose an iPhone. I can choose an android. Notice it doesn't
change a whole lot, but this is where it
gets really cool. Let me go into. Let
me refresh the page. Once the developer
tools are open and you've set your device, and you refresh the page, ionic will recognize
this and say, Oh, you're running
on an android. I'm going to change
the way this looks. So your icons will
be Androidified. Your buttons will be android, your dropdowns will be Android. So everything should
look Android. So notice how these look. And then when I click
the start button, this is an Android model. So let me switch over
back to an iPhone. It won't change yet until
I refresh the page. See the difference. This is what an apple
will look like. I can go back to setup, the button a little
more rounded. The drop down looks different. The icons a little different, side menus is a
little different. Everything is just a
little bit different. You'll see on an apple device, your titles center justified, where any of the
Androids, it's left. So you're going to get all
of this functionality, this visual change out
of the box with ionic. And that's one of the
major reasons I use it. Okay. So this is what we're
going to be building. So I have here. Like I said, F 12 to open your dev tools and windows
or command option on a Mac. I just showed you the
different design. That's the button to enter the responsive design
mode on Safari. Okay. Come on up nine. Okay. And I already
told you about this. If you switch from
one to the other, you have to reload the
pages to see the UI change. Okay. Now let's build
our first ionic page. Or in this case, we're going
to build an interface. I am going to leave,
I'm going to quit. Okay. So I'm going to use the
on generate command. I can also do with G interface. So I'm going to ask
the ionic CLI to generate typescript
interface file for me to hold the
definition of a student. And it was that quick. I'm also going to open Sd
onto my project, correct? Okay. Is there a way you can make your
front a little bit larger when you have
that? I absolutely can. How's that? That's
awesome. Thank you. I'll do the same thing here. Command plus, by the way. Right. The interface is in my source folder app student. Not a whole lot in
there. Move that out of the way for you. Okay. Okay. So that's
one of the places where that gist
will come in handy. And that is Student
TS right here. I'm going to grab the raw file. Again, you don't
need to see this, but I'm lazy and don't want
to type all this over again. So this is the
definition of a student. Does anybody know why I'm making my student an interface
and not a class? Any type script wizards
you want to weigh in? Does anybody know what
a type script interface compiles to when it gets
compiled to Javascript? No. Okay. Let me see
if I can show you. Have you ever go to type script or I've got a pipe
script playground. And on one side is
the typescript, on the other side
is the javascript. If you enter Avian interface,
that's what it builds. Absolutely nothing.
Interfaces don't exist. So they are purely for
developer convenience. If on the other hand,
I created a class, It's not a valid class. Why is that not a
valid class? Okay. Oh, I see. Need stuff like this. So not a lot more code, but it is more code code. And quite frankly, I
don't need a class. I don't my student object doesn't have to
have methods in it. So if it's just a
data transfer object, I will always opt
for an interface. Okay. Okay. So let's take a quick
look at that interface. Each student has an ID,
first and last name. Does anyone know what
the question mark means for the rest
of the fields? Option. They are optional. So
the birth date parent name a parent e mail
phone, et cetera. These are all optional. I'm
not going to leave this here. This means that I can create
this won't be valid, though. So I can create a well, Hub copilot do it
do the work for me. So I can use an object
literal initializer. Oops. That's right. All right. Now pile is getting a little overzealous. Okay. If student was a class,
I couldn't do this. I couldn't use an object
initializer like this. Okay. It wouldn't be valid.
I would have to use new student and then pass either the values through into the constructor or do
the fields individually. But because I have an interface, type script and Java script will let me initialize
a brand new object of that type just by
using an object literal. Plus, because it's an interface, I get errors if I don't provide all the fields
that are required. Finally, who can tell
me what status means? Why didn't I set status to
what is line ten there? This is more of a another
type script question, not an angular onic question. Although angular is part
of the reason I did it. I'm not sure if it's just like
some sort of custom type. It's limiting the The value to be either present or absent? Correct. Defined in this
case as it's optional. Correct. So most people especially if you're
coming from the.net world, you're probably used to
doing this with an nome. So you'd have an enum
where present equals zero and absent equals
one or vice versa. And then the compiler would ensure that it was
strongly typed. The problem with doing that in angular is that your templates
can't see those enumes. Unless you then create a local variable to hold
the num and it gets weird. But if I do it this way, I'm essentially
telling typescript that the value of
status is a string, but it can only be a string
of one of two values, like you said, and I'm
going to get intellisence. So it's automatically
telling me what my values are. Pretty slip huh. Okay. Michael, you could add an integer in that
list, couldn't you? You mean. Like that. Yeah. I like what
Co Pilot suggested. Has anyone used copilot? I meant to turn it off. I I found it useful. I found that Co Pilot is pretty good at knowing
what I want it to do. And it's really good at
building unit tests for me. Okay. Any questions on
the interface? All right. I had a question. My
inter is complaining. I think it's because the TS
conflict file for ionic? That's not It's using
TS and not ES in. Did you notice? I haven't. Is that what it's doing? Are we still defaulting on
still defaulting is S n. Min is two, so. I don't know why he's
complaining about it. Yeah. I don't see
any TSN in line. No. Okay. Something's complaining
about this, but I don't. Microsoft Dad is
complaining about it. So can you show us the plug in for a copilot
that you were using? Seems to be two of them. That's a good question. Okay. I am not currently
paying for it. So I have this one. 3131. I don't know what
this one is. Oh, nightly. Yeah. I went ahead
and I'm not using it. I'm using the official
one from G Hub. And like I said, I'm
not paying for it yet. I think I have it free for
another couple of weeks. Or maybe I'll start maintaining
an open source repo. All right. The next thing we need to do. I'm trying to do the dull
stuff getting all that out of the way early is we need to
generate a student service. This is the thing that
will handle all of the, the data interaction for
dealing with students, and that was the really big file that I have for you on the gist. What I want to do here that. Bring back my A
command line here. And there we go. Get it out of the way. Okay. So here, I'm not using the CLI. And the reason I'm
not using the on CL is to show you that they are
actually the same thing. So the ionic CLI will simply
delegate to the angular CL. The reason I prepend
it with PX is because I don't want to use the
globally installed angular CLI. I want to use the one that's
built into my ionic project. Is everyone familiar
with PX, what that does? Yes. I mean, it does
a lot of things. But the primary thing is it's
going to use the version of NG that's in my node modules folder as opposed
to my global one. Okay. So I'm going to generate a
service called students. One thing I like to do a lot. I like to use the
dry run command just to see what it's going
to do before it does it. It's going to generate
two files for me. It's going to
generate a test file and my service typescript file, and it's going to
put them directly in the app folder. That's okay. In a larger project, I
wouldn't want to do that. I want to keep a
lot of the stuff a little bit more organized. So I would tell it to put it somewhere else in
debt I could put it in service students,
for example. Now you can see that
it's going to put it in a folder called services. Well, go ahead and
leave it that way. I'll take off the dry run
flag and let it build it. The student service
is going to give us students that we can display. Without a list of students,
there's not much we can do. Again, we can go back to
my ist, which was here. Go down to the student service. Grab the version. Select a copy. Find my student service
and just paste it in. And it doesn't like that. Why doesn't it like
that? Okay. That's fair. Anyone see the immediate
problems here? This one is obvious. It's because I put the
services in a folder. So let me show you if you're
not used to this in BS code, I'm just going to
remove this line. And then I'm going to see
that the error is here. Click on it and click
on the blue Lightbulb and it's going to find it for me and rebuild that
import statement for me. Okay. This one is a little
harder to overcome. So what happens is this service uses capacitor
storage from ionic. But I don't know. Okay. We do use
it. I am using it. So we need to we need to
install capacitor storage. So I'm going to open up S
codes built in terminal, which is control back tick. And then I can simply
install capacitor storage. Okay. And then that
problem should go away. Like that. Questions,
comments, concerns. Everyone still caught up? Yes. Caught up to that. There's still a bunch of
other stuff going on that. If you feel like you're
starting to get too far behind, stop
me, let me know. Okay. Okay. So you should
have a student service now. Now, what I want to do.
The student service has an initialization
method in it. Again, just to make it
easy to get to the UI. So what I need to do
in app component T. I'm going to press Command P or Windows Control P to open this quick menu and I'm
going to type app component. I like to keep my
hands on the keyboard. Give me a second here. So
I have the constructor. And this is actually a typo because this does
not call initialize app. Is we need the app component to implement on it. And now, I'll let pilot do
some other work for me. Not a bad guess. But we need to pass in the
student service. Okay. And notice that
it went ahead and it found all that
information for us. It figured out where to
import the student service. So now. Again, not bad, but it's not
what I'm looking for. We need to market a sync
because we want to wait. Yeah. Should it be inside
the class or outside? It should be inside. Thank you. Okay. Now, what is it not like? Sorry. Here we go. I didn't import it. I don't know about
the rest of you, but one of the one
of my weaknesses, if you will, with angular.
I forget to import things. That's why I really like that
VS code will do it for me. And whatever ES setting I have doesn't a source file that doesn't have a
blank line at the end, so it's going to complain
about that a lot. Any questions here? We want to see what this is doing or do we understand
what this is doing? When the app
component starts up, it's going to call
our student service and tell it to initialize. The student service
initialization, It does a couple of things. It goes to ionic storage to try to get all of the
students out of storage. But the first time you run it through, there won't be any. So the length of that
student array will be zero. So at that point, I call data, and see data just takes these this array of mock students and puts
them into storage for me. So it gives us
something to display. Does that make sense?
Incidentally, these are all real people who agreed
to let me use their names. All right. We're
good. Moving on. Okay. I mentioned the imports. VS code will keep me honest. But if it doesn't, you are welcome to chime
in and keep me honest. Most of the code
samples that I show in my slides don't
have the imports. It it was easier to save space. Okay. Now we're going to
generate the roster page. Okay. This is where things
depart a little bit from the standard
angular CLI scaffolding. When you build an ionic
project with ionic starter, when you install the ionic CLI, Ionic gives you some angular scaffolding
that angular doesn't. Angular doesn't have
the concept of a page. I don't know if you've
ever thought about it, but when you want
to create a page and angular, you
create a component. But ionic has the concept
of an ionic page. So they give you
this scaffolding. So I can type either of these two commands because they are
functionally identical. So I can do an ionic generate
page and call it roster. All that does is it calls
G generate page. Rooster. But because Ionic
created that scaffolding for the page scaffolding
actually exists, so we can generate a page with ionic that we could
not do with angular. So again, I'm going
to dry run it. And you see it literally
just pretty well, not exactly, but the
NG generate command. The biggest difference
between building an angular component to
us as a page and actually scaffolding an ionic
page is ionic pages are built with their own module by default and
they're lazy loaded. So an ionic page will not load until at run time,
when you actually call it. That helps ionic apps, spin up, start up very quickly. Does that all make
sense? Yeah. All right. I'm going to undo my dry run
command and just let it go. Okay. I do need to make. No, I don't need to
make the change. InCars already made
this change for me. So if we look at
App routing module, The ionic CLI or the
angular CI added this forming and that's
the lazy load of the roster module
to load that page. So that means when we go
to our application and we use as our path at
the end of our URL, it will instantiate that
roster page module, which will then cause the roster routing page
to load the roster page. So we get all this for free. You can do it with
the angular CLI, but I can never
remember how you don't create a component,
you create a module. I believe it is how it works.
But I would much rather even if I wasn't using
an ionic project, I might still be tempted to
use the ionic CLI to build my pages because you're going to get that lazy loading
out of the box. So I just showed that. Now let's generate
our final page, which is our student info page. Use whichever of those two commands you
are comfortable with. Again, it's going to build almost the exact
same scaffolding. I'm going to let it go. Back in my app, you can see I have
my roster page and my student info page. Now, there's one
change I need to make. If you've ever built any
sort of master detail view, you know that when you
get to the detail view, you typically have to pass the ID of the thing
you want to see. And so this is no different. It still made a change to
apparalti module for me, but I don't have
to touch that one. But in the route for
the student Info page, I have to add this
colon ID to the path. So open up student Info routing, find the path and add colon ID. What this means is that
is in our application, we'll have a route
that looks like this. Okay. So we'll just have an ID tax
onto the end of the route. And that will get passed
as the ID route parameter. I have a question. Is there a difference from doing it this way than doing the
route parameter on the lacy loaded routing? You mean putting it putting
it in the a routing module. Putting in here, you mean?
Yeah. Is there a difference from saying the
student Info cool ID? You could do that, but then you wouldn't
be able to go into the student info routing and
make any modifications here. Maybe that's okay. So maybe that's okay. So maybe maybe you have a
path called Edit. Does that make sense? Okay. Yeah. I understand. So by putting it out
here, you'd say, okay, student Info
slash the student ID. And now, in your
student Info module, maybe you have an edit. But then maybe you
also have a Delete. And those are and what you end up having is
different components. So maybe you have a
student info page and you have a
student delete page. But those two pages would
share the same module. I hadn't thought about that. That's actually pretty smart. So yeah, you could do that.
What you can't do now, though, how would you
add a new student? Because you wouldn't have an ID. So I like to keep them I'd like to keep
them clean at this level. Okay. And then put everything in here because now you could do things like If you wanted to, now you could do You could
have student Info slash e. Okay. Yeah. And then I can reuse the same component. Right. And I believe that is
how I do it later. Thank you. Everyone
clear here so far? If not, I think
this one will make more sense as we start
to flesh out the pages. I keep looking down at
Andrew and he's like, Okay. Normally, by this point in time, I mean, I've been sitting
here for an hour and a half. When I'm doing this
workshop in person. At this point, everyone's pretty much ready
to take a break. Do you want to take five or
do you want to press forward? We're scheduled to go
till ten, another hour. Break or keep going.
I'm fine either way. Yeah. I'm fine if we keep going, that's okay. Okay.
Let's keep going. All right. Side menu. So we're going to get
into some UI now. The side menu, in this case, uses the on split pan. And the split pan
is a little bit complicated. You've
probably all seen it. When the screen is narrow, it collapses to a
hamburger menu. But when it's wide, as we see
here, it's always visible. So it's a very
responsive UI piece. The important thing you need to know when dealing
with a split pin. R, the content ID. So on the content
ID attribute of the split pane is the ID of the element on your page that's going to
hold your main content. This will be clear in a moment. This is typically your
on router outlet. So on router outlet is one of the top component on
your entire page. The disabled attribute, does
what you think it does. When it's disabled, the split
pin, the menu won't show. I can't tell you
how frustrating it is to have a disabled menu
that for bizarre reason, you can't figure out
why it doesn't show up. And when tells the split pane under what circumstances
it should be visible. It can be a Bolan. So you could programmatically
set it to true or false, or it could be a complete
CSS media query. So it could be a
media query that says screen max width of 500, for example, min width of 500. I tend to take the defaults
for things like this. So I don't tend to
mess around with them. We also have the menu ID. So when you're
using a split pan, split pan typically will
have a menu attached to it. So it's also going to need the HTML ID of the menu
that it's attached to. We also need to tell it what
side of the screen we want. Earlier versions of Ionic
used left and right, but Ionic now supports right to left cultures and layouts. So it's start and end. In most Western cultures, start would be left
and end is right. And then finally,
you need to tell it what it should look like. This is the menu type. And
I've got an animation here. I hope it comes across. I had to build this
animation just to prove to myself that these three
menu types are different. Watch them for a few seconds. Tell me if you can
figure out what the difference is
between Push and Reveal. Overlay is pretty
straightforward. But what's the
difference between Push and Reveal? Anyone? The the backgrounds
moving on Push. It's not moving on
reveal. Which background? The menu the back menu that says home in
Roster? Correct. Yeah. It took me a long time
to figure this out. In fact, I put this animation on Twitter and I still had a
bunch of people asking, what's the difference
between Push and Reveal? So you're right. The menu doesn't move in reveal. Okay. Why they fought
these up at that ionic? I'm not really sure. That one never would
have occurred to me. Seems like it's more
like drag and I kind of I think the material
specifications is what it's
considering the Z axis. So there's layers
on top of things. Does material design
typically use reveal? It's one of the specifications. The material library
is supposed to be built in a similar manner
to those specifications. But yeah material design says
there should be a Z axis. Got you. And push they're together and they're
just pushing one of them out of
the way, right? Yeah. I guess that would
be their reasoning. Very cool. I've only ever
used overlay personally. Okay. So split pane, we're going to have a menu, and the menu was going
to have two pages, the home page and
the roster page. And the way we do the
way we implement that is an array of application
pages on the app component. If I'm not mistaken. That one is also In here. Yeah. App components
already done, so we can just grab
that one from the gist. Open up app component. And I believe just paste. No, I didn't like that. Oh, I see. Because I moved
the student service. So again, I want to delete it. Come back over here and let
VS Code find it for me. There we go. And then it wants my Empty line. So now I have an array of
pages, home and Roster. So what we're doing here,
we're going to have a label for the menu title, Home and Roster.
What the URL is. So where will this
thing go? Which route? Were you going to use the home
route or the roster route? And then what icon to use? Clear so far. Next thing we do
is we're going to iterate over this array
and build the menu. So should our app have changed in the browser at all then is still
distribute plan. If you left ionic serve running, then you won't see any changes because we haven't made changes to
the homepage yet. Okay. Okay. So we've created a
bunch of other files, and we have made
changes to the app, and it should be continuously rebuilding and re rendering. But because we
haven't made changes to the homepage yet,
you won't see it. Okay. And the reason I'm
doing it in this order, essentially is the final reveal will be a little
more impressive. We did everything
right. I'm just just curious. All right. So next, This is what we're going to
do to make Well, to start our split pin. This goes in app component HTML. So right now, the only
thing in app component HTML should be the on app and
the on router outlet. So the absolute bare minimum to display anything
in an ionic app. Okay. And this one, I did not give
you copy and pastability. So I'm going to get
that out of the way. And it looks like I got stuck
on my other monitor. Okay. I'm going to pause a little bit while you all type this into your inside your on app. So you can see at
the bottom here, I have the on router outlet. So all of the on
split pane wraps the on router outlet and all of this code goes
inside of the on app tag. Does that make sense? Yeah.
I'm going to type it also. Okay. Well, do you want to watch
me type it or do you want to have me type off screen
so you can copy this. You can do it off screen,
that'll make it easier. Okay. Interestingly enough, the
copilot did a pretty good job. So inside of the split
pan, we have the on menu, and that's what's going to be on that left menu component. So we start with an on header, which is that little
gray area at the top, and the header consists
of a tool bar, and that consists of the title
with the word menu in it. That is a pattern you will see repeated over and
over again in ionic. A header or footer
contains a tool bar, which contains a title
buttons collection, which contains buttons. It's very hierarchical,
but very consistent. So in here, we're
only going to have a tool bar with the word menu
in it inside of the header. Below the header,
we have on content. Almost anything
you want to render in ionic needs to be
in an ion content. And on the next
slide, I believe, we'll put the menu
content in there. So you don't have
to type in menu. We'll go here. What is content ID in this example. Is that a directed or
some other ular thing. Excuse. Okay. So you're talking with this
content ID at the top? Yes. What this is telling
us is the split pane and the menu are controlling
things that are in another HTM element
whose ID is main content. So you'll see that down here, your on router outlet. We need to have the ID
main content added to it. Okay. That makes sense? Yeah. How is that achieved
through a view child or typically how does someone do that if
you're making your own? We don't have to go into it now. Serious. I'm not sure I
followed the question. If you wanted to create your own component that
did something similar. Would you use child
or some other. You could? Yeah. You
could use a child. I I make use of child
a couple of places. I don't remember if I do
it in here. But yeah. If you wanted your
own custom component, you mean that acted on the router outlet or something something
else that had an ID? If I understand your
question correctly, then yes, you could do
that with a view trial. Great. Yeah. Are we
ready to move on to the menu? Okay. I am. Okay. So again,
from the content. Inside of the content, we're
going to have an on list. An on list is pretty much what you'd expect.
It's a list of things. It's a collection of it's a container component that
can hold other things. Where's the content going? What files in now? This is in app component HTML. So if you look what
we're going to do is inside the on list, we're going to add
an on menu toggle. This is going to
be an on component that knows how to
interact with that menu. Okay. So we're going to
have an on menu toggle auto hide set to false. And we're going to have one for every element in our
at page of the array. So remember. Hang on. My BS code is stuck. Okay. There we go. Remember, we
have this at pages array. And so we're going
to use this N G four to loop over that array and create one of these menu toggles for every page in that array. Does that make sense? Move
this back out of your way. The next thing we're going
to add is an ion item. An on item is
another collection, another grouping
element from ionic. If you in this case, we're going to have
an icon and a label. And by putting them in an
ion item in an on list, the ionic rendering engine will know how to display
them together as a group. So the ion item is the thing
that the user can click on. Not the icon, not the label, not a button if you had that, but the entire item itself, the entire horizontal grouping, I'm fitting the
lines attribute to none so that we don't have
lines separating the items. And detail to false. But you are welcome to
change that if you'd like. Detail false gets rid of
the little right arrow, chevron on the menu. Detail, it would be there. So it's a It's a UI preference, whether or not you
want to see it. I would even say play around with it see which
one you like better. The next attribute
is router link. That is an angular thing,
not an ionic thing. So when we set in a router
link to the page URL, Angular will automatically
give us a hyperlink. We don't have to worry
about click events. We don't have to
worry about setting up anchor tags or
anything like that. A router direction is animation. So if you provide a
router direction of root, you get default animation, and I believe you can
have forward backward or forward back and root. So the animation changes subtly depending on
which one you choose. Forward and backward are
pretty straightforward, left and right, the pages
will slide in when you click. Root I believe that one just kind of fades
up from the bottom. Okay. And the last one is router link active set
it equal to selected. And I believe we're
also getting that one for free from ionic. So that'll change the class subtly if the route the
currently selected page. Does that make sense? All right. Finally,
inside the ion item. We have the page icon. Remember it said home or people. So that's setting the
icon for the menu item. And then finally, the
page titled as label. So when all is said and done, it, something like this. Are we good or do
we need more time? I'm good. Yeah.
I'm I'm caught up. No already. Okay. So now let's flesh out the home page UI and see how all this
stuff gets put together. Okay. The home page
consists of an on card. I'm going to go back real quick. On card, y
3. Elevating User Experience: Advanced Ionic Components: Okay. Okay. Everyone.
Welcome to Session two. At this point, we
should all have a class roster that looks
something like this, and tonight we're going to
try to flesh it out with some functionality and
some more UI components. And just like before, if it turns out that I'm going
too fast or if I'm skipping an important concept that isn't obvious to everyone, go ahead and stop me and
we'll slow down a little bit. Again, just like last
time when we're done, I can stick around
for a little bit and and visit anything
when we need you. Sound good? Yep. All right. So from here, I think we have the picture of the individual
and the name, correct? We don't have any of this
other stuff up here, and we don't have the
fab button down here. Correct. And for some reason, it really doesn't
like advancing. Okay. We already talked
about on icons. So I don't think we need
to revisit that again. But just as a recap, if there are icons
you want to look for, you need to know
where to find them, you just get them from on icons. Okay. So let's jump right in. And this is what we're going
to add to the roster page. And looking at this
code real quick. This is going to create the two buttons on the right
side of each student name. So we're going to create and on buttons container
inside of each ion item, and each on buttons container
will contain two buttons, and those buttons will
be composed of icon only the ellipsis to give us a detailed menu and then the forward chevron that will take us to
the Rofter page. Okay. Makes sense? Yeah. All right. Let's
see. If I can do this alongside you,
but still have it. This one's going to be tough to do simultaneously, isn't it? Let's do it this way. If I go to my rooster page, me my Roster HTML page. And we have the on list and the on om with the person outline icon and then label for
the person's name. So right after that,
we want some on buttons and inside it on buttons put equal to the end in a minute here on button handler. This function doesn't exist yet, but we're going to write a function called
present action sheet, and we're going to pass
in the current student, so each row has its own student
because of the NG four. Okay. And then inside
of the button. Yeah, we're going to use an
on icon with slot icon only, so there will be no
text to this button. And I want the ellipsis
horizontal outline. If I do nothing else, let me get my on curve going. Absolute text. Oh. Okay. You're muted. You're muted. Okay.
Okay. How long have I been muted?
Since you walked away. All right. Do I need
to go backwards? I don't think we heard when you were doing the sliding. Yeah. So we got here, right? Everyone's good with
this one? I mean, at least my resulted list looks like the one
you're presenting. Everyone has
something like this? Okay. Yep. Okay. I do apologize. So did everyone create an empty function for
presenting an action sheet? It doesn't do anything.
It just prevents us from having an error in the console? Yes. All right. So
we'll go for that one. Okay. So now, Let's
go back here. Okay. Now we're going to
flesh out the UI just a little bit more with the slider. I think we've all
seen this UI before. What we do here is
that we have to add an ion item options component. And with that, we
can add a button on either side of the item. So it'll remain hidden until the user swipes left or right. In this case, what I
want to do is create a delete button on
the right side. So if the user
slides to the left, they'll see the delete button. This is the markup that we
need to make that happen, and it comes right after
the ion items closed tag. Do that here. I find the ion item closed tag, and I add the on
options side end, which means it's going to be
on the right for most of us. Here, I'm going to
use the danger color, which is red by
default four ionic, and I'm going to give
the button a delete. So a couple of things. I think I mentioned
this last time. Whenever you have a container, an ionic that can handle
multiple things like button or in this
case, on item option. You will typically put that in a plural version of
that same tag name. So on buttons surround
contain on button objects. In this case one options contain option. Does
that make sense? Okay. And then for here,
we're going to have a click events that
I'm going to call. Confirm student passing
the current student. We're still inside the NG four,
so we still have student. Okay. Okay. And again,
it doesn't exist yet. Now, one really cool
thing about this. Let me show you this real quick. Go to the rendered page. So now I should be able to slide it and get
the delete button. And because there's no function, it won't do anything, we give
me an error in the console. But for grins, you're not limited because you're
not limited to one and that should be a given because it's got the plural
component container. So for grins if I give
it two, There's two. And so I was asking
myself one day, I wonder how many can handle. And interestingly enough, it pretty much handles as many
as you can throw at it. And it does the right thing. The markup I mean, looks
silly, but the markup works. So I found that kind of cool
but they do support that. How many did I do
I have to remove? Okay. Quite a few. Okay. And I'm assuming you can also use as an icon instead of Kevin's
words as well. Interestingly enough,
no. Because you notice this is not an on button. It's an ion item option. But you do bring
up a good point. Let me pull up I've
never done that before. So let's see if what I
says we have to do there. So that was the option. Can you put an icon in it? It doesn't look like
it supports an icon. It's in the item sliding
part of the documentation. All right. So here's
what we're doing now? No, there you go. Yeah. Okay. I'm happy to be wrong here. That does make a lot of sense. So in this case, we could have instead
of the ion item option. Well, let's try it.
We could have done I think that's a valid one. And then where does
the click of it do? On the Offman's Bill? Does that? No. I need a slot. All right. I'm never
wanted to shy away from doing live coding and
experimentation on the fly. That's the death for
demo God, right? Right. Now the question is, where's
my app? Here's my app. Look at that. It's
not quite right. Kinds I still had an extra one. Okay. So I'm guessing we could have
done the same thing here. Roller equals danger. No. So that would be put
that one on the option. There you go. How's that? Honestly, I think I
like that better. So I'm going to get
rid of this one. I just have one
option with the icon. And it renders. Okay. Not bad. Good call. It honestly never occurred
to me to put an icon there. I've never seen it done.
It's always a text button. All right. Is everyone caught up here? Yeah. Let me get the
code real quick. Oh, sure. Or do you
want the icon code? Oh, the icon code. Yeah. Icon code I have here.
Can you read that? Yeah. Yeah. Okay. All right. Let me know
when you've got it. And you can probably
guess what's coming next. The next thing we need
to do is just flesh out that missing function. All right, got it. And
then we'll do that. Okay. No, at least for now. Okay. The next
thing I want to do. Keep that out of the way again. This down here at the bottom
is a floating action button. It's a fab, and I believe it's mostly used
in material design. I don't think I've
seen it much in IOSAsthh the Google applications use it Gmail and Google Docs. Okay. So in order to use this, and I've got here is it's just a quick pop up menu for almost for
debugging purposes. So this is an add
student button, and this is a reset the application to
its original state, and I believe this one
was going to be delete all and then see the database. In order to do that. Just a couple of things
to know about a fab. When it's open, it's activated. You can set the edge
attribute to true or false. If it's true, see if
I get this right, the fab will display
on the edge of the header if vertical is. So horizontal and vertical to determine where the fab is
positioned on the screen. Okay. I've only ever
seen him in the corner, but you can put them
in the middle as well. I believe when edge is true, it will actually overlap
the header a little bit. And if it's false, it'll sit underneath the
header in the content. And I have one other note here. If vertical is set to bottom, it should be used
with the slot fixed. That is a note that
I have to myself, and I honestly don't
remember what that means. Okay. So. This is the markup to get that
fab menu functional. So we're going to create a
look at the container at the bottom right horizontal end, so it's the bottom right. And here I do use slot fixed. And It will consist
of a fab button. That's where you see when when
the menu is not expanded. It'll just be an icon
with a vertical ellipsis. When it is expanded, we'll have the on fab list. And it will expand to the left to to the
start of the page. And it will have some buttons. And remember how
I was saying that the ionic is really consistent about how
its names things. This appears to be an exception because the list
contains the buttons. It's not an on fab
buttons collection. It's an on fab list collection. Let's get that done real quick. See if I can do this. That's
a lot of text on the screen. Let me do in pieces. This will be the left element
inside the on content. So on fab. I have no idea how it knows
that I wanted to do that. All right, I think
you get a copil It's getting a
little scary. Okay. You guys using copilot and can you give me
the link for that? Yeah. We were talking
about that last time. I have the extension load here. No, never mind, sorry. I was thinking you're
using the snippets. Yeah. I do have some snippets. All right. I'm just
going to type. I'm I can't see it now. I do have some that's the ionic. I do have some on snippets. It's this one on just
called on snippets. I want to get back here. I could probably just
turn off the co pilot. All right. So in here,
we on fab button. The vertical ellipses. And then after the button. Okay. Oh, pretty good. I'm going to have just
a few more. Okay. The icon is an egg, but to me, it looked close enough
to a seed that I decided to use that
to seed the database. But for now, we're not
going to even get to add any functionality to this. If it's working, we
so working menu. Is that what everyone has? Okay. If you want you can
play around with the one on faul
side equal start. If you prefer it to grow up, then we should be able to
change it to side equal top. Then grow up. Okay. That's neat. It's a cool little feature. I use it a lot for debugging. I'll create a little debugging
fab that's only enabled when production mode is false or develop mode is true or
whichever one angular uses. I'll put in things
like database, clear the database,
clear the logs, show me device information,
things like that. Or if I'm writing a game, I'll have one that'll
play the entire game to the very last move so that I could test the
end of game scenario. Okay. Okay. You can mess with these
programmatically as well. They all have an API, but I try to do as much
in markup as I can. Everyone good ready to move on. Does everyone have a fab? Yeah. Yeah. All right. So now it's time to put some functionality
behind these UIs. So remember, I mentioned
that there were some imperative controllers
that we're going to need to. So let's do that now. Is everyone familiar
with the action sheet? That's the little menu that
pops up from the bottom? I think both IOS and Android
have a version of this. And as you would expect, Monic is going to
give you the one that looks negative for your device. You do build these
programmatically though. You don't build them in HTML. You build them in typescript. Okay. But we have this function
sitting there empty. We're going to need to mark
it as a sync because all of the ionic controllers
they're all asynchronous, so we're going to want to await the functions that we call. So the first thing I want to do We are going to
create some buttons. Normally, I would do this all
in one big giant function, but that's really
hard to present. So what I'm going to do is I'm going to create the buttons first and then I'll combine them all and display
them. Does that make sense? So with my code here. No. There we go. B in the
rosters typescript. Before we present
the action sheet, No, sorry. Inside
the action sheet. So we're going to
create a button. It is a type action
sheet button. Which gives this
nice intelligence. Okay. Okay. And what do we want
this function to do or what do we want the button to do when the user clicks it. So the first thing is the
text label for the menu item, the icon we want to present, which is just the icons
name from on icons. And then the function
we want to run, could be a name function, but in this case, I'm just going to use
an arrow function. And the function already
exists on the student service. So this student
service Mark present. I need a comma. And
then a semicolon. And then as I often do, I forgot to import the action sheet button
from ionic angular. Does this all clear? Okay. Is everyone got this one? Yeah. So is it really the back ticks like that
or is it single quotes? It It can be either. Okay. I think in one place, I was actually I
remember why I did this. If you type in single
quotes in PowerPoint, it automatically turns them to Curly which means you
can't copy and paste. So I started using
backticks slides. C. Okay. Good question. Okay. So Mark absent is going to
be almost exactly the same. So Lazy me. I'm going
to highlight it. And then shift
options down arrow. Make a copy of the block. Some of the gets in the way. Okay. Mark absent button. Mark absent. And
that is the outline. And this one, I'm going to call the student service
to Mark Absent. Let me know when I can move on. And on mine, it's everything when I put those in there,
everything was red. So I must have them
in the wrong spot. Do you want to share
your screen real quick? I I can't because it's not I'm on my tablet
on this. Okay. Make sure that the constants are inside that present an
action sheet function. That would be the reason
I did the same thing. When I was I just started
typing on them outside. And then I remembered
you can't have a constant on your class. Okay. Okay. That did it. I did it. Okay. So we just have a couple more
buttons to create, but they're all going to
be created very similarly. Again, I'm just going
to make a new block. And this is delete button
text labels delete. Use the trach icon. And this one, notice I'm
adding another property to it. I'm adding a role, and
that role is destructive. Okay. Destructive only
makes a difference on IOS. Android, it won't make
a difference at all. But on IOS, it'll show that
particular menu item in red. And then for the handler, I'm going to call this
confirmed delete student. Everyone have that? 1 second. Sure. Michael, do we have two buttons on the
confirmed Delete student? Do we have two buttons on
Confirmed Delete student? Well, can you just show the grader code
there for a second. The mine? Yeah. That's fine. Okay. So all of these are present actions. Okay. That's my problem.
Correct. Easily fix. Right. And confirm, we're
going to end up putting up, you know, a confirmation
dialogue and say, Are you sure you want
to delete this person? That's why I'm never calling Delete on the
student service yet. Got you. Makes sense. Okay. Let me put that
back up here for now. Okay. And this is I
believe our last button, and that's the cancel button. So the action sheet shows up. You don't want to do anything. You just want to cancel it.
That's a cancel button. Notice this one has no handler. So because it doesn't need one. So I'm just going to take. Same thing, duplicate it,
get rid of the handler. Call it cancel button, Texas cancel cons clothes
and the role is cancel. So there are some
built in roles to the action sheet button
cancel as one of them, and that just means do nothing. And as you saw, there's
also destructive. Okay. So now we should have four buttons that
don't do anything, right? They don't exist
yet. They're not actually being
referenced by anything. So the next thing is to create the action sheet
from those buttons. Let me move this down.
Here out of your way. So now we want to create
the action sheet. In order to do that.
Sorry, go ahead the same. Sorry, that's in the same
present action sheet. We're still in the
present action sheet. Function. But that first line is not going to
work because Mike never remembers to inject
things into his constructor. So before we do that, come on top of your
constructor and add an action sheet controller
of pipe action controller. Why is it not liking that? Because I haven't imported it. So I'm going to import
action sheet controller from ionic angular. Once you've done that, now
we can come back down into present action sheet and
type the rest of this. So we're going to create
an action sheet and we're going to await this
action sheet controller. I've mentioned it before.
All of these functions are asynchronous and
return promises. To create the action sheet, we give it a single
options object. This is where we tell it
what we want inside of it. We want a header here the back
ticks actually are useful. We want the student first
name and last name. And then we're going to create.
That's pretty good too. And we're to create
the button by creating an array of those constant
buttons we've already created. That makes sense? Do we have any type script
or angular guru here? I always asked this question, and I've never gotten a
consistent answer. Okay. Does it make sense to await the last statement of
an asynchronous function? Okay. If you look now at the present
an action sheet button, Typescript thinks it
returns a promise void because we marked at a sync and we're not
returning anything. But I could also present, which returns a promise. And then Typescript thinks
it returns a promise void. What is the difference
between returning the promise given to us by action present or
just awaiting it? There is a difference
and it's very subtle. And I honestly don't
remember what it is. It has something
to do, I believe, with the call stack
and with errors. I think it's if you don't
return the action see precent the result of the
promise is undefined. But if you return the
action precent then you're returning the value of the
promise present is returning. Which is also promise void. Yeah. So the difference
as I see it, we decide to return undefined. So this method pretty much becomes a fire and
forget, correct? I guess so. Do you see any value in
returning the promise? I don't even know
why they return promise because if
they return is void, and maybe you want to see
if it fails, I don't know. Honestly, in all of the ionic
apps that I've written, I've never found a reason to do this. You
can even do this. You don't even have to await it. And I believe that
still it still thinks. It's promise void. I have seen other people do
things like this though. They'll do something
after the present. But if you're going to
do that, you've already gone with the async
await pattern, you could just do it this way. Something like that. Fill that. Okay. Okay. Okay. So if you have this now, then when it renders, we should get an action sheet. So what are we going
to do to Casey McBry? We're going to mark present,
mark absent, et cetera. We're going to delete,
delete won't do anything, and we could cancel. You can also dismiss
an action sheet just by clicking
anywhere off of it. And the escape key
on your keyboard. Yep. Does everyone have a
functioning action sheet? Yes. Yes. All right. So we're going to do a lot of the
similar thing again. By implementing the
alert to delete. To do that, we're going to
need the alert controller. The API is almost identical to the action
sheet controller. So again, what I want to
do for simplicity sake or screen real estate sake is
create a couple of buttons, and this has got to be a sync. This delete button. Delete picks Handler. Yeah, sure. Delete student. It. Okay. So typo on the slide. I believe Delete student is looking for the ID
of the student. So we just pass the student ID instead
of the entire student. And then the cancel
button. Okay. Okay. And just like before the role of cancel automatically does
the way you'd expect it to. It automatically
dismisses the alert. I'm only missing here. Have we made a delete student method? Should be a delete
student method on the on the student service. Yeah, I see one. And then just like before. What was the role?
Sorry, was it cancel? Role cancel. Yeah. Okay. And so no handler needed. You can still add Handler to all of these things
with role cancel. And I can imagine you
might want to log. You know, hey, they
just deleted a student, that sort of thing. Just like before, on alert controller. Everyone have their two buttons? And the alert controller? No. So, I guess I'm where you're at. My alert controller is
grade out and never used. Right. Because we
haven't used it yet. Okay. So to do that
now. Okay. I'm good. And again, it's very similar to the action
sheet controller. In this case, we're
also going to have a sub header and a message. We've got the two buttons. Now we need to just like the other controller, it takes it has a create function that
takes an options object. Okay. And this is inside
the confirmed delete? We are still inside the
confirmed delete, yes. Okay. Okay. So what I want to do
here is show hey, do you want to
delete the student, show the students first and last name so that the user
knows what they're deleting. You know, nothing worse than clicking on the wrong person. And then message. It really can be done. But another time. And then we add the two
buttons. And then finally, if you take everything
correctly. Okay. A couple of things. One,
is this should work. And this should work. And the delete button
simply calls the service. If I delete seride is. I can get rid of Greg.
Get rid of Neil so on. Because they're
in local storage, be even if I refresh
a bunch of time. All right. I think we go. Are you all leading students
with abandoned? No. I No. I'm not getting the the alert. Okay. So let's fan
this a little bit. Your confirmed
delete should look like this. Confirmed student. Delete button, delete
handler, delete student, yes. Cancel button, cancel
close, never mind clothes. And then constant alert. Oh, okay. There's my problem. And that Okay. Yes. Okay, works. I was missing the line 70. Okay. All right. So now. Give me a second here. Okay. All right. We're going to
make a bit of a change. And it would help
you saw the slides. Okay. I want to add a delete student function
to the component. And I'll show you why. Let's go into the code
and add another function. Remember I had that. This
is what I want to see. Which means here in
the confirmed Delete, we'll call this Delete
student instead. This point, nothing
at all should change. Calling I changed
the handler for the delete button from calling the student service to
calling this delete student. Okay. It's a little bit
more consistent API, you know, we passed the student
around on the component. And then this hides
the fact that the student service just
wants to do it by ID. So passing the full
student To this one. Well, in and on the
call. Okay. Got. Okay. So what I want to do here is use the last of the ionic controllers
that we'll use here, and that is the
toast controller. So a lot of times
you want to give the user some message
that something happened. But it's not critical enough to stop the user in its tracks. And if the user
misses the message, maybe not that big
a deal, right? So that's the perfect
use case for a toast. Okay. So and you can see the
picture up here of the toast. So what I want to do now is implement the rest of the
delete student function. Okay. So you'll see the API for
the toast controller is almost exactly the same
as the alert controller. But in this case, I
don't have any buttons, so it's a much simpler function. Let me move this
out of your way. Come into my delete student
function and get that set up. Delete student returns a
promise so we can await it. Then we're going
to create a toast. And you probably already
see the error that I have? And that's that I don't have
a toast controller yet. So back up to the constructor, post controller, and then
import it from ionic angular. Then I can come down
here and finish. My toast has a message. And one good. It's been deleted. Okay. And now, so the message is pretty straightforward. What do
you want to tell the user. The rest of them are
the other options are, how long do you want to
display this information? And where do you want to
display this information? And in my case, I
want to go ahead and let's show 3 seconds. So that's in milliseconds. And I'm going to put it
at the top of the screen. There are other
things we can do. We can do color danger
to show it in red. Okay. I think the cool thing
is if you control space, you can actually get all of you get in tell sense it tells you what are the
other options here. So you can add buttons
to a toast just like we added the array
of buttons to the others. And it's literally the same API. So you could create a button
that the user could click to close it before the 3 seconds has elapsed. That's elapsed. You could give it an
icon for the left side, an icon on almost a header
next to the message. So we can do, we
can do icon tract, so then present the toast. Now, when I go to delete. The user. I get the confirmation, and then I should get
a toast at the top. And you can see the
little trash icon and has been deleted. Okay. And I can also put
it at in the middle. I must believe, Bobby. There you go. Or at the bottom. Questions. Has everyone
got that one working? Okay. Ordinarily at this point, we would be at time per break. We have approximately
half hour left. And the next thing we're
going to jump into is the student info page. So what I think I want to do, that's usually usually
do that one after lunch. So there is something that we missed on the
student info page. Does anyone know what it is? Does anyone notice it? Let's go back to the app. Actually, there are a
couple of things we missed. We can flesh out in
the next 20 minutes. There's no code behind any
of these except for new. None of these do
anything. And nothing happens if we mark As present. So I'm going to ask
for a group consensus. What would you like
to work on next? Do you want to mark them absent and present or do you want to flush these out, seating the database and deleting everybody
in the database? Well, let's go for
present and absent. All righty. Okay. So
present and absent, you bring the S code back? Okay. So the UI I
had imagined for present and absent would be another icon
somewhere on the list, or maybe replacing the icon
with a present or an absent. Do you have a
preference? Do either one of those sound better
or worse to anyone? Imagining this could end
up being a very tiny UI. I think Let's try this. Right after the
person outline icon. Let's add another on icon. I believe we still want
slot equals start. And this one is a couple of
ways we could go about this. I'm going to do it the verbose This one's going to be equals. We'll use the same icons that we use for mark
present and delete. So the present and the
off outline for absent. If we do this, we have
an icon for present, and then we have one absent, which means we need to
decide which one to show. We can do that one of two
ways. We can do this. We'll NGF this icon
will only render if student status is equal
to present. Okay. And then we can do this
one student status is equal to. Absent. So before I save this
and have it render, what is it going to show us
now? What is it going to do? It's going to show one
of the two buttons. Are you sure? Sorry.
One of the two. I What if it's? Because you remember
it's an optional field, so it can be null. So looking at that. Not super pleased with that UI. What do you think? Okay.
And I guess it works. Add a third icon. A nothing icon? What happens if you. You certainly could. So we can add so we can have another one. And you can actually do this I think if you give
it a name that doesn't exist. So I'm going to call it Mike. And you can just say
NG Not student status. So if it has no
value whatsoever, then I think what will happen. Yeah. Is that what
you had in mind? I got nothing now, rendering. Awesome. What did you change? I added an. I put a Tilda instead
of a Okay. I'm good. Okay. So that's not bad. But then I started
asking myself, what is the purpose
of the person icon? But maybe the thing to do
is to put the person icon, if not student status, and then get rid of
this one entirely. How does that? I warned you a
couple of days ago. I'm not a designer. That's why I use ionic because I can usually copy their
patterns pretty good. Can you look at the code again? Sure. It it seems like we need two new
flavors of the person icon. Well, with a plus next to it and something
with a slash through it. All right. Then let's
look at Look at on icons. And let's look at
all of our Person. There you go. Plus and Mus. We're using that
to add a person. Yeah. Okay. But we have
filled and unfilled. So you have outline and filled. Okay. Instead of the eyeball. And then you have sharp, but I don't think that
really helps us here. I mean, again, it's kind of. There was another one, though, wasn't there? What is this one? I would not have
guessed that was accessibility, but okay. So we could use that
one for I don't know, or we could use this one to. This body. And then
you could use Okay. Person and person outline? Can you change the
color of them? Yes, she could. What
are you thinking? I don't know. Solid
black outline black or gray or unknown. Well, I mean, it's it's a design issue with you that I'm not a designer,
so I don't really care. But as you can see, all
you'd have to do here is change this part. But you had a good point there, so you could have this
one they've got a gray. What color is that Okay. Let me go back into their colors on buttons have list of colors. Flight color equals light. W work. And then you could
do if they're absent Okay. Person outline. And if they're here, person and you can even do
color equal success. No, not that one. Okay. How's that? Sure. Well, that one's
almost invisible, isn't it? So I guess I would change
that to color equals. Was it medium? Medium. Yeah. Yeah, that
doesn't help me either. Is there a medium filled? We could do that. So that
would just be person. Yeah. I could live with that. So outline, they're
absent, green, they're present and
medium we don't know yet. And that was the point
of the reset button was to reset all of them to be we don't
know what they are. I can't get any of the icons to show up other than the outline. Okay. Are you capable
of sharing your screen? No. Let me just look at the code one more
time just so I can Okay. Okay. Pay attention to the the name
should be case sensitive. Make sure the NGF and
the slots are correct. Looks right. Yeah. Okay. Do your GFS have the
right quotation marks? Yeah. Everything looks the
same, but for some reason, it's just not not doing it. I don't know. Weird. Can you copy and
paste your icon? No, I guess you can't can
you hand to the chat? I guess you can't
do that either. Yeah. No. I Okay. Well, does does everyone
else have the icons working? Yeah. So I apologize. I didn't have the the
participants window open. Who's currently
having the problem? D. Okay. So if you want, we can stick around for
a little bit after. Well, we can keep moving on. I don't want to
hold everybody up. Well, let's go ahead and
wire up these buttons here because I believe the student service has all
of the functions for these. So if we go back
into R here it is, if we go back into
the fab buttons, then This is more live coding,
so we have to be careful. This one should be call it
reset, and that doesn't exist. And then for circle outline, I think that one
was the weeding. Let me come back to that
one and this one is click. Seed. Now if I come back
over to the component, I need to reset. I think that is right.
No. Reset attendance. And I believe that
returns a promise. But in this case, I don't need to await it someone's
going to return it. And then I need a seed. And that one is seed data, which returns a promise. So with that, I should
be able to come in here and reset my attendance, which turns them all gray. And then I can mark them
present. One at a time. And I can receive my database, which puts everyone back. Again, these functions are already
on the student service. So if you want to take a look at them and
see how they work. Just need to see the code again. Are This code or the
HTML code or both? Yeah. So that's fine. I was trying to see what the name of that
method was there, so they called it the Yeah. I think I had one more. Yeah, clear data, which
returns a promise. And that would be wired
up to this button. Which one is that? That's this one. Okay. Clear. And then I should be able
to come in here and clear the entire database and then reset them with
seating the data. What are you using to switch button I use the circle. Okay. This one here? No. Everything else still
works. Myth still works. Yeah. Okay. Anything else on the
student Roster page that you think we missed her, you'd like to see differently
or have a question about? Let me show you
something kind of cool. If I can find it. I think
it's in A Module TS. Yes. Okay. So in an ionic app. I remember I mentioned that the components take on the appearance of whatever
device they're running on. So one of the things you can do. Let me find a button. So let me go back
to the home page. So this is a is a. We've got a button. I'm going to go ahead
and duplicate this one. Okay. That's the one outside the card. And I'm going to
add a mode to it. So you can on most UI
elements in ionic, you can override the
default behavior. Enforce it to be
one or the other. Material design or IOS. Okay. And I believe I haven't
done this awhile. So again, this is the whole live coding from memory thing. If you go to module and you find the ionic
module import for root, I believe you can
pass in an object. Forcing the entire
application into MD, except for where
you overwride it. So if I go into there now, let me go back into edge. So I forced it into
material design. The first time.
Even in IOS, Okay. So I have it told I'm iPhone 12. But still looks very
Android. So it's not blue. It's got
4. Form Generation & Validation in Ionic: Okay. Did I enable live transcription before?
Did it just happen? Well, there you go. Okay. So transcription
is turned on. If you want to see it, you can I think it's
under the more menu. You can you can view it, change the size, et cetera. All. All right. Without further ado. So at this point, we should have a pretty much fully
functional roster page. And I don't know if
everyone saw it, but I left a challenge both
in e mail and on Slack to see how we might get rid
of the three on icons. Anyone have any ideas or any thoughts about
how to do that? If so just come on, Yeah. I got it to work. What did you do? So I could
share if you want. Sure. Let me make sure that
that's I'll share screen, but I think I have
to stop sharing. Okay. Let's see how
do I share screen? I don't know if you
guys can see that. So I word I put it. So I commented out
all of this stuff. No, it's right here. So line 28. Yeah. So name bound
to icon name, passing it to student, and I did color also. Perfect. Color is based
on wait what did you do? I just passed so I'm just
passing in the student record. Color equals student in
parens. What am I missing? What did you know what I
was messing with this. Sorry. Sorry. Yeah. I was like, I've seen
that syntax before. No. And then the functions are just two H statements
here starting there. Okay. Did you notice the flaw in doing this
because you're right. This is an easy way to do it and a lot of people
do it this way. But there's a flaw in doing
it this way and angular. I want to know if you
did you notice it? I don't think so. Okay. I was writing stuff to the
console and I don't know. It's a little hard to follow. Okay. So tell me. So put a console log
statement inside of each function with the
name of the function. And if I'm wrong, I'll be
very happy to be wrong. Okay. Perfect. And then
another one for color. Does anyone know what's
going to happen? Okay. So open up
your death tools. There you go. That's
what's going to happen. Yeah. So these are getting
called all the time. Yeah. Every time that angular has to check to
see if anything's changed, so for data binding, it's got to call those functions
because it has no way of knowing that it doesn't
have to repaint. In an application like this, not a big deal,
you'll never see it. But if you can imagine something with hundreds of data
bound components on it, it would be really nasty. Especially if these
functions did something more than just what
they do there, right? These functions don't do much. So it's not that big a deal. I was on one project
where they had a mouseover that
made a rest call. Okay. As you can imagine,
that was not pretty. So I think you're
on the right track. But the way I've
seen this done to prevent this is to
turn the icon name and icon color into an angular pipe. Okay. And with an angular pipe, it's literally the
same functions. But because the input to
the pipe hasn't changed. Angular knows it doesn't
have to recall the function. Is that something
that's easily done? Oh, yeah. Sure. Do you want me to talk you through
it or do you want me to Sure. Okay. So let's see where are we stop the
app from running. And go ahead and ask angular. If you want, we
can just do it on one, the name or the color. It doesn't matter which
were to the name. Okay. So have angular CLI generate a pipe be
PXG generate pipe. And then the name of the pipe, so maybe icon name. Capital or I couldn't matter. Maybe maybe you Okay. This is fine. So now open
up the icon name pipe. That's going to be You can command or
control click on it. In the terminal. Where it says create
source app icon name? Does control click on the
file name in the output? This guy, right? No. The one next to that one. I got you. That's the test file. Yeah.
Let's click on the other one. The non test file.
That's the app module. All right, we'll
get the middle one. There you go. Okay. Okay. So when you use a pipe, whatever you pass in for the data bound value is
going to be passed to value. So essentially what
you want here is the student's name.
The students. Attendance status, right? Yeah. You probably
wouldn't want to pass the entire student value to this because you only care
about that one value. Okay. So go ahead. So value is
going to be a string. I don't think you need the
rest of those parameters. It's not a string though
it's. You are correct. It's not a string.
It's Student status? Correct. So I mean, once you get to
refactoring this point, it probably makes sense to
make that its own type. Okay. But for now, you can make it. It should be okay
to be a string. What if I do well. Okay. You could make
it exactly the same. You could make it
absent or present. Let's just go with student
right now and I'll. You can refactor later. So yeah, now it's just a
matter of copying and pasting that same code. Okay. And this is value. Okay. Okay. So that looks pretty good. So now back in your HTML, where you're passing on
calling icon name student, simply pass student in student. Just student, and then pipe
it to the name of the pipe. Icon name. And then get
rid of that Pen Okay. And I believe there
probably is something else you can leave that
one alone if you want because you should see
it in the console. You'll see that one
of them doesn't get called over and over again. What I don't remember was if there's something
you can no longer use. Yeah, get rid of that. Okay. And I'd put a similar
console log in the pipe. That way, you can
prove to everyone that it's only being called
when it needs to be. And there is something else
you still need to do here. I'm forgetting what
it is for now, so we'll have to
discover it together. Go ahead and run it. The fact that it's on at module, that may be all you needed to do Because that was
automatically added. No, there's counsel. Okay. All right. That's what I was
afraid. It can be found. This is worse than life coating. This is trying to
tell someone else how to life coat. I know. All right. So the pipe is there. Do I need to be Do I need
to be in the roster module. Go back into A module. I think we may have
to declare it. No, sir. And I meant to do
this, you know, this afternoon to make
sure that I ready. Oh, gosh. No, I feel bad. Is it this? What was it What's
the pipe name? In the pipe dot TS file. There you go. Maybe not. No. Open up your pipe TS file again. It's the third tab
on your editor. No, it's here. Okay. Yeah. So
what should be calling it. Yeah, my brain is
having a rough time remembering this and I
use these all the time. It's one of those things
that once you write it, you just never have to
think about it again. It wants to make sure
that it's declared or imported in the
Roster page module. Oh, maybe it doesn't
go in the A module. Maybe you're right.
Maybe it goes in the roster page module. Okay. So declare it here. Under import or It doesn't have its own
module. So just declare it. If you type icon name, it
should find it for you. There you go. And you may need to take it
out of App module. Here, that's right. Okay. There you go. All right. So it's still called how many times? Once for every person, right? Yeah. And see how many more
times icon color type nine. So now if you click around,
just click anywhere. Okay. Yeah. All right. Well it's
gotten a little better, so it's not continuing to
call my buttons went away. I'm not sure what I did there. Yeah. There you go. Yeah, nine times. Interestingly enough,
the icon name pipe did get what did you do? You you reset something? I don't think so.
I think you did. I think you hit reset
on your fab button. Because all the I hal the water. Yeah, probably. All of your attendance statuses
went away? Yeah. Okay. Okay. So the whole
point of that exercise. I was not to waste 15
minutes of your time. It was to impress
upon you that calling functions from your
angular templates is never really a good idea. Was that the message you got
out of this? Yeah. Totally. I had no idea. I mean, I've
seen that behavior before. Never knew why? Never knew I never understood. I mean, I don't know
that much about angular. Is everyone here going to be dumping angular and going
to react next week? No. One of the things
that I do have is some of this course in a book and a video
format for react. I just tend to use
angular far more often, so that's where I'm comfortable. All right. So let's re share. And we'll get to the
student detail page. Andrew, are you
going to need to get those buttons back so you can
get to the student detail? I'm going to work. I'm
going to work on it. I'll figure it out. All right. Okay. Okay. So the student info page, this is the detail page, and this is going to be mostly form building in validation. And as you might imagine, ionic has a lot of components, a lot of functionality to make
this as easy as possible. But ironically, it's
also very complicated. So on our student info page, we're going to want to implement a back button so you can
go back to the Rosa. We're going to reuse on labels. You've seen those, but we're going to use them in
a context of a form. We're going to use an on input, and on input is essentially
the same as the HTML input. It's anything you want to
get data from the user. One of those inputs is the
new one in version six, which is the new on date time. Okay. So let's open up a student roster and
implement a backlog. So we should go right into move some of this
around for you again. Get rid of that. We're going to open
the student info page. Get the other student info page, so this is the HTML. Okay. So we already
have a header with a tool bar and
we've got a title. Sorry. Were we supposed to
make a student info page? You should already have
a student info page. B from day one. We made all those pages and
the routing to them. Okay. I don't think I have one. You don't. Then we can
if you want to re share, we can we can go back and get that done
for you real quick. Is that a ionic? Ionic generate
page student info. And if you do the student info
this way in your command? Yeah. Okay. It'll case it and do the file names
correctly. Okay. I have that. Okay. So you have the
student info page? Yeah. Okay. So your
student info page should have a title bar or header though with a tool
bar that looks like this? Yeah. So I want to change
it just a little bit. So that it shows the student
first name and last name. And we'll do that with angular regular string data binding. Student first mean a
space between there. It's complaining because I
don't have a student yet. So to get a back button in there, we already
have the tool bar, and now we need a
container for our button, which is going to
be an on buttons, and then a specific
on back button. And what we're going to have
in here is that default HRF. And what that says is in the event we come
directly to the roster page, and there's nothing
in the history. And they hit the
back button anyway. We need to give them
someplace to go. So even if there's nowhere
for the back button to go, we're defining that to
be the roster page. You don't tend to
see that problem too much in a mobile app because you can control as a developer how the user
gets from place to place. But in a web browser, they could just put in
whatever URL they want and go straight there.
That makes sense? And then we're also going
to want a menu button. Although we could argue that a menu button doesn't make
sense in the detail page. It's going to be a decision
left up to you, really. So let me get my sir
running again. Okay. It is compiling. Did anybody have any questions
on this particular code? The syntax? Everything but the back button should be
familiar at this point. Okay. So let me come
back over here. And here is mine. So if I go Let me
open You know what? I'm not going to do it that way. We're going to use edges. Okay. So my roster, this might actually error out because I don't have a student first
name or student last name. So if you're following along, this is what you
should be seeing also, you don't have a student yet. Okay. Which should bring
up the question, how do we get a
student on the page? If you look at the URL, well, I guess you can't look
at the RL because it failed. The URL for a student info. If you recall the roving was the student info slash
the ID of the student, right now, that's not
working at all because of the syntax error or
the binding error. So I can fix that quickly by coming in here
and just saying, Okay. I can just give it an empty
student on my component and then at least it
shouldn't fail, right? But the title,
there's nothing here. So by the same token, if I came in here and said. First name John, last
name Do Let it rebuild. And now we see John Doe. And we still have our menu
button and our backbon. But that doesn't help us get
the student onto the page. Yeah. Mine's not going to
the student page at all. What is your doing?
Just nothing. Okay. Do you want to
share and diagnose? I mean, to me, this is
where the real learning happens when we actually sit
down and solve the problems? Yeah. Let me join
the thing again. Okay. Zoom again. Okay. I'll kill the sharing here. I definitely want to make
sure we get this part right because creating the form
actually isn't that hard. So I think we have extra time
on the schedule tonight. The first piece of the
form will be annoying. The rest of it straightforward. A lot of duplication of HTML. Okay. What are we
looking at? So I think it's this
line here, right? It calls student info? Yes. So you've got your router link and
you're passing the array, student info, and student ID. And what happens when
you click that link? Yeah. I think I know what
the problem is, but I want to double
check it first. So here I just Okay. You've got errors
in your console. Click the number five up
there with the error icon. Okay. The same problem
I had before, right? Because I first
name and last name. Okay. So it was on mine it didn't even
render to the page. Okay. Okay. I'm sorry. Yeah, I didn't for me either. So if you want to
fix it for now, just to make sure that
you're getting there, go ahead and just add
the dummy student object in your student info TS file. Yeah, that should work. Go ahead and add a first name
and last name to it. It should be a Colon. First name and last
name should have colon instead of an equal sign. Because you're creating a
type script object literal. Yeah, there you go. Yeah. That's the Java in me. I can't tell you how many
times I've I've done that. Thank you. Okay. So it so render. Still not rendering? No. Unexpected token
student at column 19. Open your HTML file. Looks like you've
got a typo there. How I see what the problem is. The student in page. What did I do? Student info page dot HTML
is the one you want to open. And you can even see VS code is telling you you've
got two errors in it. See the fact on the left. The file is listed in red. Okay. So click the red or
orange file on the left. Yeah. You have two errors. So what you've got here
is you just need to put the Curly braces around
each one independently. So it's student first
name close brace. Space pen you go. Now
it should be fine. Okay. There you go. I guess. I'll do that one just a
little bit too quickly. No. I did. No, I did. Okay. Got you. All right. I'll stop sharing. Already.
No, I will resume sharing. Okay. So we need to get a
student onto a page. And Okay. I think I touched on
this the other day. I am a huge fan of our X JS, and I use X JS maybe
more than is healthy, but I find that once you become really comfortable with it, you write better code. So this code here. Well, first, let me ask, does anyone already
comfortable with our XJS or do we know if
you know what our HKS is? I've heard of it.
Okay. Then this might take a bit of it certainly takes a
little getting used to. So what we're doing here
and I'll try to go slow is I've got an observable on my student info page that
I call student dollar sign. And What's happening is that I have the
route of the page, which contains a parameter map. That's the par map. And Angular makes that
available as an observable, so that you can write code
that when the route changes. So if the student info
page is student Info one, and it's the first time you've
ever been to that page. You component renders, the
constructor is called, the G on and it runs, and all of that stuff happens in the angular page life cycle,
the way it's supposed to. If the route then changes, but the page doesn't have to. So from student info one
to student Info two. Angular knows that it doesn't have to rebuild the
entire page from scratch because only a part of the parameter
map has changed. So you can pay attention. You can subscribe
to these changes. The component won't render,
the page won't render. But you can respond to it by paying attention by subscribing to
the parameter map. So what I'm doing here is I'm setting up a new observable
that's based on the changes to the p hyping those changes to another RX JS function
called switch Map. Switch Map says, This observable just
fired the new value. Take that value and
switch it to another observable that we're going to get by calling this function. So we're going to
take the parameter, the ID parameter
of params get ID. And we're going to
pass that value to the student
service get student. So we're going to ask
student service to give us Student one student
two, student three. We're going to take that value, and we're going to run an
R XJS operator called TAP, which means we're just
going to peek at the value. We're not going to do
anything special with it. We're just going to
peek at it. So student is going to give
us a student back, or it's going to give us
nothing if we can't find one. So if there's no
student with that ID, we're going to tell
the, the angular router to go back to the Roster page. Is that clear so far?
It's cool if it's not. In fact, there's a secondary
way we can implement this, and it might be
easier to understand. But I wanted to go through
the hard way first. Okay. The student essentially becomes an observable
of students. When the parameter,
when the route changes, the student observable
gets the new student. That's the important thing to remember out of these lines. The student VM observable is building upon the
student observable and simply pipes
that value through a mapper that clones that student to give us
an exact deep copy of it. And Clone student just
does a string of JS part. It's a Forman's clone that
one you may have seen before. All of that to say, when we get a student object
from the student service, we get a copy of it
whenever the route changes. Where is this piece
of code going? That's what I'm going
to show you next. Okay. Okay. And I'm going to try to
do this kind of live. Last time I did this workshop, Mike Cartington
from Ionic stopped by just as I was
going over this code. And one of the things he told me was with an Ionic app, you
don't have to do this. So what we're going to do
this time. So let's see. The student info page.
I still want a student. But this time, I'm going
to predefine it as a Let me think about
this one for a second. Because I want to
do this one the way Mike told me to.
Well, let me ask you. You want me to do it
this way and then simplify it or do you want to
do it the simple way first? Let's go both ways
to see what changes. Okay. Fair enough. So I want the students and Okay. Okay. So let's
leave it there for a second because I don't
have the router yet. Remember what I said the
other day about not doing my imports or not showing
my imports in the slides. So we need the we
need the route, which is a trying to do
this from memory here. It's the Not that either. It's the right. Did you ever have
one of those days where you can't
remember your name? Is it not the angular router? No. No, no, no. We
need that too though. So that's the router.
We need that. And that's how we
route navigate. It's the crying out
loud. Give me a second. One of those things that
I can't remember my name. Activated t. So remember that. Activated route has information about the route used
to render your page. Okay. So we've got that and param map is
on the activated route. As you can see, it is
a observable of type. Every time that changes, we're
going to pipe its value. This Student service, which means we need to
get the student service. Anything you're wondering does Mike really code like this? Yes, he does. Student service student
service students. Okay. Okay. If not students. I'm also close, but
we'll go back to Roster. And of course, now we
got to figure out all of the all of the lovely ps that
were that are messed up. To like that. That should it is not happy with me. So Router or Map. Oh. We need to more real estate. This
piped switch map. Get service. That's
not a problem. Okay. All right. So there is no students. I think what's happening here we've got some
imports missing. Import switch maps
spell import perfo. There you go. S Okay. There we go. So switch map and
Taper from X JS operators. Okay. So as soon as the ID
changes the route changes, we regret the ID, we
calls to get student. If we don't get a
student, we navigate back to the roster. That is correct. Can you leave that just
as it is for 1 second. The slide or code. They're the same. Which
one can you read better? The thing in the red. Okay. Get. I switch man. Okay. Switch map essentially takes the value from an observable and
creates a brand new observable and switches
to that new observable. Ultimately, if we end up with a student is an
observable student. And whenever you're working
with RXJS like this, fill them up slowly
and compose them. Don't try to make everything
into a single observable. Even this could
might be too much. But now, I'm going to create a student view
model to move this up. MP also comes from
our JS operators, and Clone student
does not exist yet. See if co pilot knows
what to do here? Not quite. Now it does. And then wept students. Okay. Okay. Okay. This was enough to
get the student from the route on the page
into the component. So on our template, we will work only with this one. Mike, sorry, is all this code, what is this sitting in? Is it in on a it? Is it in the constructor? It's not in the constructor. It's it's it's just
part of the component. These are actually components. Mine's pretty messed up.
I'm not sure what's up. Okay. You want me to put this in the slack channel so you
can copy and paste it. It's useful, but it's not necessary to understand
the ionic portion. No. I just it's I got red squigglies all
over the place. Yeah. I did too. Mostly because if you don't have
all of this stuff. Yeah. This ahead, I'll I'll connect
with you afterwards. Okay. Yeah. I'm getting squiggly
on my constructor. It says Member constructor
shod be declared before all public instance
methods definitions. Correct. Yeah, I got
this you've got that. Yeah. And that's because I
didn't put student below it. That should make it happy. Depending on what you're
using for lending, the way that angular
apps are supposed to be architected here is
that you have your, your instance
variables, your fields just at the top of the class, then your constructor, then
your lifecycle events, and then your functions. Okay. All right. This is how we get the
student onto the page. Okay. Essentially, the
entire student info page, all of the HTML is wrapped
with an G container tag using an NG directive so that it only renders if
there is a student. I'm going to say that
again. We're going to wrap the entire HTML of the
page with an container. And the G container will only render if we have
a valid student. This prevents essentially undefined null reference errors. Okay. A couple of things if you should
already know about NGF, so it won't render
unless the NGF is true. But what's more is
NG container is a special angular tag that doesn't render
any output whatsoever. It doesn't affect the markup. So essentially, this is
saying that everything inside the G container will not exist if we don't
have a valid student. The rest of that line
is an angular pipe, and we're calling the a pipe. So the Async pipe is
going to take care of the subscribing
and unsubscribing for us, we don't have
to deal with it. Anytime student VM fires
a property, a new value. Everything inside of that
energy container will be told tout repaint. The last thing we do is we tell the An pipe that
whatever value we're getting from this observable
internally to my template. I'm going to refer to it as
the invariable name student. That's why I can say first
name student dallast name. I put that in practice. If I come in here now and
collapse all of my content. I can simply do container GF Not VM dollar. As student. And then close energy container I don't know
where that came from. And it's complaining because
do I still have a student? I didn't get film. I got
rid of student, didn't I? Why is it complaining?
Because I I'm not closing. Thank you. Format. Okay. Okay. Now, we go back into edge. I'm still getting
my my data mining. The data mining is working. Okay. So I want to make sure that everybody
gets at least to this point. And then I'll show you the
simpler way that Mike gave us. It's not a whole lot simpler. A simpler. Do you
see the power here? I'm not I'm not subscribing
to observables. I'm not waiting for
promises to resolve. I'm not I'm not making an HTTP call
directly from my component. I'm not dealing with
error handling. All of that can be done
inside of my service, and the component
can be written in such a way that it only renders
when it has valid data. So you can really focus on what does the
component need to do. Does that make sense? It should be, this is all the code that you
need on the component. Does everyone have those? It's working on
my side. Awesome. Anyone else. Anyone have it
not working that wants to. I'm there. Okay. Okay. Are you all okay going over
a little long tonight? I'm fine with it if you are. Depends on how long
we get this right. Okay. And the workshop feedback, I fly expect you guys to go. Okay. Don't spend
an hour on our J. I'm going to take a quick
nature break already. All right. Who are
we still waiting on? So I must be missing the
imports for switch Map, tap and map. Let's see. Yeah. PS is pretty good
about guessing, but only once you
have one of them. Okay. Ready to move on? We've got to the point
where we can do this. Okay. So from here, what we're going to want
to do is create a form. Probably done this
before in HTML. So we're going to need
a form for all of the values that are
editable on a student. We can use an on
label with an on input together, let's see. Things to know about on labels. The important ones probably not color just about everything
can be changed color. But the position of the label
relative to its input item. So it looks like this So
if you have a default, you get the label next
to the placeholder. X looks the same. I tend to use stack or floating. What do that? Okay. Okay. Loading is kind of cool because it looks like a fixed label. And then when you click in
it, it becomes a stack label. So it animates up and out
of the way so you can type. Which one you use really
is going to be up to you. Whatever your
design choices are. So on input is a huge topic. Think of everything
you can do with an HTML input tag
and supercharge. On has they've done a lot of
work at making it really, really powerful, so it might
seem a little overwhelming. It doesn't really have to be everything else with
angular and ionic. If you start with the basics and then go from there,
it's not too bad. Here are some other important
things for the input. So imagine you
have a text input. Again, you can create the color. You can give it a debounce value every N input will fire a change event as the
user is changing it. But if you make a debounce value that's
greater than zero, you won't get that
change event until so many miliseconds have elapsed after the user
has made those changes. So for example, you
put a debounce of 500 and the user's typing. You're not going to get
that change message until half a second has gone by without them making any changes. If you have seen on a mobile
device where you can enter a search string and
instead of a return or enter key on the
onscreen keyboard, it says, search or. That's the enter key hint. You can also give the mobile
device a hint on which kind of keyboard to show
based on the input mode. And finally, type is just
like an HTML input type. What kind of data
are you looking for? It's going to default to text. So you can use all of these different attributes
to kind of personalize, customize the experience
for your user. We can also validate our inputs. These are the built
in validations that are available to you. Minimum maximum
of string length, min max numeric values, reg x pattern, and whether
or not a field is required. The next one, I'm
going to show you. Don't try to take it all in. These are all of the
auto complete hints that on inputs allow. So if you've ever gone to a web page and your
browser has said, Hey, let me enter this for you. It's because of
things like this. So your first name, your address, your city state. And if your browser knows that information, it'll
enter it for you. Makes sense? Okay. Let's go. All right. I just wanted to push to
touch on that real quick. So what we need to
do in order to get the input from the user for the student is
to create a form, just a regular HTML form. With an angular form, we want to provide an event
handler for N G submit. This is what function gets called when the user
submits the form. The pound student
form equals N G form. That's another angularsm. What this is saying is that when we have
a form in angular, We're going to it will expose an G form to us that represents
the entire rendered form. And we're going to assign that form to the local template
variable student form. And when we do that, we'll be
able to inside of our HTML, we'll be able to
reference that form, ask angular if it's valid, ask it for errors, and so forth. What I want to do
here, come back here inside on content
currently empty. I want to create a form. Empty submit equals submit. We're going to submit the
student object when the form is submitted and we're
going to have a local template
variable student form, and that is the NG form
that gets built for us. On submit does not exist yet. To keep it happy, Just come in here
and create one. Yeah. Even if it
doesn't do anything. Now, at least it's happy. Next. Let's create a
single input field because all of the input fields are going to look like this. And I think I do
want an on list. We want an on item. No I don't want co pilot
doing the work for me. In the on item, I want an on label. And I'm going to set its color. First name valid. I'll
explain this in a second. I'm doing really well. Okay. I want to stop
right there for a second. I'm creating a list
for all of the inputs. So I only need one of these. Oops. Okay. And then every one of my form input elements is going to be
inside an ion item. The on label simply tells me what we're going
to put there. Setting the color
either to nothing, which will be the default
default color for the form or the ionic color called danger in the event that the first name
field is not valid. But notice it doesn't
like first name because it doesn't exist, right? So I need an input and I'm
going to set it to first name. I'm going to set it to required. Yes, I'm going to
use the two way data minding for NG model first name. I also need. That's what
I was missing there. The input also needs A template variable? I mean, I've missed
something from the slide, but that's okay. All right. Do you see what's
going to happen here? Go into the browser. Okay. So first name is Casey. So I can Notice the
first name became red. It went to that danger state, that danger color because
first name is required, but I'm no longer providing it. Does that make sense?
For the other thing I can do. Let's see. Okay. I changed the
position to floating. Yeah, I moved it up, moved
the label up. Okay. Okay. And then when you're not when you don't have the
field doesn't have focus. It animates B, which
is kind of cool. I like it. And then I had
done one more thing here. And that was inside the label. I wanted a fan. Not quite. How did I do it? Span G first
name errors is required. Okay. So what I'm doing here is I'm creating a span of text
just the words is required. In the event that the first name field has errors and that
error is required. This shows you the depth of an angular form where you
can actually go in and interrogate something
is messed up. So If you had an e mail field, you could say, you could
say that it's required. But if they type something in, you could have a different
error message that says, it's not a valid e mail address. Or it's, you know, a
phone number field. It's not a valid phone number. Or your passwords don't
match, that sort of thing. One of the cool
things I like to do. I back up a second. Is outside the form, I think this will work to an HTML pretag that's actually an interesting
thing to do too. So we can look at the entire
value of the student form. But instead, I think
what I want to do is look at the errors. So if we go back into right now, there are no errors,
so that value is null, but if I get rid of the
word Casey, and I still no. Again, this is the fun part
of live demo typing, right. Okay. So let's do.
Let's get rid of that. What we really want to do. Yep. Let's do that. Okay. I knew that. See how it changed? Now. Let's go ahead and do
the same thing for last. Miss the ion item. The label should be on say how I did the
code duplication? Or how did the update of the
first name and last name. You're going so fast that I'm still trying to catch
up for the last one, and so I missed it,
but that's okay. Because I can watch
the video afterwards. Okay. So I'll explain it. So I highlighted the blocks of code that I
wanted to duplicate. And then I held down on a Mac. It's Option Shift Down arrow. I believe on the
Windows, it's Alt Shift down arrow. Mac copies. If you don't hold
shift, it moves Okay. And then Instead of last name. What I did here is I did
command or Control D. To highlight all of the
ones that are the same. And then you can
just type over it. Let's open real
quick student page. So let's go with
parent name here. Okay. So instead of last name, I can just type parent name and that replaces it everywhere. Escape to get out of that. And then parent name. And then when it
renders? Still working. And again, everything
is required. So we get that validation
automatically. This is what I was
trying to show earlier. So you can use code like this to debug your form
in your model. I'm still trying
5. From Prototype to Launch: Building iOS and Android Apps with Ionic: All right, guys. Welcome to the fourth and final workshop. I want to start off
this evening by talking about the application storage
and how that all works. With ionic, there's a bunch
of different storage options. And because I usually
mostly work with devices. I do a lot of on device storage. So I'm not going to go into
the different types of cloud storage and Ionic has an enterprise offering that does secure cloud storage. This is literally
just how do you put simple data on the device. And that's what I'm doing here. So So what I use as
capacitor storage. You may remember from the first session we
had to go out and install at capacitor
slash storage to get the storage service door or the students service door. And as you can see here, it's a pretty simplistic API. You have get set methods, a remove method, clear
the database method and a method to get the
array of all of the keys in your database. And I say database. I use the term
loosely because it's really just a key value store attached to your application. And what I mean by that
is it's attached to your You HTTP scheme. So if you were to use NPM start, which launches NG serve with the default of
Port four tan 200. Play with the application,
got your store set up, created some new students
and edited them. And then close the app down, started it up again
with ionic serve, which I believe us Port 8,100. It would not have
the same database. So, likewise, if it
was HTTP versus HTTPS, I think they even get
different databases. It's really just tied to your applications
running incidents. On a desktop browser, it's going to use local storage, which means it's volatile. It could be destroyed
at any time. On a real device, it indexed DB or what
is the other one? SQL Light? No. You can tell
to use SQL Light. So there is an option for that, and on pretty good with that. So you can use SQL Light. But that's not the one's
Index TV and some other one. It's escaping me now,
but it doesn't matter. It'll use the right one
for the right device. And that's one of the things you get by using capacitor storage. You don't have to
worry about it. So whether you're a PWA, whether you're Android,
IOS, it doesn't care. So to set up the student service with only these five API calls, I essentially created a
bunch of public methods. The capacitor storage service
is all promise based, so you'll see that everything I do here is also promise based. Except for it looks
like the second one. All students is the
observable that our component roster
component, relies on. So the way this works is when anything
happens to a student, whether you mark them
absent, present, delete them, save retrieve it, get a new one,
what have you. What the storage service does is it takes the
information you just gave it. So here's a brand new student. Here's a fully hydrated
brand new student object. It saves it in the local
storage or storage, and then immediately tells
that all students observable, that a brand new completely
regenerated array has been created for you, and that causes the
component to update itself. As you can probably imagine. If you have a dozen students,
this is not a problem. If you have 1,000 students or 10,000 students, this
could be a problem. The way the student
service is written is you could extend it
by providing paging, sorting, all sorts of things. And then you would
only still have to pay attention to
that observable. I will leave that as an
exercise for the viewer. Also inside of the
student service, there are some private pieces
that will go over shortly, and that is the student array itself is implemented as
an RHS behavior subject. And what that does is that
maintains a local cash inside the student service that it updates whenever
it has a change. And then that's what gets sent out to the component
to the subscribers. And it does that through
the function called push A. Push A just goes and says, Hey, we have a new
behavior subject. We have a new array,
go process it. The other three functions
here are simply internal instumentations
that we will see shortly, and they're just basically
helper functions. So inside the student service, I created a generic
object called a new student of
student interface, and as you can see, it just
blanks out all of the fields, makes them empty streams. So we haven't tried it yet. But if you go to If you go
to the student info page. There is code in
the student service that will return this student, the empty student
instead of the one, the student by ID
that you asked for. Here is the behavior subject. Again, it holds an array
of students internally. And when the
application starts up, the student roster
component simply asks for all students function and that gets that behavior
subject as unobservable. As a general rule, if you're
dealing with a behavior subject with multiple
subscribers, you don't want to expose the actual subject to your subscribers
because then they could all start putting in new
values uncontrollably. So the general pattern is to return to your subscribers the behavior subject
as unobservable, and that's what
these few lines do. Feel free to stop me if
I'm going too quick, or if you need
something clarified. You've seen this, I believe, at the beginning of the
student service. We have an initialized function, and all that does is it calls
push all the first time. And so Push A says, get me all of my
students and then tell the behavior subject to emit another value with
those students in it. So again, it's just kind of
it's not a database seed, it's an application seed. So here's the beginning value. Get all students ask
the storage system, the capacitor storage system, to give me all of my keys
out of the database. The next thing I do is I filter that array for only those keys that start with the
students key constant, which I believe is just the
word student underscore. You don't have You don't have a whole lot of
say in how it's stored, how data is stored here. So you can store anything. So if I want to store students or I want to store things that are
other than students, which I might at some point, I might want to store teachers
at some point or classes. I need to to differentiate them since there is a
single key value store. So I created a student's key, which is just the word student. So I have filter all the keys from the database based
on that student key. And then the next line here, I have to await a promise all and get every
student by its key. Does that make sense? So when that promise
all resolves, I have an array of students. And the astute among
you will notice that I don't have any error handling in here, and I probably should. Okay. And here's the getting a single student and here's that special
case for new. So if you pass the
student ID of new, I will simply
resolve the promise with that empty student. Otherwise, I go into the database and look for the student by that
key hyphen its ID. So students key one, students key two, et cetera. And get student by key. You'll notice it
looks a little weird. So I have to go and call the storage function,
it's get method. And I need to pass an object. I'm not really sure why
you don't pass the key, but you have to pass
it as an object. So that's why there's the curly braces inside
the parameter. So I'm actually
passing an object with the key of key and the value of that student key parameter being passed in. It's
kind of bizarre. Capacitor storage will
only store strings. It does not do JSON parsing
or serialization for you, which is why I have
to the result. And not just the result but
the value of the result. Again, what storage DG is returning me as a
promise of an object. And in that object,
there's a value. Does that make sense?
It's kind of weird. And I think there are simpler storage libraries out there, but I wanted to stick
with the ionic stuff for this Similarly, delete student, again, you call storage remove and
you have to pass that key. For saving a student, I have a UUID library. So if you create a
brand new student, you pass me a student to
save student without an ID. Instead of just trying to
find one, two, three, four, I'm going to create a UUID
and save that assets ID. It's unique enough that I
don't think you would ever run into a collision locally. Probably not globally either, but one never knows. What's the double
question mark mean? That is that is equivalent of saying student ID
equals student ID. Unless it's null, then
assign UUID four. That's relatively
new in type script. I think it's clever. It
saves about ten keystrokes, but I don't know that
it's any clearer. Would you agree? Yeah. I mean, it is the first
time I'd seen it, so that's why I was wondering. Yeah, I think sometimes I'm Sometimes I'm too clever for myself because when I first saw that the other day, I had to remind
myself what it does. So yeah, I think that one
probably should just be student dot ID equals
student dot ID. And then question
mark question mark, which means, you know, not in. So that might be
a little easier. Let's see. So after a
delete or a student, we call push All and that sends out the array to
all the subscribers again. Do save student is the internal implementation
of save student. So it assumes you've got a
student ID or a key already, and it simply calls the storage set function
passing the key in the value. Notice again, I have to stringify the result because it's not going to do it for me. Mark present is very simple. I set the student
status to present. Same with absent and then
I call do Save student. Do save student
updates the storage, calls Push All again. Reset attendance goes through every student And then
unsets the status. And again, I'm being clever
there because you can see that map statement
has a short cut. So I'm taking the
status property out of the student
object and then passing the rest of the student object with the rest operator. That would be the equivalent
of going through and just calling unset
student status. But again, I had
to be clever, so. If you feel that you
would ding me on a pull request review
for cleverness, you're not going to get
any argument from me. Is that one clear or is
that one just bizarre. Well, I've been
doing the, you know, the java streams craziness, too. So, I mean, it it
does make sense. You know, again, you know, these words are just for
humans to understand. You know, it is all
translated into whatever the computers
going to use. Right. You know,
it's it's all about what we need to comprehend
what we're doing. Yeah. And quite frankly, what
we did last session with the getting rid of all of the observables to get the student onto the
student info page, it is so much more readable now. I think HGS has its place and that particular
place was not its place. Okay. So these are a couple
of other things we had. I think we saw that.
We have theme data, I'm sorry, seed data. And this was just at
the very beginning, if we have nothing
in the database, we can seeat it and get
a couple of I think we have ten fake students, and then clear data
is the opposite. And that one's easy. We just
call storage clear. Okay. And that is everything
for storage. Do you have any questions
before we go to the camera. Oh, I mean, that's literally all you have to do to use local storage. Wow. Yeah. And the codes all there. It's
all in the student service. Yeah. Okay. So what I'm
going to do now? Give me a second here. Well, I guess I can edit it out later. I'm to go back. This was all supplemental
material before. Okay. All right. So let's talk about
the camera. Okay. So we looked at
Pixabay once before. And what I did here is I went and found
a picture of a camera. What I wanted was a
placeholder image. So if there was no
picture of the student, I wanted something to
display in its place. So if you want to follow along, go to go to Pixabay and find a nice
picture of a camera. Doesn't even matter which
one. This one's a cool. Okay. So that actually, I haven't done it here,
so I have to do it here. Yeah, I don't have
it here. So let's go with. Which one do you like? I've got a lot of them. One, I want to go with the poloid. So I want to download the
SVG version. And then I do with. Why did
it not do with? Try that again. Okay. There it is. I'm going to name
it? Camera. And I'm going to drag it to my images. I don't
need to see it there. Okay. So it's in images. Okay. Okay. Here I say save to
camera dot PNG, but you want to save it to
whatever you download it. If you download a
PNG, then obviously, use the right extension. Okay. Now we need these
two NPM packages. We have to tell capacitor that we're going
to use the camera. And then because I think all of us right
now are in a browser, we need the ionic PWA elements to make it work in a browser. So I'm going to do that. Okay. Okay. And I install. Both of those. All
right. And that is done. Is anyone anyone following along and you need to wait for
the for the NPM to finish? Yeah. Sorry. I was trying
to get the image still, so let me do that real quick. Okay. Then you'll want that? All right, D. All right. Everyone's got a camera and
the NPM stall is finished. Okay. Next, you're
going to to open. Most of this should
already be there. But I remember I had
to have you somebody on day one comment some of this stuff out like
this import here. And this defined
custom elements. You either deleted it
or commented it out. I don't remember
which. So Open T. Yeah. I don't have this at all. There's a couple of things
we have to do in here. Get this out of the
way. I close this. Okay. So we need to platform, we need to bootstrap the
platform. Whatever it is there. Okay. So we've already got that in the catch. So
we need to call that Okay. That didn't work. So we're going to need to define or import custom elements and do it while
typing correctly. There we go. B elements loader. All right. Does everyone agree
that that looks the same? Oops. All right. Does everyone have this? Not yet. All righty. Oops. I can't imagine how
many times that I have ops followed by the left arrow. How many of those I'll
have to edit out? The arm rest of my
chair keeps sitting my keyboard. All right. Okay. In the student info page, we need to import these things
at the top of the file. So camera camera result type and camera source from
at capacitor camera. Let me see if I can do that. There we go. So back in
the student info page. Good. And then this is how
we take a picture. You will notice that the object or class of ionic capacitor
is also very promise based. So we're going to make
an A sync function called take picture
that will call the cameras get photo function and it takes a single
object of configuration. There's a lot of different
things you can pass here. This should get us
a JPEG image of reasonable quality that we can then assign to the
actual data image al. The images data U. Because we're assigning it at the very last line to
the student image, it will be a string. It'll be a base 64 encoded
string of the image. Attached to the student object
so that when we save it, that just get saved to
local storage as well. All automatically. Let me bring in my VS code, see if I can do this kind
of out of the way here. So this goes on the
student info component. That's pretty darn good. But I'm not going
to do it that way. Someone needs to remind
me to turn off copilot. All right. That's not bad. We don't want base 64 as a
result type. We want data URL. If we even got
intellisence there. Quality 90 is probably okay. Feel free to play with it.
Allow editing is true, which says, give
the user a chance to or play with it a little
bit before accepting it. That's also optional. And the source It is
going to be camera. I think you can also
do if you're not on a machine with a camera, you can just go
to source photos. I think that might
work for a Mac or Windows, if you
don't have a camera. I have a web cam, so I'm
going to leave it as camera. So that'll get our image. I need a cloth tag. And then Not sure why I
have two lines there. Why not just said it? Oh, I see. But I want to get the
data URL from the image. And then I want to set this. And that's a typo, it has
to be this, never mind. I'm sorry. We're passing
the student in, right. So it'll be student
image equals image URL. Is that clear? Yeah. But I get a little screty
it says image is not a property on student. I don't know why that is, but Well, the reason I'm not is because I didn't give it I didn't tell it
what student is. So, you're right. So if we tell it it's a student, I get the same problem, right? Yeah. So I'm going to
command click on student. And I'm going to add That is a instructional piece of type script. If
you think about it. Because on line 39, I hadn't told the function
that I was taking a student. So it defaults to any. So student image is fine. You got the squiggles
because you got the error because you had
told it it was a student. So what would have
happened had I left my student object,
the way I had it. And did not have an image. Can you guess? Well, either it's going to
work or it's not. It will work just fine because the type information really
only exists at compile time. Once all your type safety that you get out of
typescript is gone. Once you're transfied to Javascript and
you're running it. It's just Javascript. It's going to say,
Oh, you set a field of you gave me a string and you said to make
it student image. Cool. I'm going to
do that for you. Because it would
work in Javascript, it'll work just fine. Okay. But we like to play
nice here, so. So we're going to
do it that way. So did you update
your student with an optional string called image? Yes. All right. So now
we need to wire up something to the
take picture function. And we'll do that in the HTML. So what I want to do here to student info HTML. Let me get all this
out of your way again. So we have our student form, and we have the on list. So what I want to do here
is just add another on item with a click handler. And I'm going to pass
the student to it. In there, I sell student wrong. Here, I've got two images. The first image only appears
if student image exists, and I'm going to set it class, we'll update the
CSS in a minute. Student photo. Okay. Is student age. If we have a picture of the student on the
student object, we're going to create an image tag with that
student image as the source. And my image tag is complaining because
I don't have Altex. So we can set up alt text
equal to's do it this way. All the first time. A lquFst name. Student last. So are all
text to the student's name. If on the other hand, we do
not have a student image. Not a force equals Assets, images, M was an SVG. A equals k a picture.
How does that look? I I'm going to fire up my
NG server or NPM start. And before we take a look at it, let's go ahead and fix the CSS. We didn't talk a lot about
CSS in this in this workshop. I don't consider
myself a CSS expert, but for this, it's not
too hard to do by them. There we go. So that student photo class
that I set on the image? I'm going to give
it a max height of 25% of the vertical space. So no more than
that. And I'm going to set it's object fit to cover. So it'll crop the image, but still take up
the whole rectangle. We do that. Then we come back in and
refresh the page here. I don't see any error,
so let's go into here. There's my polid the text so
I don't see it do anything. But if I click on
it, and you can see my camera. That's cool. Using the other camera. If I want to take a picture. Well, I didn't work very well. Let's try that
again. There we go. And then I can save it.
And there's my picture. Then if I save Jonathan Bennett. Come back in.
Picture still there. How cool is that? Okay. No applause, no nothing. All right. How's
everyone else's coming? Sorry, I was on mute,
but no, that's cool. Is it working for you? Yeah. I I had the image. It it was then says
no camera found. Okay. Gives me an option
to choose an image. So let me try that and see. So now, if I say it
You can go back. W. Very cool. Yeah. That's cool. I like that. So that is capacitor, essentially in a nutshell. Capacitor is going to give
you a consistent API. Across all devices
and web pages. Now, not every
capacitor plug in, we'll work with the desktop
browser. Many will. If you go to the
official plug ins and then they also have
community plug ins, they'll tell you
what they work with. There are things like Face ID that obviously only works
with an Apple product, and I think works
with iPhones or IOS. But you can access the GPS
through through anything. I'll use the browser API. I'll use if you're
on a desk pop, it'll go deeper and
it'll use your WiFi and if you're on an iPhone,
they'll use that GPS. On Android, it'll use that GPS. But it gives you a consistent
API for you to develop to, so you don't have to
remember well, Android, I have to do this or
IOS, I have to do that. Does that make sense? So now, Now we get to do. Well, before I move
on, is there anyone who wants to get the camera working,
but isn't hasn't yet? Take that as a no. So now we come to the probably the most danger
part of the workshop. Because I have no
slides on this stuff. This one I just completely
do live on the fly. So as you can imagine,
it's quite exciting. So at this point, we have
a functioning application. And I think it's good enough to be put into the app
store or the play store. So let me make sure that I have the ionic extension running
loaded and running. No. Make sure everything's good. That's fine. Okay. Where is? There's the ionic one.
There it is. Okay. Have you all seen the
ionic extension yet? We really haven't
used it because I don't like to rely
on it necessarily. But there's got some
cool things that it can do. What does it want us to do? It wants to migrate It wants
us to add these features. These are recommendations that the ionic plug in is
going to give us. The first thing I want to do now is I want to add an IOS project, it should be a matter of
simply clicking right there. Yes, I would like
to add IOS support to my capacitor project. And it's showing
me in the terminal here commands it's running. Okay. Okay. So could not. Could not sink was missing WWW. And yes, I always
forget this myself. In order to do a
sync with capacitor, you must at least build a production version of
your application one time. So I just ran NPM run build. So what is Coco pods? What are you used
to developing on? What native desktop
application are you used to? I Mac I thought maybe you
were a dot developer. Oh, well, no, I'm
a java developer, so Then I think it's
equivalent to Maven. It's a package manager. Okay. Or at least that's one of the
things Maven can do, right? I know it can do a lot. Yeah. Okay. It's a CocoaPods, I believe it's just a
dependency manager. The cool thing is, unless
you're going to build your own capacitor plug ins, you don't really have
to care that much. But now that we've
built the app, we should be able to
sync with capacitor. Okay. And let me open up.
Package, Jason. Oh, they don't have
it here. Okay. I was expecting some script.
So NPM scripts. Okay. So it seemed
to have finished. Come back here. Let's
look at what it did. So the NPM run build built my ionic Angular app and put all of the
assets into the WWW. So this is the entire
built application. Capacitor sync copied that
entire angular ionic app into this IOS project. So this is an X code project. We technically don't have to care a whole lot about this because Ionic has done a
lot of the work for us. And I will be the
first to admit, I am not an X code guy or an objective C guy
or a swift guy. It's just not something that's ever held much appeal to me. But now that I've
built and synced, I can open this
project in Xcode. And I was afraid of that. Okay. So my O F has updated since
the last time I ran XCode, which means I have
to update EXCO, or at least part of Xcode. Now, let's see what it does. Is one of you following
along on your mac? Yeah. All right. I want to click this again. That looks better. Okay.
So there's X code. Are you an Apple developer? No. No. I am registered as
an Apple developer, but I don't pay the
subscription fee, so I can't push anything
to the App store. But I should at least be able to do This if I can find it. Okay. So I've got a
bundle identifier. Signing is automatic,
but I don't have a team, so I need to go to
my personal team. And that should fail to
register because you can't the bundle identifier
has to be globally unique. Well, mine because I use
walking as my domain. And my watch wants me to trust
my computer. Yes, you may. Come walking. Let's call it July 2022. Try again. Okay. So it's created
a signage certificate and a provisioning
profile for me. So at this point, I should be able to Pick
a simulator or if I want, actually plug in
my actual iPhone if I had a lightning cable. Somewhere around here. If we have time, I'll go
ahead and do that. Let's take Let's go with an iPhone eight one
of the smaller older ones. I should be able to click Play. It is building. I told you the Macbook
was fast, didn't I? Okay. Yeah. I didn't see
the open X code underneath my capacitor
in the ionic. You did not? Yeah.
I didn't have that. Had you done the
build on the sink? Yeah. Well, and you done the
ad IOS project? Yes. Yes. Because that's that's
why I had that coca pods. Okay. Right. Well, let me try to build it
one more time to see. All right. The simulators
is firing up now. So on iPhone eight
with IOS 1155. You can see at the very top. If you can see it, that's small, it says, running apple
on iPhone eight. There you go. With all three buttons. Now, I can tell you
this is going to fail. It's not the application is going to work, right?
I can come in here. I can mark present.
I can mark absent. I can go, I can change
Jennifer's name to Jen. Okay. And it's behaving
like an iPhone. And we're going to say
that Jen was born in March 95 on the tenth. And we're going to save Jen. So now it's Jen and still
got the same birthday. I can delete Troy. And everything we've
built over the last 3.5 sessions is completely running as if it were a
native iPhone app. A couple of things
we still have to do to make it better,
but it is working. So if I come in here to Casey, does anyone know what's
going to happen when I click the picture of the camera? There's not a camera simulator, so it's not going to it's
going to fail for that. I'll probably ask you to
choose an image or just die. Nope, it just dies. No. But I believe the reason it died is not because
there's no camera. It is right here. So this is where
it starts to get. We're not really in the
realm of ionic anymore. And if you go to the
capacitor camera plug in documentation, it'll
warn you about this. The camera won't
function unless you tell X code that you want to ask for permission to
use the camera and. You've all seen it, right? Application X wants to use
your camera and then there's a little sentence or
two underneath that that tells you what they're
going to do with the image, or how they're going
to use that data. Right. That is in here.
That is in X code. You can't do this with ionic and it's different for
Android than it is for IOS. It's the same thing. You still have to
ask for permission, but the way you
asked for permission is different with Android. So as I recall, let
me kill the app. Okay. As I recall, it's
in here somewhere. I'm in info. And what do they
tell me I'm looking for. You are missing Anna Photo
Library ad usage description. Required device capabilities. I always forget this one. So I'm going to take this. I'm going to go back
to the interwebs. Okay. And Apple says, a message
that tells user why the App is requesting this ad
this where does it go? There we go. How to
add that in x code. So we're in info,
custom IOS targets. I don't see that. Do
you see that? No. Of course, they changed the
stuff with almost every, here's custom I always started. That's way over
here on the left. Right click on any key
row and click Add row. Add. That feels. I see wrong, doesn't it? I don't think that's belongs. Okay. How about R s values? No, I like that one e. Okay, what's that on the list? Ly. That's the one I want. There we go. That's what
I want it. Not that one. So now that I have that there, I believe this is just
why we want to use it. Write the value describing why
your application needs it. Here, we can take your picture. Okay. That makes sense?
Well run it again. The simulator still running. And now I go to the roster. Click here, hopefully. I still didn't like it. This is why we use ionic
and nott's missing. Let's double check here. It is gone, isn't
it? No. Here on the bottom. Here you go. Was that supposed
to be inside of the required device
capabilities? No. They did it on the
bundle ex the bundle. They did it here somewhere. Yeah. So what was their
value that they had? Maybe that's the difference. The value of the key
will be shown as a description of the pop
up shown to the user, so write the value
describing why your application needs
access to the photo library? That looks good. Let's try. Go back to the app. Do you have to build it again? That's what I was thinking. Let's just clean
the build folder. And then build the run it again. Oh. Wow. Yeah. It's still
happy about that, is it? It is possible. Oh, it's here, too, isn't it? It's so it's in Info P list. It's even right there. I'm pretty sure it's not in the pod. I guess it's just here. Always fun dealing with IOS. So let's go to capacitor.
Let's see what they say. Mera plug in. It requires
more than just that one. So we did this one, right? No. We did this wall. All right. So we have that one. These are all the
same, were they? Okay. Okay. I want to make them a little different so I know
which one's which. Okay. Let's try that. Asador says we need three,
so we have three now. That didn't feel like
it built, did it? You said it did? No.
Let's give it a try. There you go. But that was what we needed.
We needed all three. All right. So let's try looking to see if I have
a I do have a cable here. Which means I have to unplug. That's the problem with
the Macbook error. It's only got two ports. So I'm going to unplug my power since the thing will run for six or 7
hours on a battery. I'm in my iPhone 11. Okay. Now that we
have that functional. See I have my iPhone 11 here to unlock to
use the accessories. Now Michael's iPhone. I am still sharing the screen, right? Yeah. Yeah. Okay. Okay. So I've
selected my iPhone. And now I will
start it up again. And I think Bill succeeded. Michael, that's fine. I'm going to stop sharing for a moment. I want
to try something. No. It does not there it
is. What do you see now? You see the iPhone, right? Yep. EXCO is still waiting. All right. So while XCoda still waiting? Let's go back here. And I want to do splash
screens and icon. Okay. I've only ever done this
from the command line with someone else's library. What happens if we click that? It's not going
to work, right? We need to select the file, a 10204 square PNG file that does not contain
transparency. What I'm going to do here then
is I'm going to go back to Pixabay I'm going to look
for a icon of people. That one's not pet. That one probably has transparency
though, right? Yeah. All right. What
else can we find? I think in the past, I used to clipboard image. That also has transparency, but I might be able to fix that. So 10204 by 10204. That's a weird one. Let's see. What else would make a good one? Sorry, that one. All right. 12 80 by 12 80 P
and G. I'll download that. Open it in preview. Actually downward. Let's go with no, no, no. Go with that'll work. I'll show you what
I'm going to do. So I scale it down a little bit. Now I'm going to cut it. Go back to image size. Not proportional. Make it exactly 10204 by 10204. And make a white box. It uses a background, and then paste my
clipboard inside it. Little unorthodox,
but it does the job. Now, back in my downloads
for, I have clipboard. So now if I come back into OVS code, I'm going
to select the file. Got to my downloads clipboard. I need a splash screen
also or doing something. All right. So it found
that. So splash screen. It wants a 27 32 by 27 32 PNG. So what I'm going to
do there back out to the finder and I'm going to make a copy
of that same file. Call it splash. And I'm going to do the
same thing I did before. Open it. Cut. I no, sorry. Yeah. C. 27 32, right? Yeah. Okay. Drop the square. Zoom out a lot.
Two part of o out. Okay. And then paste
the image right into the dead center as dead
center as I can make it. Okay. I'm not convinced that's a dead center. Does
that look good? Yeah. Quit. Splash collect file. There we go. Now, what it's going to
do for me is it's going to create splash screens and icons for IOS at all of the different resolutions
that Apple wants. And when it's finished,
re open an code. Wow. Still waiting, huh?
Hoping you'll be dub. Okay. So now. We should
have a launch screen. And somewhere in here should
be the icon. There it is. See? Let somebody
else do the work. All right. Let's kill that let's try
running on my iPhone again. Installing, that's better. All right. Switch back to
sharing in the iPhone. Oh, maybe that was the
problem because did you see X code lost connection
as soon as Zoom got it. But now, what you're seeing
is this is my iPhone running. The same thing you're
seeing on your screen. I can't click on the screen. I have to do it manually here. Yep. And now it's the
back facing camera, or I can flip it
around to see me. How cool is that? Oh,
I turned it sideways. Good Troy. Pretty amazing, huh? Yeah,
Troy, is what you call me? Okay. Actually, let me go back to the All right. So I'm going to go
way out of that. And somewhere in here.
Not going to be there. Should be in
recently added apps. Yeah, there it is see it. Right here. Yeah. So I forced it to quit. So we should get the splash
screen now and we don't. Can't explain that
one. That usually works perfectly. But
we got the icon. And we obviously have
camera functionality now. And that's a really
bad infinity there. Thoughts. Android
is very similar. You need to have Android
studio installed. But once you do, then you can come in here and add
the Android project. It'll build the assets for
Android just as easily. If we look at what capacitor
wants us to do there. We need to add a
couple of lines in the Android manifest XML file. Questions, comments?