Ninja Space Content Tech Blog

Postgres issue

May 18, 2021
Today, I ran into a postgres connect issue when I was going back to a database under development on my localhost because I needed to add another feature. This was the error that I received in my terminal when I tried to 'npm run start':

psql: error: could not connect to server: could not connect to server:


I never ran into this problem before so I am thinking maybe something needed updating because even my Postico was not opening my databases. I googled this error and found that someone with a Mac had this problem and fixed it by typing the following command in the terminal:

brew install postgres


Then, my terminal prompted me with the following:
To have launchd start postgresql now and restart at login:
brew services start postgresql
so, I copied and pasted brew services start postgresql

And then typed in: psql in my terminal and it was giving me this error: psql: error: could not connect to server: FATAL:  database "******injaspace" does not exist. 

After that I figured I had to enter createdb in the terminal and it looks like my old databases were wipe out. So in order to get my existing database to work again like it did a couple of weeks ago, I had to create the database again so I entered:

CREATE DATABASE roses;
because roses was what I called my database. So I went back to my project in Visual Studio Code, started the server and voila, the error went away. I seeded my data and it is back now. This took me a good 45 minutes to debug. Hope it'll help you.

Note: I put ****** in place of part of my username for privacy above.
 

Week Seven of Learning Angular

May 11, 2021
I'm officially 30% through Programming with Mosh' Angular tutorial! This week I am learning to pull data using http services with Angular. Read my week-to-week down notes and thoughts as I am learning Angular through an online self-pace tutorial.

I'm already encountering version errors at the beginning. Firstly, HttpModule cannot be imported from @angular/http as it has been deprecated and here are the changes I had to make!

In Mosh' tutorial, he started out with instructing that we need to add the following for the app.module.ts file:

import {HttpModule} from '@angular/http'; and then under imports, add: HttpModule to the array but that created errors for me.

So, I made the following changes in order to compile without errors:

import { HttpClientModule } from '@angular/common/http'; and then under imports, it should be HttpClientModule

Secondly, in Mosh's tutorial, in the posts.component.ts file, he instructed to add
import {Http} from '@angular/http'; and in the constructor with 
constructor(http: Http) That's deprecated so I had to change to the following: import {HttpClient} from '@angular/common/http'; and constructor(http: HttpClient).

Type any[ ] for http class
I spent a good 30 minutes debugging this because I'm learning from Programming with Mosh's tutorial and he used an older TypeScript version and I am using version 11.2.8. In Mosh' tutorial, he initialized posts like this: posts: any[];but I actually had to initialize it like this: posts: any = [];. Otherwise, you'll keep this this error in your terminal: Type 'Object' is missing the following properties from type 'any[]': length, pop, push, concat, and 26 more. Here is my full working code for my version to pull data:

import {HttpClient} from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'posts',
  templateUrl: './posts.component.html',
  styleUrls: ['./posts.component.css']
})
export class PostsComponent {
  posts: any = [];
 
  constructor(http: HttpClient) { 
   
    http.get('http://jsonplaceholder.typicode.com/posts')
    .subscribe(response => {
      console.log(response);
      this.posts = response;
    });
  }
  ngOnInit(): void {
  }
}

Notably, from above, I also didn't have to call the json function to get the json response as it seems to be doing that automatically now under the hood for my version. Mosh had to in his older TypeScript version. Yay, for efficiency!

I also want to say that I love how much time Mosh spends on analyzing data like going into the Network data because I didn't get to go too deep with that in my coding bootcamp days so not having a time-sensitive project coming up lets me really get in deep into this type of response data.

Sample Create, Update and Delete Functions
I know this will be very handy for me later so here were the Create, Update and Delete functions that I created under my posts.component.ts file: 
import {HttpClient} from '@angular/common/http';
import { Component, OnInit } from '@angular/core';

@Component({
 selector: 'posts',
 templateUrl: './posts.component.html',
 styleUrls: ['./posts.component.css']
})
export class PostsComponent {
 posts: any = [];
 private url = 'http://jsonplaceholder.typicode.com/posts'

 constructor(private http: HttpClient) { 
 
 http.get(this.url)
 .subscribe(response => {
 console.log(response);
 this.posts = response;
 });
 }

 createPost(input: HTMLInputElement) {
 let post: any = {title: input.value}
 input.value = '';

 this.http.post(this.url, JSON.stringify(post))
 .subscribe(response => {
 this.posts.splice(0,0, post)
 console.log(response)
 });
 }

 updatePost(post: any) {
 this.http.patch(this.url + '/' + post.id, JSON.stringify({isRead: true}))
 .subscribe(response => {
 console.log(response)
 })
 }

 deletePost(post:any) {
 this.http.delete(this.url + '/' + post.id)
 .subscribe(response => {
 let index = this.posts.indexOf(post);
 this.posts.splice(index, 1)
 })
 }

 ngOnInit(): void {
 }

}
Here's my code from the posts.component.html file:

<input 
(keyup.enter)="createPost(title)" #title
type="text" class="form-control">
<ul class="list-group">
    <li 
    *ngFor = "let post of posts"
    class="list-group-item">
    <button 
        (click)="deletePost(post)"
        class="btn btn-default btn-sm">Delete</button>
    {{post.title}}
    <button 
        (click)="updatePost(post)"
        class="btn btn-default btn-sm">Update</button>
</li>
</ul>
 

Week Six of Learning Angular

April 21, 2021
This week, I am going to be taking notes on reactive forms in Angular. Reactive forms is where you explicitly create the forms that's more complex, like implementing async validation.

Reactive Forms
In order to use formControlName, you'll need to import ReactiveFormsModule to the array on imports in the app.module.ts file. Then, it'll automatically add it as an import to the top of that page like so: 
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
There was a bug that I kept getting following the first part of Programming with Mosh's Angular tutorial. The error was Object is possibly 'null'. This is related to my newer Angular version. I had to make sure the object is truthy in my && conditionals. Here's my html code that I have to fix it:  

<form [formGroup]="form">
    <div class="form-group">
        <label for="username">Username</label>
        <input 
            formControlName="username"
            id="username" 
            type="text" 
            class="form-control">
            <div *ngIf="username && username.touched && username.invalid" class="alert alert-danger">Username is required.</div>
    </div>
    <div class="form-group">
        <label for="password">Password</label>
        <input 
            formControlName="password"
            id="password" 
            type="text" 
            class="form-control">
    </div>
    <button class="btn btn-primary" type="submit">Sign Up</button>
</form>
 
When creating reactive forms, remember to import Validators at the top of the ts file. Here is my code as an example in the ts file:

import { Component } from '@angular/core';
import {FormGroup, FormControl, Validators} from '@angular/forms';

@Component({
  selector: 'signup-form',
  templateUrl: './signup-form.component.html',
  styleUrls: ['./signup-form.component.css']
})
export class SignupFormComponent {
  form = new FormGroup({
    username: new FormControl('', Validators.required),
    password: new FormControl('', Validators.required)
  });

  get username() {
    return this.form.get('username');
  }
}

Display Loader Image or Message
You can use the pending property to display a message, which is so nifty! Here is an example: 

<div *ngIf="username && username.pending">Checking...</div>
 
Simple Error for a Form Because of Angular Version
There as another thing that was different with my latest Angular version and it had to do with AbstractControl. In Programming with Mosh' Angular Tutorial, he used:

removeTopic(topic: FormControll) { let index = this.topics.controls.indexOf(topic);this.topics.removeAt(index); }
 
and this kept throwing a error in my terminal with the following:  Argument of type 'AbstractControl' is not assignable to parameter of type 'FormControl'.

It was I had to change FormControl to AbstractControl and then that fixed it. So my reactive form has the following code in the ts file:
import { Component} from '@angular/core';
import { FormArray, FormControl, FormGroup, AbstractControl} from '@angular/forms';

@Component({
 selector: 'new-course-form',
 templateUrl: './new-course-form.component.html',
 styleUrls: ['./new-course-form.component.css']
})

export class NewCourseFormComponent {
 form = new FormGroup({
 topics: new FormArray([])
 });

 addTopic(topic: HTMLInputElement) {
 this.topics.push(new FormControl(topic.value));
 topic.value='';
 }

 removeTopic(topic: AbstractControl) {
 let index = this.topics.controls.indexOf(topic);
 this.topics.removeAt(index);
 }

 get topics() {
 return this.form.get('topics') as FormArray;
 }
}
And my html file has the following code:

<form>
    <label>Form Array</label>
    <input 
    type="text" class="form-control"
    (keyup.enter)="addTopic(topic)" #topic
    >
    <ul class="list-group">
        <li 
        *ngFor="let topic of topics.controls"
        (click)="removeTopic(topic)"
        class="list-group item">
        {{topic.value}}
      
        </li>
    </ul>
</form>

FormBuilder
These section seemed a bit redundant to me so I didn't code it along with Mosh for this part. It was only a few minutes long. I will revisit FormBuilder some time again in the future.

Multi-Cursor Editing
The cool thing that learned during this particular session is multi-cursor editing. So I can just select the particular word or variable that I'd like to change, press Command and D as many times needed, edit my word and then it'll change those for me.

Abstract Control Error with Possible Null Value
While I was trying to get my validators working in a ts file, I kept getting an error about the object possibly being null when I used Mosh's code. 

In his code, he had:  

static passwordsShouldMatch(control: AbstractControl) {
        let newPassword = control.get('newPassword');
        let confirmPassword = control.get('confirmPassword');

        if (newPassword.value !== confirmPassword.value)
            return { passwordsShouldMatch: true};
            
            return null;
    }

I had to add two more conditionals to get rid of the compile error. Here's my code to fix the error:

static passwordsShouldMatch(control: AbstractControl) {
        let newPassword = control.get('newPassword');
        let confirmPassword = control.get('confirmPassword');

        if (newPassword && confirmPassword && newPassword.value !== confirmPassword.value)
            return { passwordsShouldMatch: true};
            
            return null;
    }

Then, when I was working with its html,  I also encountered object not null possibility error so here were my adjustments. I had to add a couple more truthy conditionals:  

<div class="form-group">
        <label for=''>Confirm Password</label>
        <input formControlName="confirmPassword" type="password" class="form-control">
        <div 
            *ngIf="confirmPassword && confirmPassword.touched && confirmPassword.invalid"
            class="alert alert-danger">
        <div *ngIf="confirmPassword.errors && confirmPassword.errors.required">New confirm password is required.</div>
        </div>
        <div *ngIf="confirmPassword && confirmPassword.valid && form.invalid && form.errors && form.errors.passwordsShouldMatch" class="alert alert-danger">Passwords do not match.</div>
    </div>

Whew, this form section was really hard for me to plow through but I did it! I'm about 29% of the way through the Programming with Mosh tutorial for Angular and it took me 6 weeks guys. I had another project I'm working on and also accepted a writing pitch so that took some of my hours away from this tutorial. However, I am eager to finish it. Read my list of week-to-week Angular notes.
 

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>
 

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.