Angular – Populate UI with data – Part 3

Angular Project Content:

Populate Cards

1. Open my-dashboard.component.css and replace all the content with the code below:

.main-container {

padding: 10px;

}

.grid-container {

display: inherit;

margin: 20px;

}

.flex-container {

display: flex;

flex-wrap: wrap;

flex-shrink: 1;

flex-basis: auto;

}

.dashboard-card {

left: 10px;

right: 10px;

margin-bottom: 2%;

flex-shrink: 1;

flex-grow: 1;

}

.more-button {

position: absolute;

top: 5px;

right: 10px;

}

.dashboard-card-content {

text-align: left;

}

.example-header-image {

background-size: cover;

}

HOW TO: install PHP 7.2 on Windows

2. Open my-dashboard.component.ts and populate cards.

2.1 Let’s create a global empty array object that we can populate later on. Add the code below before the constructor:
/** Empty Cards Array */

public cards= [];
Define empty array variable
Define empty array variable
2.2. Edit the getRandomPics() function, to make it populate the cards. Your function should look like the one below:
The first thing we do when the function gets called is to make the cards variable empty again. This ensures that we show fresh result every time the API gets called, not just add new pictures in the array.
Then, we assign the links to a local constant and have a two for loops that go through the results and push each one of them as an object in the cards array.
        for (var i = 1; i < randomPics.length; i++) {

          for (let picture of randomPics) {

            this.cards.push({

              id: i++,

              pic: picture,

              likes: 0

            });

          }

        }
getRandomPics() function
getRandomPics() function
The code above says loops through all 5 results and for each picture it pushes a new object into the cards array. This object contains an id, picture link (pic) and the number of likes, which is always set to 0 to start with.
Now that we have all the data necessary, our UI can start to render it correctly and display all five cards with pictures and names.

3. Open my-dashboard.component.html and replace all the contents with the code below:

<div class="grid-container">

<mat-grid-list cols="2" style="padding: 5%">

<mat-card class="dashboard-card" *ngFor="let card of cards">

<mat-card-header>

<!-- Static avatar image for card-->

<img mat-card-avatar class="example-header-image" src="https://material.angular.io/assets/img/examples/shiba1.jpg">

<mat-card-title>Dogy {{card.id}}</mat-card-title>

<mat-card-subtitle>Breed:

<i>{{selectedValue}}</i>

</mat-card-subtitle>

<button mat-icon-button class="more-button" [matMenuTriggerFor]="menu" aria-label="Toggle menu">

<mat-icon>more_vert</mat-icon>

</button>

<mat-menu #menu="matMenu" xPosition="before">

<button mat-menu-item>Expand</button>

<button mat-menu-item (click)="closeCard(card)">Remove</button>

</mat-menu>

</mat-card-header>

<img mat-card-image src="{{card.img_link}}" alt="Photo of a dog">

<!-- Static content of card-->

<mat-card-content class="dashboard-card-content">

<p>

The Shiba Inu is the smallest of the six original and distinct spitz breeds of dog from Japan. A small, agile dog that copes

very well with mountainous terrain, the Shiba Inu was originally bred for hunting.

</p>

</mat-card-content>

<mat-card-actions>

<button mat-button (click)="count(card)">

<b>{{card.likes}} </b>

<i class="material-icons">

favorite_border

</i>

</button>

<button mat-button>SHARE</button>

</mat-card-actions>

</mat-card>

</mat-grid-list>

</div>
If you save this file now and refresh your page in the browser, you will see five cards being displayed, containing different pictures of dogs, the title is Dogy but the number at the end is incrementing, and they all have zero likes.
Basically, the *ngFor in line 3, <mat-card class=”dashboard-card”  *ngFor=”let card of cards”>, generates a new card for each item in cards, the cards array contains 5 items because our API returns exactly 5 links. The name has an incremental number at the end because we are showing the card id there. The breed will be empty for now but on line 22, we have an image element that has as a source the img_link which shows the image on the page.
As you can see, all three elements of the object we are pushing in the cards array are being used in the UI. Your UI should look like this:
How UI looks so far
How UI looks so far

Populate Cards – Selected breed

1. Add two new functions in the dogs.service.ts file. Your file should look like the one below:

dogs service file - final version
dogs service file – final version

The first function called getAllBreeds() will get you a list of all available breeds, while the second function, getRandomPicsForBreed() takes one parameter which is the breed you selected and gets you five random images for that dog breed.

2. Open my-dashboard.component.ts and populate the list of dog breeds.

2.1. Declare allBreeds array before the constructor:

Declare array
Declare array

2.2. Create new function called getAllBreeds():

Create getAllBreeds function
Create getAllBreeds function

Given the nature of the data returned by the API, I found it easier to stringify then parse the data. Then, using Object.keys() I return an array containing all the breeds. If you save this file and check the console in the web browser, you should see the below output:

List of breeds - console.log
List of breeds – console.log

3. Allow user to select breed from UI.

3.1. Open my-dashboard.html and add the following code at the top of the page.

<div class="main-container">
<div class="row">
<div class="col-sm-4">
<form>
<mat-form-field>
<mat-select placeholder="Select breed" [(ngModel)]="selectedValue" name="breed" (ngModelChange)="selectedBreed($event)">
<mat-option *ngFor="let breed of allBreeds" [value]="breed">
{{breed}}
</mat-option>
</mat-select>
</mat-form-field>
</form>
</div>
<div class="col-sm-8" align="right">
<button mat-flat-button color="primary" (click)="getRandomPics()" align="center">Random Refresh</button>
</div>
</div>
</div>
<mat-divider></mat-divider>
my-dashboard.component.html - final
my-dashboard.component.html – final

This creates a drop-down that contains all the dog breeds. When a breed is selected, a function that doesn’t yet exist is called. That function will get new random pictures for the selected breed. There is also a button on the right side of the screen. When this button is pressed, the getRandomPics() function is called again and refreshes the cards on the page.

Your button and drop-down will not be aligned correctly, add the following line of code to your index.html file, in the head section.

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"

crossorigin="anonymous">
This imports bootstrap and allows the kind of column alignments we make in our my-dashboard.component.html file.

3.2. Open app.modules.ts and add the following imports:

MatFormFieldModule,
MatSelectModule,
FormsModule
Add modules for select to work
Add modules for select to work

These modules are required for the web page to work and render correctly.

If you save the page now, the dropdown and new button should show up. The button will work fine, but when a breed is selected from the drop-down, an error will show up in the console. That’s because the function that gets called doesn’t exist. On the other hand, the Breed gets set on all of the cards now. That’s because we are using a ngModel and use the same variable on line 29, in the <mat-card-subtitle> element.

3.3. Get images for the selected breed.

First, let’s create a simple function called selectedBreed. All this function has to do is to call a different function that will populate the cards.

selectedBreed()
selectedBreed()

For now, let’s just console log the selectedBreed param and see if it works as we expect it. What we select from the drop down, it should be displayed in the console.

Expected output
Expected output

As you can see from above, whenever we select a breed, the name of the breed is displayed in the console. Now is time to call the function that will get the dog pictures based on the breed.

Next, create the function gets all the pictures of dogs based on the breed:

getRandomPicsForBreed function
getRandomPicsForBreed function

Make sure that line 75 is uncommented and save the file. Check it in the browser. The page should show cards based on the selected breed.

Example of everything working
Example of everything working

Count number of likes

1. Add the following function to my-dashboard.component.ts

public count(card:any) {
  for (var x in this.cards) {
    if (this.cards[x] === card) {
    this.cards[x].likes = this.cards[x].likes + 1;
    console.log(this.cards[x]);
   }
  }
}

This for loop is going through all the cards and if any of the cards matches the card passed in the function, then it will increment the number of likes by one.

Count number of likes
Count number of likes

The console log will show you the card object every time the like button is clicked. Feel free to take out the console.log().

Conclusion

Building this app is a lot simpler than it looks. There is plenty of room for improvements, like adding error validation, allowing users to add their own photos or add unit tests, but the purpose of this tutorial was just to show easy it is to build an application using Angular 6 and Angular Material. Please make sure you read and understand the Angular Documentation properly before trying to work on very advanced projects. It will only make your life easier.

HOW TO: Link headings to navigation list

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.