Mobile App Development Workshop with Ionic and Angular | Michael Callaghan | Skillshare
Search

Playback Speed


1.0x


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

Mobile App Development Workshop with Ionic and Angular

teacher avatar Michael Callaghan, Lead Ionic Developer

Watch this class and thousands more

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

Watch this class and thousands more

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

Lessons in This Class

    • 1.

      CoursePromo

      1:48

    • 2.

      Introduction to Ionic: Crafting Your First App

      121:20

    • 3.

      Elevating User Experience: Advanced Ionic Components

      85:41

    • 4.

      Form Generation & Validation in Ionic

      114:58

    • 5.

      From Prototype to Launch: Building iOS and Android Apps with Ionic

      84:38

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

Community Generated

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

48

Students

1

Projects

About This Class

Transform your mobile app vision into reality with this transformative course designed for aspiring and seasoned developers alike. Whether you're brimming with innovative app ideas but lack the technical team to bring them to life across Android and iOS platforms, possess web development expertise and dream of seeing your app featured in the App Stores, or are eager to delve into mobile web development but unsure where to begin, this course is tailor-made for you.

Imagine facing a daunting challenge: a critical business operation is at risk due to hardware support discontinuation. Faced with the need for a swift and effective solution, the choice between developing separate apps for Android and iOS or finding a unified development approach becomes stark. This course emerges from real-world challenges, offering a powerful solution that doesn't require choosing between cost, efficiency, and platform coverage.

Welcome to a workshop where impossibilities are turned into achievements. Utilizing the cutting-edge capabilities of Ionic, Angular, and Capacitor, you'll discover the secrets to developing fully-functional mobile applications for both iOS and Android using a single codebase. This approach not only accelerates development time but also significantly cuts down costs.

What You Will Gain:

  • Session 1: Kickstart your journey with an introduction to Ionic Framework development. By the end of this session, you'll have crafted your first app, complete with functional pages.

  • Session 2: Enhance the main page of your app with sophisticated and user-friendly Ionic components, elevating the user experience.

  • Session 3: Master form generation and validation, a crucial skill for engaging and understanding your users.

  • Session 4: Bring your project to life by generating an iOS or Android app, ready to launch in Xcode or Android Studio.

Meet Your Instructor:

Mike Callaghan, a seasoned software developer with nearly three decades of experience and an acclaimed Ionic Developer Expert, will guide you through this journey. With extensive expertise in Ionic and Angular from their inception, Mike offers unparalleled insights into mobile app development.

Course Prerequisites:

  • A computer with web editor capabilities (Visual Studio Code recommended).

  • A Mac and an Apple Developer account for iOS app development.

  • Any computer capable of running Android Studio for Android app development.

  • Basic web development or Angular knowledge is beneficial but not mandatory.

This course encapsulates the essence of a live workshop conducted in July 2022, offering an unfiltered and immersive learning experience, complete with real-time interactions, questions, and even the occasional mishap, providing a raw, authentic insight into the world of mobile app development.

Embark on this journey to transform your mobile app development skills, make your app idea a reality, and step confidently into the world of multi-platform app development. Enroll now and be part of a learning experience that bridges gaps, defies barriers, and sets you on the path to success in the dynamic field of mobile app development.

Meet Your Teacher

Teacher Profile Image

Michael Callaghan

Lead Ionic Developer

Teacher

Hello, I'm Mike Callaghan. I am an LDS husband, father, and Software Engineer for Disney Parks, Experience, and Products Technology. I also create video courses about web development, mostly revolving around the Ionic Framework. 

I've been building software professionally since 1995, and using the Ionic Framework from before it was at version 1. Over the past few years, I have authored four popular Ionic courses for Pluralsight.

Now I am embarking on a new journey, building two new Ionic courses, one using Angular and one using React.

I invite you to join me on this journey... experiencing all the marvelous and wondrous aspects about building web and mobile applications.

See full profile

Level: Intermediate

Class Ratings

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

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

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

Transcripts

1. 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?