- Overview
- Transcript
3.7 Models
We'll spend most of the course looking at the view and controller parts of Angular's MVC (model-view-controller) architecture, but first we should understand how models work. In this lesson we'll do just that.
1.Introduction6 lessons, 42:00
1.1Introduction00:48
1.2Get Started With Angular-CLI11:09
1.3Developing With Angular-CLI13:17
1.4TypeScript vs. JavaScript06:54
1.5Angular Modules From the CLI04:31
1.6CLI Options05:21
2.Get Started With Angular7 lessons, 42:38
2.1Bootstrapping the Application04:30
2.2The Application Module04:15
2.3The Application Component08:06
2.4Component Styling03:06
2.5Global Styling05:11
2.6Creating a Component With the CLI09:34
2.7Creating a Service With the CLI07:56
3.Core Concepts7 lessons, 55:20
3.1Component Trees06:20
3.2Dependency Injection06:52
3.3Content Projection05:38
3.4Component and Directive Lifecycle Methods06:31
3.5Component-Only Lifecycle Methods05:28
3.6Decorators07:36
3.7Models16:55
4.Template Deep Dive11 lessons, 1:10:56
4.1Basic Data Binding With Interpolation05:35
4.2Property Bindings07:07
4.3Attribute Bindings03:29
4.4Event Bindings08:16
4.5Class and Style Bindings05:44
4.6The `NgClass` and `NgStyle` Directives05:04
4.7The `*ngIf` Directive04:41
4.8The `*ngFor` Directive09:29
4.9Inputs05:33
4.10Using Pipes in a Template07:31
4.11Using Pipes in a Class08:27
5.Forms10 lessons, 1:45:41
5.1Handling User Input With Template Reference Variables07:06
5.2Template-Driven Forms11:10
5.3Template-Driven Forms: Validation and Submission14:00
5.4Reactive Forms11:26
5.5Using a `FormBuilder`08:01
5.6Reactive Validation With Built-in Validators14:53
5.7Creating Custom Validators for Template-Driven Forms12:18
5.8Creating Custom Validators for Reactive Forms08:26
5.9Observing Form State Changes12:40
5.10Working With the `@HostListener` Decorator05:41
6.Routing9 lessons, 1:15:10
6.1Defining and Configuring Routes07:53
6.2Rendering Components With Router Outlets10:14
6.3Using Router Links for Navigation05:25
6.4Navigating Routes Using the Router06:24
6.5Determining the Active Route Using an Activated Route07:16
6.6Working With Route Parameters10:42
6.7Using Route Guards07:36
6.8Observing Router Events10:55
6.9Adding Child Routes08:45
7.Using the HTTP Client5 lessons, 56:24
7.1Sending an HTTP Request10:52
7.2Handling an HTTP Response11:22
7.3Setting Request Headers12:33
7.4Intercepting Requests09:04
7.5Finishing the Example Application12:33
8.Testing10 lessons, 1:23:27
8.1Service Unit Test Preparation10:45
8.2Unit Testing Services13:24
8.3Component Unit Test Preparation12:35
8.4Unit Testing Components07:27
8.5Unit Testing Component Templates06:58
8.6Unit Testing Pipes04:41
8.7Unit Testing Directives04:56
8.8Unit Testing Validators04:48
8.9Unit Testing Observables11:37
8.10Unit Testing HTTP Interceptors06:16
9.Building for Production1 lesson, 03:40
9.1Building for Production03:40
10.Conclusion1 lesson, 01:32
10.1Conclusion01:32
3.7 Models
Hi folks. In this lesson, we're going to take a quick look at models. Now, Angular doesn't have a built-in definition of the term model. There's no app model decorator, or anything like that. And just to clarify, I mean model in the sense of an MVC model. So an entity that encapsulates the data used by your application. Even though Angular 2 and above doesn't have a formal definition of a controller anymore, the components class can be seen as a controller of sorts. And Angular can still be loosely described as an MVC framework. So most applications are going to need some objects, which contain the data for the application, and maybe some behavior or logic as well. And the example application that we're building will, too. So that's what we're going to look at in this lesson. The example application that we're building is a card game. So one object that we're definitely going to need is a card, which represents a playing card. So let's add a card model first of all. We can create a new folder for our models. They're going to be very generic, rather than being part of any single component or feature. So let's call the folder _models This will then sit right up at the top of the app folder with our generic_services folder. So inside this new folder, let's create a new typescript file called card.ts. So this will be a very simple class, And inside the constructor we can specify some public properties. So cards have three simple string properties, colored suit and name, and finally a value property which will be a number. The constructor accepts these as arguments and because we use the public key word, typescript will automatically add the values past into the constructors as properties. We don't have to do this manually and type the constructor body. Another object that we're going to need is a player. So let's add a player model as well. We can add a new file cool player.ts to the _models folder. And again this will be simple class, So we specify two public properties of the class, a score and a hand property. We aren't providing any type information here, and there's actually an error because I used a colon and that should be an equals sign. So going back to what I was about to say then, we're not providing any typing information here, we are initializing the values, and that's why we don't need to provide typing information. We don't need to tell typescript that score will be a number, because we're initializing it with a numeric value. So the type for this property is implied. Typescript already knows that it's gonna be a number. And the same with the hand property, it's an array, we're initializing it with an array, so typescript will understand that this property will be of the array type. So now let's add a constructor, And the only thing that will get passed to the constructor is the name of the player and we use the public keyword again to get typescript to add this as a public property. And we do specify the type here because we're not actually going to initialize the value. That will happen when we new up instances of this player class. There's one more model that we'll need, and that will be a deck. So this will be used to create the deck of cards and provide some behavior in the form of shuffling and and dealing the cards. This will bring together the player and card objects, and is a much bigger model than the previous two models. So let's create a new file for this one. We will need to import some things for this model. So we'll need to import the card, the player, and the constant service. We'll also need a function does nothing, commonly known as a noop or noop. So this is an error function that simply returns undefined. We could probably actually put that into the constant service because it's the kind of thing that we do use all over an application. But I'm just gonna leave that as a local variable within this file for now. So now we can have the deck class itself. So the type information that we specified here is quite different than any that we've used before. So what we are staying here is that the cards property will be an array of card objects. Now let's add the constructor. So the constructor for this class accepts a single parameter called aces high which will be a Boolean. And we actually want to initialize our card array as an empty array, and we can do that where we specify the property. So inside the constructor, we'll first need to create a new instance of the constants service. Even though it's an Angular service, it's still basically a class, so we can just create an instance of it using new as we would a regular class. Next, we can build the deck of cards. We'll need 52 cards in specific groups of colors and cards. And we'll use a loop based on the suits' constant. Let's just open up the constants service. So you can see that we've got a number of things in here. We've got an array for the colors, so those will be the different colors. Cards can either be black or red. We've also got a suits array. There are typically four suits of cards, spades, hearts, diamonds, and clubs. We then have an array for the face cards, so these are special cards. They aren't just numbers, they normally have pictures on them, ace, jack, queen, and king. And then lastly we have all of the regular cards, these are known as PIP cards and they typically have values from one to ten. So these are some of the things that we're gonna be making use of as we build our deck. The first thing that we're gonna use is the array of suits. So we've used the forEach method on the suits array. And each time the callback function gets invoked, it will be passed the current suit and the suit's index. Inside this function, we first need to check whether aces are high, because this affects the value of the card. By default, aces are low in Blackjack, and so worth one points. If they are high, however, they are worth 11. So we need to splice the value 1 out from the start of the PIPS array and replace it with the value 11 instead. If aces aren't high, we just invoke out noop function. Noops are super useful for ternary statements like this. To create the individual cards within each suits, we can use the PIPS array from the constants. We need another loop for this part and we need to handle the face cards, ace, jack, queen and king as well as regular number cards. Inside the inner forEach, we can first define a variable called name. If the current value is 1 or 11, we set the name variable to faces 0 which will be ace. So we can use a similar ternary and noop expression here, just like before. So now if the value of the card is equal to 1 or 11, we give it the first item from the faces array, which will be ace, and otherwise, we just invoke our noop function. So at this point, if the value of the card is equal to ten, then it's one of the other face cards. So we can set the card name to either jack, queen, or king depending on which card it is. So we're using the faceCount variable to iterate through the faces array, to make sure that each card with a value of ten gets given the correct name. So there will be a jack, a queen, and a king. Once we've set the name to king, which will be CONSTS.FACES3, then we need to reset the faceCount variable, and that will then get reused for the next suit. So we also need to determine the color of the card, and that will be either red or black. So if the suit index is equal to either 0 or 3, the color will be black, otherwise, the color will be red. And last of all, we can create the new card. We want to push that into the cards array at the point of creation. So this should results in a deck of 52 cards being created. The deck will also need methods to shuffle and deal the cards, so let's add these quickly as well. And it looks like I'm missing a closing parenthesis to start that in there. So let's add the shuffle method first of all. So we need a temporary copy of the cards array so we can use the slice method to create a copy of that array and that won't affect the original array then So in order to shuffle the deck of cards, we use a for loop here. And then inside the for loop, we use destructuring assignment to randomly shuffle the order of the cards based on the counter variables from the for loop and a random number. So now we want to add a method that will deal cards. So we've got some underlining here, and I think we can ignore that in this case. So let's move on to add the deal method. So this method will take an array of players that the cards will be dealt to and the number of cards to deal to each player as arguments. So for each player, we pop one of the cards off of the cards array which belongs to the deck class, and we do this to make sure that two players don't get dealt the same card. We can then push that new card into the player's hand, and update the players score at the same time. So that should be the deck model in its entirety. Just in case you're interested, the shuffle method uses a Durstenfeld shuffle, which is a computer optimized version of the classic Fisher-Yates sorting algorithm. So let's just test our new models out quickly, and we can do that using the home component. So let's import the deck. And let's just add an ngOnInit. And inside the OnInit, let's initialize a new deck, and see if we can log into the console. So we'll just keep aces low for the time being. And let's check it out in the browser. And we can see that we have our deck here, and we have an array of 52 cards. So we have all of the spades, we've got the ace, and the jack, queen and king. Then we have all of the hearts, which are red, all of the diamonds which are red, and all of the clubs which are black, perfect! And if we really wanted to make sure that everything was working properly, we could also test the shuffling and the dealing. We'll need to bring in the player model for this part. What we've done so far should create two new players, one called Dealer, one called Dan. And then it should deal two cards to each of the players. So let's take a look at one of the players, and let's check things out in the browsers console. So we can see that the player has been created correctly. It looks like I've got quite a good score, it's a shame I'm not actually playing the game yet. And I've got two cards in my hand, which sounds about right. And one is a spade and one is a heart and I've got a king and a jack. So that looks like the shuffling and the dealing worked as expected. So in this lesson, we created some models that will be used by the example application. These are mostly quite simple models. Two of them have no methods and just a couple properties each. One of them, the deck model was quite a bit more complex and had a lot of initialization that happened in the constructor as well as a couple of methods. Thanks for watching.