Ninja Space Content Blog

Connecting Facebook to Yola CMS

May 29, 2021
Today, I'm focusing on adding another way for my visitors to be able to visit my websites without leaving my Facebook pages if they're already on there. I'm a Yola CMS client and there's a tool under my Yola log-in that allows me to add my website that I published through them as a tab on my Facebook page. I'm adding this Facebook publishing integration to a few of my Yola sites. 

As part of my marketing strategy, I always create an associated Facebook page for each website so that there could be some cross-marketing. (Read more about how I leverage free social media marketing to grow my traffic.) I've seen in my Google Analytics reports that every time I post something on social media and include a link in the post to my website, web traffic definitely shows a bit of a spike and occasionally, a big spike. So, I'm going to try this Facebook publishing feature where it adds a new tab on my Facebook page and allow visitors to go on my "Website" without leaving Facebook.

I can only add the Facebook publishing feature to Facebook pages that have lesser likes and followers because it currently only works in an older version of Facebook pages.

I learned that I couldn't implement it on my Facebook page that has over 1,800 likers/followers because Facebook has just updated my higher trafficked Facebook page to their latest version while keeping my less popular Facebook pages on the older version; and Yola's Facebook publishing feature doesn't work on the latest version.

STEPS for Yola Facebook Publishing:

Yola has the Facebook publishing feature under their "Settings". It is turnkey.

  1. Go to "Settings" of your working site. Then, go to "Publishing" on the left side bar. At the bottom of the page, click on "Connect with Facebook". 
  2. Select the Facebook page you'd like to use for this particular Yola site. If you've configured a facebook publishing feature for a different Yola site for a Facebook page before, hit "Edit Settings" instead of "Continue as..." of your account (this will open a new tab or window). Select the exact Facebook page you'd like to use for your particular account (this is for those who have many Facebook pages under one Facebook account), then toggle "Yes" to allow Yola Website Builder to manage your Facebook page. 
  3. Then go back to the original tab of your "Publishing" settings. You'll see a radio button to select that exact Facebook page to allow the "Website" tab to show up on your Facebook page. You'll notice that before you did this, a "Website" tab was not seen from your list of tabs on your Facebook page. After a few minutes, you should see it as Yola has done this for you automatically since you've allowed them to publish it on your behalf. It is pretty cool. 

I would move the "Website" tab on my Facebook page up once it's propagated so that it's on the second tab. That way, visitors can see it when they go on the Facebook page. This will increase awareness and make it more apparent to visitors. See my screenshot below of one of my Facebook pages with this "Website" tab below. 

Importantly, you can only view this "Website" tab on the desktop version of Facebook and not the mobile versions of the Facebook pages.

You can also view Yola's detailed instructions and Q & As on enabling the Facebook Publishing feature for your Yola account.
 

Adding a Sitemap to Godaddy Shared Hosting

May 22, 2021
On May 9th, 2021, I added a sitemap.txt file to one of my React apps so that it can get properly indexed in the search engine and I can start seeing stats on Google's search console. I am current hosting this app on Godaddy's shared hosting. 

Today, a couple of weeks later, I noticed that I am not showing hits on certain pages; just on the homepage. So, I went on my app and utilized real time tracking and I realized Google Analytics doesn't pick it up even in real-time. I figured this may have something to do with my sitemap submission.

To submit a sitemap to Godaddy shared hosting, I just went into the cPanel, went to the public_html and added my sitemap.txt file with a list of the pages I want to index, line by line.

Now, since not all of the pages are being indexed properly, I went into my search console and noticed that it excluded these subpages for some unknown reason. Amazingly, Google Search Console has a URL inspection tool where I can go into each of the links they excluded and request that Google indexes them by clicking on "REQUEST INDEXING" link. Within a couple of minutes, I'm able to see the other pages show up when I am on them via Google Analytics so it was a very easy process! Just watch out for your indexing quota.
 

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.
 

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. Most recently, I decided to complete a JavaScript coding bootcamp and graduated in Dec 2020.
Note: links to resources and promoting special deals may allow me to earn a small commission from each sale.