Ninja Space Content Tech Blog

Deploying React App with AWS Amplify

April 15, 2021
I created an AWS account 3 months ago but hadn't deployed anything on any of their services until last evening! A few months ago, I was having trouble with AWS Elastic Beanstalk and decided to put it in the back burner to learn Angular and TypeScript. Now, I'm ready to dig into AWS again. Instead of using AWS Elastic Beanstalk this time, which was what I originally had in mind, I decided to try out AWS Amplify to see if deploying my React app this way would be easier. It definitely is.

Here were my steps to deploy my React app on AWS Amplify: 
  1. I signed into my AWS account, and then clicked on AWS Amplify. Then, I had the choice to develop using their framework or just deploying. I'm only interested in deploying with the Amplify Console so I clicked on that deploy button option and then clicked on the GitHub link from there to authorize AWS to get access to my GitHub.
  2. Then after my GitHub was successfully connected, I selected the GitHub file that I needed to use to deploy and hit the "Next" button. I clicked "Next" again and then continued to deploy. Then, it sent me to a status screen where I patiently waited until all steps: Provision, Build, Deploy and Verify have taken place.
  3. I clicked on Verify and it says Build Duration was 1 minutes and 42 seconds. From there, under Domain, I found the link where my app was deployed at. Whoa, that was it! No CLI needed for just deployment on AWS Amplify. This was way easier than I thought!
Issue:
Initially, the main issue that I had was my Nodemailer under my Contact section was not working. Otherwise, everything is rendering great. It's because AWS Amplify is server-less so for backend stuff like Nodemailer, it will not work. I created the backend and front end in one app for this one. I will need to try to deploy it on AWS Elastic Beanstalk if I want a full stack app to deploy properly. However, I am pretty happy with how easy it is to deploy a front-end app on AWS Amplify. (Update: I found a workaround with this. See this blog entry on how I handled getting Nodemailer to work via AWS Amplify.)

The Best Thing:
The greatest thing about AWS Amplify that I love is when I do my regular "git push" command for my app, I can just simply click on the right angle bracket via AWS Amplify to update the deployment and I can easily watch it go through the Provision, Build, Deploy and Verify steps. This is a huge time saver! I didn't have to do an "npm run build" command  in my terminal.

Here is my working deployed app link via AWS Amplify: https://master.d27cizkq724af1.amplifyapp.com.
 

Week Five of Learning Angular

April 11, 2021
I am now getting into forms using the Programming with Mosh's Angular Tutorial. I'm in my 5th week of learning Angular and focusing this blog entry on the introduction to forms and narrowing in on Template-driven Forms. Click here to see my weekly breakdown of learning Angular.

Forms
In Angular, it is a requirement to write a div with a class of form-group for any forms like so:

 <div class="form-group">
    <label for="firstName"></label>
    <input id="firstName" type="text" class="form-control">
    </div>  

Zen Coding
One of the amazing things that I learned is zen coding from Mosh as I am going through this Angular tutorial. You can type something like the following: 

div.form-group>label[for='comment']+textarea[id='comment'].form-control and click tab, and you'll get the mark ups needed quickly for html. Then, this will generate the following: 

<div class="form-group"><label for="comment"></label><textarea name="" id="comment" cols="30" rows="10" class="form-control"></textarea></div>


Form Control
Angular has a class called FormControl and you can check the following: value, touched, untouched, dirty, pristine, valid and errors.

Form Group
FormGroup is a class that represents a group of controls in a form. All the attributes from the Form Control can also be seen from Form Group, which includes: value, touched, dirty, pristine, valid and errors.

You need 1 Form Group for a form and each input field has a Form Control to keep in track for each state of fields.

There are 2 types of forms: Reactive (previously called model-driven form) and Template-driven (with directives).  Reactive is good for complex forms. Template-driven is great for simple forms and easier to code with less code.

FormsModule
I received this error message when I was working with Forms: No directive found with exportAs 'ngModel'. What I had to do to use the ngModel directive in my html file is to go to my app.module.ts file and import {FormsModule} from '@angular/forms'; and also make sure I added it under the imports: array. That way I was able to implement this form below without compiling errors.

<form>
    <div class="form-group">
        <label for="firstName">First Name</label>
        <input ngModel name="firstName" #firstName="ngModel" (change)="log(firstName)" id="firstName" type="text" class="form-control">
    </div>  

    <div class="form-group">
        <label for="comment">Comment</label>
        <textarea ngModel name="comment" id="comment" cols="30" rows="10" class="form-control"></textarea>
    </div>

    <button class="btn btn-primary">Submit</button>
</form>

Adding Validation
You can add input validation alerts like so: <div class="alert alert-danger" *ngIf="firstName.touched && !firstName.valid">First Name is required.</div>

Error for Using *ngIf for Forms
I was following Programming with Mosh's tutorial line by line and for my typescript version, I kept getting this error: Object is possibly 'null'.

After digging into Stack Overflow, it's because with Mosh's typescript version, it wasn't an issue. For me I had to add the following conditional with an && to get the compiling error to go away : 
<div *ngIf="firstName.errors">First Name is required.</div>
<div *ngIf="firstName.errors && firstName.errors.minlength">First name should be minimum 3 characters</div>

After debugging for a little while, here's the working code below: 
  <div class="form-group">
        <label for="firstName">First Name</label>
        <input required minlength="4" maxlength="10" pattern="luis" ngModel name="firstName" #firstName="ngModel" (change)="log(firstName)" id="firstName" type="text" class="form-control">
        <div class="alert alert-danger" *ngIf="firstName.touched && !firstName.valid">
            <div *ngIf="firstName.errors && firstName.errors.required">First Name is required.</div>
            <div *ngIf="firstName.errors && firstName.errors.minlength">First name should be minimum {{firstName.errors.minlength.requiredLength}} characters</div>
            <div *ngIf="firstName.errors && firstName.errors.pattern">First name does not match pattern.</div>
            Error!
        </div>
    </div>
Form Classes 
Built into Angular are other classes like ng-form-control, ng-invalid, ng-touched and ng-dirty. To change the styling on your input when a user's input does not meet the criterias, you can utilized these classes to your advantage. Ex for styling: 

.form-control.ng-touched.ng-invalid { border: 2px solid red; }


ngForm Directive
You can also use ngForm to utilize the values of the properties and test by console logging it.

Template-driven Form Example
Here is a great full form example below starting with ts file under that component folder:

export class NewCourseFormComponent implements OnInit {
  categories = [
    {id: 1, name: 'Development' },
    {id: 2, name: 'Art' },
    {id: 3, name: 'Languages' },
  ]
  constructor() { }

  submit(course: any) {
    console.log(course)
  }

  ngOnInit(): void {
  }

Then, in html file:

<form #f="ngForm" (ngSubmit)="submit(f.value)">  
    <div class="form-group">
        <label for="name">Course Name</label>
        <input required minlength="3" ngModel name="name" #name="ngModel" type="text" id="name" class="form-control">
        <div *ngIf="name.touched && name.invalid"></div>
            <div *ngIf="name.errors && name.errors.required">Name field is required.</div>
            <div *ngIf="name.errors && name.errors.minlength">Min length should be {{name.errors.minlength.requiredLength}} characters</div>
    </div>
    <div class="form-group">
        <label for="category">Category</label>
        <select required ngModel name="category" #category="ngModel" id="category" class="form-control">
            <option value=""></option>
            <option *ngFor="let category of categories" 
            [value]='category.id'
            >{{category.name}}</option>
        </select>
        <div *ngIf="category.touched && category.invalid">
            Category field is required
        </div>
    </div>
    <div class="checkbox">
        <label for="moneyBackGuarantee">
            <input ngModel name="hasMoneyBackGuarantee" type="checkbox" id="moneyBackGuarantee" class="form-control">
            30-day money back guarantee?
        </label>
    </div>
    <p>{{f.value | json }}

    </p>
    <button [disabled]="f.invalid" >Create</button>
</form>
 

Week Four of Learning Angular

April 5, 2021
I'm on week 4 of learning Angular now! To see my weekly break down on learning Angular, go to Angular Blogs' List. What I'm realizing is that because I am note taking and coding along the way, a 5 minute video tutorial could easily have me spending 15 minutes to digest the material before moving onto the next video clip! If there is an unforeseen bug, it would take even longer. So make sure you allot enough time in between if you're studying the same way I am.

Using ng-content property
Use ng-content container as mark-up convenience like so:
<div class="panel-body">
    <ng-content select=".body"></ng-content>
</div>

Directives
Use ngIf for looping depending on a condition. We use directives to modify the DOM. There are two types: structural and attribute. Other directives include: ngSwitchCase and ngFor. One way is:  

<div *ngif="courses.length > 0">
  List of courses
<div *ngif="courses.length == 0">No courses yet

 Another way is:  

<div *ngIf="courses.length > 0; then coursesList else noCourses">
    List of courses
</div>
<ng-template #coursesList>
    List of Courses
</ng-template>
<ng-template #noCourses>No courses yet</ng-template>

You can also use the hidden property as well but this doesn't remove the elements from the DOM; it just hides it. Example of a hidden property:
<div [hidden]="courses.length == 0">List of courses</div>
<div [hidden]="courses.length > 0">No courses yet</div>

ngSwitchCase
I really like the ngSwitchCase directive. It's great for switching things back and forth for viewing. Here is the sample code:  
<div [ngSwitch]="viewMode">
    <div *ngSwitchCase="'map'">Map View Content</div>
    <div *ngSwitchCase="'list'">List View Content</div>
    <div *ngSwitchDefault>Otherwise</div>
</div>

Important Note
One thing that threw me off that's different from React is you need a comma after the last object in your array in Angular or else you get a compile error. This is the correct syntax below:  list = [
    {id: 1,name: "course1"},
    {id: 2,name: "course2"},
    {id: 3,name: "course3"},
   ];

ngFor Directive useful values
ngFor is really ngForOf. You can utilize other things in this loop like:  index as i (local variable), first, last, even and odd.

Ex: 
<ul>
    <li *ngFor="let course of courses; even as isEven">
       {{course.name}} <span *ngIf="isEven">(EVEN)</span>
    </li>
</ul>

Remove and Update on Change Detection
Angular is so intuitive. It can detect change and updates automatically. It is so easily to create a remove button for each element like so: 

Under ts file: 
  onRemove(course: any) {
     let index = this.courses.indexOf(course);
     this.courses.splice(index, 1)
   }

Under html file:
<ul>
    <li *ngFor="let course of courses; even as isEven">
       {{course.name}} 
       <button (click)="onRemove(course)">remove</button>
    </li>
</ul>


TrackBy
TrackBy is such a great tool to use when you want to improve performance with large data. Here's an example.
Under ts file:

  trackCourse(index: number, course: any) {
    return course? course.id : undefined;
   }

Under html file:
<button (click)="loadCourses()">Add</button>
<ul>
    <li *ngFor="let course of courses; trackBy: trackCourse">
       {{course.name}} 
      
    </li>
</ul>

Example of an Attribute Directive using ngClass
There's usually more than one way of making something work. Here an example of using a favorite icon with an attribute directive:
<span
    class="bi"
    [ngClass]="{
        'bi-star-fill': isSelected,
        'bi-star': !isSelected

    }"
    (click)="onClick()"
    >
    Star Test Icon
</span>

Styling with CSS
You can style like so:

<button 
    [style.backgroundColor]="canSave ? 'blue': 'gray'"
    [style.color]="canSave ? 'white' : 'black'"
    [style.fontWeight]="canSave ? 'bold' : 'normal'"
>
Save
</button> 

or use ngStyle directive to make it look cleaner like so:

<button 
    [ngStyle]="{
        'backgroundColor': canSave? 'blue': 'gray',
        'color' : canSave? 'pink' : 'black'
    }"
    >
Save
</button> 

Safe Traversal Operator
This is important to use when using complex data. When a value is null, you don't want the console to throw red errors. By solving this , you can use the safe traversal operator with a question mark like so: 

<div>
<span>{{task.assignee?.name}}</span>
</div>

Custom Directives

To create a new directive, go to terminal and type: ng g d directive-name
 

Week Three of Learning Angular

April 1, 2021
I'm on Week Three of Angular and I'm going to re-do a workshop again because I wanted to figure something out that wasn't working properly for me before. I'm coding along with Programming with Mosh's tutorial on Angular.

My Fixes
In the Section 14-Solution-Favorite-Component, Mosh wrote the following line in the favorite.component.ts file: isFavorite: boolean; and it showed a red squiggly line for me and my front end would not compile right. There were two different changes that I could choose in order to fix it. I could either declare the state as false like so: isFavorite = false; or I could add the exclamation point after my variable name like so: isFavorite!: boolean;. The reasoning why it worked for Mosh his way and not for me is because I am using a later version of TypeScript. His tutorial is a few years old. That is something you'll always have to keep in mind as a programmer. Things are always changing.

Component API
This is where the input is the state and the output is the event. You would need to import the Input decorator and also note  @Input() isFavorite!: boolean; in your variable to define an Input property.

Output Properties
For some reason, I had to go over this twice to get it to work. Just like the input part, I had to import Output and additionally, also import EventEmitter and to define the output I had to code the following:  @Output() change = new EventEmitter(); and then add the following as a method: onClick() { this.isTest = !this.isTest; this.change.emit(); } and then finally, in the html file I could implement this like so: <favorite [isfavorite]="post.isFavorite" (change)="onFavoriteChange()"></favorite>

Styles
There are three ways to style. What comes last will become effective. You can write in-line with a style tag. You can use styles through the component.css or add styles property in an array. There's a reference on Shadow DOM.
 

Week Two of Learning Angular Part 2

March 25, 2021
This is Week Two of Angular Part 2, click here to see Week Two of Angular Part 1.

What else impresses me about Angular so far
I am so excited about their pipes and how easily it is to change the format of your data!

Two-way Binding
Following the Angular Tutorial from Programming with Mosh, I kept getting the following error: "NG8002: Can't bind to 'ngModel' since it isn't a known property of 'input'." After some googling, I realized that with my version of Angular installed, I had to go to my app.module.ts file to add:
import { FormsModule } from '@angular/forms'; and include FormsModule under my array of imports.

Using Bootstrap Icons
First, npm i bootstrap-icons. Then add @import "~bootstrap-icons/font/bootstrap-icons.css"; to the style.css file. After that, you can implement the icon of your choice from https://icons.getbootstrap.com.

Creating a New Pipe
You can create a new pipe in the terminal by typing ng g p pipe-name. Go to that ts file and edit the transform section. Then, in the template or html file, you will implement it.

Input Properties
Going through the lesson with Mosh at 15%, I couldn't replicate the same results as he did using the same code. It could be that my Angular/TypeScript version is different than his and so the implementation may be different now. I'll need to revisit this!

Cool Tip
A cool tip that I learned is how to change a variable name and let it change the rest of them by selecting the variable name, click F2 and then change the variable name and click 'enter'.
 

About Ninja Space Content


Ninja Space Content I have been building simple websites on my own since 2008 and currently run several websites at the moment, including this one. I used to be an account manager for an affiliate/e-commerce company, helping affiliates grow their sales so I have some knowledge on the business side and client side of affiliate marketing. During the Covid-19 pandemic, I completed a JavaScript coding bootcamp and graduated in Dec 2020. I've been working as a contractor for a few software companies ever since.
Note: links to resources and promoting special deals may allow me to earn a small commission from each sale.