Angular 13: How to make a clickoutside Directive with RXjs

Going outside with clickoutside directives

Hi all, it has certainly been a while, even though the only comments I get are from bizarre spam bots. As always there is a TLDR for you down below. So lets get into it.

Have you ever been in a situation where you make a lovely custom dropdown menu for someone and you do not know how to close the dropdown when you or they click away?

Well this is where a directive comes in and we even get to use fancy Rxjs in the mix.

Directives are defined as classes that can add new behavior to the elements in the template or modify existing behavior.

First off you will need to create your directive would recommend using the Angular CLI tool on this one.

// Angular generate new service
ng g s servicename

[Pro tip]: If you are unsure where the CLI tool will place your directive you can use the extension –dry-run.

We will be using RXjs in this directive to listen to the clicking of the element outside the assigned element

TLDR here is the Directive code to handle the clicking outside directive. Be sure to declare the Directive in your module that you are using said directive.

import { DOCUMENT } from "@angular/common";
import { AfterViewInit, Directive, ElementRef, EventEmitter, Inject, OnDestroy, Output } from "@angular/core";
import { filter, fromEvent, Subscription } from "rxjs";

@Directive({
    selector: '[appClickOutside]',
})

export class ClickOutsideDirective implements AfterViewInit, OnDestroy {
    @Output() appClickOutside = new EventEmitter<void>();

    documentClickSubscription: Subscription | undefined;

    constructor(
        private element: ElementRef,
        @Inject(DOCUMENT) private document: Document,
    ) { }

    ngAfterViewInit(): void {
        // you are listening for a click anywhere on the document
        this.documentClickSubscription = fromEvent(this.document, 'click')
            .pipe(
                filter((event) => {
                    // the Rxjs filter will return when a click is not within the directive element
                    return !this.isInside(event.target as HTMLElement);
                }),
            )
            .subscribe(() => {
                // upon the case of element clicked outside the subscription will be emitted
                this.appClickOutside.emit();
            });
    }

    ngOnDestroy(): void {
        this.documentClickSubscription?.unsubscribe();
    }

    isInside(elementToCheck: HTMLElement): boolean {
        return (
            elementToCheck === this.element.nativeElement ||
            this.element.nativeElement.contains(elementToCheck)
        );
    }
}

How does this directive work?

The finer detail is that the subscription is being used to subscribe to specifically where the user is clicking on the document. The pipe contains a filter which checks if the user has clicked off the element or on the element, this is where we subscribe to said subscription to when the event has been clicked outside the element. The emitter will emit the appClickOutside emitter.

I don’t care how it works, what else must I do to get this setup in my project!

Assuring that you have created your directive and have declared it in your module next you will need to update the view. On the view of your component you will need to add the appClickOutside directive to the element that wraps around your custom dropdown menu, as you can see on line 2 I have a dropdown wrapper class to ensure that I have the area of the dropdown covered so you may need to specify the height or width depending on your layout.

If the click off is not quite working, I’d advice to take look at your styles and element wrapper.

Ya that is about it. Feel free to take a look at my working sample on github if you are facing any challenges

Working with component instances & @ng-bootstrap’s pop up modal

pop up modal

I’m gonna cut to the chase, so no story time here.

First off here is the documentation for the @ngbootrap Modal !

To install and setup first
run this command line to get access to the @ng-bootstrap/ng-bootstrap node modules.

npm i @ng-bootstrap/ng-bootstrap

Once you have installed the files make a new component for the Modal itself

You would need to import the NgbModal with the line below.


// import into modal.component.ts file
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

For this sample I am using the NgbModal. If you take a look at the documentation it has a list of APIs associated with the NgbModal and we are going to use some of the basic samples to get this up and running.

For the modal.component.html view what is nice is that you can use conditional rendering if you want to hide some of the details. or comment it out…I was having issues toggling and where to hide and show these details and I think this is the simplest way to manage with my specific demo project.

I have a working Angular 9 project that I have setup to emit a value of a userProfile component that contains the details of Name, Job and bio.

I was thinking of going through the code line by line but you’ll need to pass data to the component and through the emitter the function will emit the value to the parent component and now to create the component instance. So in the view you can see I’m using the event emitter value from the card profile component, so
this ‘(selectedProfile)= parentFunction(userProfile)” is going to help us create this component instance of the bootstrap modal in the main app component .

  parentfunction(userProfile:CardProfile) {
    const modalReff = this.modalService.open(ModalComponent, { size: 'sm' });
    const componentInstance = modalReff.componentInstance as ModalComponent;

    componentInstance.userProfile = userProfile
  }

The above is where the magic happens, upon clicking the parentFunction it’ll create a const modalReff. from there you can reference the componentInstance and should have access to the ModalComponent’s inputs and variables.

Granted its a bit of setup work but this is how one would use a component instance in a project

If you have any issues you can check out the working sample project right here

this carries examples of inputs and outputs

Angular how to make reuseable components with @Output Part 2

If you have read my first post covering @inputs then be sure to give that a quick read before continuing.

In the previous post we have covered all our inputs and you might be thinking what about @outputs, well lets make one. When you have an @output it would emit a value up to the parent component, I believe there are many ways to do this, but all I’m trying to say is that @output requires at least an emmitter. As seen in the card.profle component. (picture below).


Update the following code in the app.component.ts file:
  data = [
    {
      name: 'Jonny Doe',
      job: 'FrontEnd Gopher',
      bio: 'I am a Gopher that likes to FrontEnd Gophe',
    },
    {
      name: 'John Dear',
      job: 'Dear FrontEnd',
      bio: 'I am a Dear that likes to dearly FrontEnd',
    },
    {
      name: 'Tony Tones',
      job: 'FrontEnd Developer',
      bio: 'I am a Tony Tones,I use JavaScript, TypeScript and Angular Framework',
    },
  ];

  ngOnInit() {
    this.userProfiles = this.data;
  }

Refresh and you should have 3 loverly gophers staring at you.

In this example we will link the follow button to emit the username of the profile selected to the parent component. This exercise we will use the eventmitter to help us emit the profile name selected to the parent component.

Line 13 we have our @output named btnClick connected to our new eventEmitter of type string (for our name variable).

We use the buttonClicked() function and pass the variable name in the buttonClick(name), which we have declared in our cardprofile component and the next step is to link it on the app.component.html and you can see the emitter btnClick.

And finally to add the function in the app component

Now spin up the project and open the dev tools and click on one of the profiles.

Here we are console logging the profile username to the parent component and thats about it.


Feel free to fork my github, here is the source code.

Dev Notes on Angular: Re-useable components with @Input() decorator (part 1)

Using reusable components and passing data to them. There are a number of ways to pass data to and from parent to child, but I will be focusing on the @Input and @Output decorators. I’m hoping to go through both these guys and have a working angular project with working examples with TypeScript models.

Setting up


I would start by just making a new component via the cmd.

// Generates a new component into the "components" folder.
ng g c components/cardprofile
// or
ng generate component components/cardprofile

From there you will need to build your ideal card UI and take note on what data you would like to populate into said component.

// Just add the card component selector to the app.component like so
<app-card-profile></app-card-profile>
My favorite frontEnd Gopher

Not the prettiest I’m no designer, but this is a card profile component none the less. I think its fine to start with some hard coded data. Just note the details we want to add dynamically, like Name, Job and bio.

In the card profile component i made the following object just for a single entry.


// set within the card profile component for hardcoded data
      name = 'Jonny Doe';
      job = 'FrontEnd Gopher';
      bio = 'I am a Gopher that likes to FrontEnd Gophe';

In the card.profile.component.html view I updated the fields with string interpolation for name, job, bio fields.


// card profile component html
<div class="container">
  <div class="card">
    <div class="banner-image">
      <img class="cover" src="../../../assets/images/profilebgimage.PNG" />
    </div>
    <img class="profile" src="../../../assets/images/gopher.PNG" alt="Avatar" />
    <div class="footer">
      <h1 class="name">{{ name }}</h1>
      <p class="description">{{ job }}</p>
      <p class="description">{{ bio }}</p>
    </div>
    <button class="btn">Follow</button>
  </div>
</div>

Now we have a working card that can accept values and render them in the view!

A good practice would be to create a modal for that data structure, so I made a Card interface.

export interface CardProfile {
    name: String,
    job: String,
    bio: String,
}

Implementation of @input()

Now we import our @Input() from ‘@angular/core’ for the Card component and make an @input for each piece of data we want to populate in the card component.

import { Component, Input } from '@angular/core';


@Component({
  selector: 'app-card-profile',
  templateUrl: './card.profile.component.html',
  styleUrls: ['./card.profile.component.css'],
})
export class CardProfileComponent {
  @Input() name: String;
  @Input() job: String;
  @Input() bio: String;
}

Now that we have our inputs set for the card component we’ll need to pass through the data from the app.component (Parent component) into the card component’s selector, so we’ll need to add the inputs in the card component selector as seen below <app-card-profile> is the child component and we are using it in the app.component.html.


// Add this to your app.component.html
<app-card-profile [name]="userProfile.name" 
          [job]="userProfile.job" 
          [bio]="userProfile.bio">
</app-card-profile>

Now for the data to come from the app.component.ts into the card component via the app.component.html view.

import { Component, OnInit } from '@angular/core';
import { CardProfile } from './models/cardProfile.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  title = 'input-output';

// userProfile with type cardProfile
  userProfile: CardProfile;

// object that we are going to pass into the card component
  data = {
    name: 'Jonny Doe',
    job: 'FrontEnd Gopher',
    bio: 'I am a Gopher that likes to FrontEnd Gophe',
  };

  ngOnInit() {
// setting the userProfile with the data...data
    this.userProfile = this.data;
  }
}

Now to add multiple card profiles! Lets setup the data first and make our userProfile to be userProfiles array…. which i’ll save for the next post.
If you faced any problems have a look at source code on this repo

Deploying angular cannot find js files?

Deploying Angular

Hey gents and ladies, as always there is a TLDR section for all of you. From time to time I need to deploy an angular project to my hosting site and just about everytime I try I come across the same issue.

I have a site hosted by Gator and I have access to the file manager where I can upload my Angular projects and what not.

Just about everytime I come across the following issue and at first it always baffels me.

First is create a folder on my gator file manager and give it the name of my angular project and then do a ng build which creates a dist folder and then upload the dist folder contents (mainly js files) into the folder I created on the gator file manager ( that I pay a hefty price for) then this happens.

Then I think to myself, how does one fix this issue?
Upon closer inspection you will see that the file structure is not quite right. When selecting one of the failed js files have a look at the Request URL. It appears to have skipped my Angular project file name and tries to find the files at the base of my URL as seen below when highlighting main.js.

TLDR

I came across this Stackoverflow solution , which in the command terminal the command will set the baseUrl for the distribution file to find the proper location of said files. I forget the command line so this is a personal note for me.

ng build --base-href=/ANGULARPROJECTNAME/

This will update the file structure and the results after deploying and uploading the appropriate files should look something this. Make sure your File naming convention is inline, I won’t lie this took me a few tries and yes my project is called fireCrud. I had to update my angular.json file to fix my naming convention.

Here is the stackOverflow solution that I referenced

Enjoy and happy deploying. Hope this helps

How to add scss to your Angular project fast

scss new niece

Of course as always there is a TLDR thing somewhere down there.
I come across this from time to time and I normally forget all about it…then I just end up always using css (come on I can not be the only one)

Lets get to it, you have either built or going to build an angular project. In the past i have seen it ask and say “you wanna css, scs,s sasax and …” other options.
so i’d normally select scss and then it just worked.

TLDR COMMAND FOR ANGULAR PROJECT ALREADY BUILT
If you have already built an angular project then run the following line of code.

ng config schematics.@schematics/angular:component.style scss

This should add the style as scss in your angular.json package
for more in-depth detail you can read up on the source. on the one that has 557 votes oh wait 558.

ANOTHER THING TO NOTE
if you get the following error:
“Error Module not found: Error: Can’t resolve PATH in PATH or “didn’t return string.

Be sure to update your component’s style location cause it will still point to your component.css file


In the reference above, they also show you how to add scss to a new project by use of the following command:
TDLR COMMAND FOR NEW ANGULAR PROJECT

ng new NEWANGULARPROJECTNAME --style=scss 

Ok that’s it good luck
If this solution did not work for you, please feel free to comment. I know there never is a solution for everything.

Angular how to generate a new project in to a specific directory

bird and snow

When you are starting you just don’t know what you can do at times. I have been in a situation where I already have a file on where I want to put my new Angular project but sadly my folder structure gets messed up completely.

POST note: You will need to have installed the Angular CLI first before doing this step.

So use this command line below to create an Angular project and place said project into a specific directory of your choosing:

TLDR

ng new angular-project --directory=./new-angular-project-file

This should sort you out. In development its important to keep your work space clean especially your git repo. It doesn’t reflect well if your repo is being reviewed or checked out.

Angular active router link

merryxmas lego

Merry Xmas and there isn’t a TLDR on this post but there is an angular 10 git project repo below! stay safe wear a mask properly and take care of yourselves.


I assure you that this is easier than you think it is. Firstly you’ll need to add the active rout class to your css or scss,

I’ll be honest I went a bit overboard with the styles but ya its for demonstrative purposes I swear

Side Note I would love some feedback on if my image snippets are helpful or readable.
You want to place some code in your style sheets for the active state style.


.nav ul li a.active {
    font-weight: 600;
    background-color:blue;
    color: white;
}

// or just simply
.active {
     font-weight: 600;
     color: white;
}

You want to import this active router functionality into this project so go to your project modules. This snippet is in the context of my project by the way so just note the RouterModule.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './components/home/home.component';
import { PageOneComponent } from './components/page-one/page-one.component';
import { PageTwoComponent } from './components/page-two/page-two.component';
import { PageThreeComponent } from './components/page-three/page-three.component';
import { RouterModule, Routes } from '@angular/router';
import { NavbarComponent } from './components/navbar/navbar.component';

const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'page-one', component: PageOneComponent },
  { path: 'page-two', component: PageTwoComponent },
  { path: 'page-three', component: PageThreeComponent },
  { path: '**', component: HomeComponent }

]; // sets up routes constant where you define your routes


@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    PageOneComponent,
    PageTwoComponent,
    PageThreeComponent,
    NavbarComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    RouterModule.forRoot(routes)
  ],
  exports: [RouterModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


Note the export and imports above, be sure to place it in the correct style sheet. From there active your navigation styles tags like so.

<nav class="nav">
    <ul>
      <li><a routerLink="/home" routerLinkActive="active">home </a></li>
      <li><a routerLink="/page-one" [routerLinkActive]="['active']">page-one</a></li>
      <li><a routerLink="/page-two" [routerLinkActive]="['active']">page-two</a></li>
      <li><a routerLink="/page-three" [routerLinkActive]="['active']">page-three</a></li>
    </ul>
  </nav>

Npm install and make sure nothing is missing and you should be well on your way with the active styles triggering per active link match. For a working example checkout my github project.

For a deeper implementation referencing parents and ancestors please be sure to take a look at the following post.

[newbie] sticky footer css, a solution

its my mums

(AS ALWAYS THERE IS A TLDR BELOW)

The sticky footer. If you have been searching for a while then i think you know what a sticky footer is by now (if not here is a good explanation of one. The challenge is that there is no short way of doing “position stay down please” like so:

position:stay-at-the-bottom-please-thanks-k-bye

You sadly need to know what is going on and what other components/elements are invovled in order to get the position of the footer right at all times…sticky footer style kinda times.

So we now know that there is no one position solution and no position: “sticky” is not an option<insert sarcastic tone>

please note the styles, the colors are horrible.

I tried with the min-height set to 100%, but no dice for me for some reason. The sticky footer is a tricky concept to catch. You need to understand the position property and also its relationship with the absolute position.

Think of the absolute position… its relative to the other style/component overall position.

(had to add a pause when proof reading the sentence)

If this doesn’t work..i would only imagine that the scope of your relative element is not aware of the style that has the position of absolute. Its ….relative to your project and how its structured.

The margin and padding being set to zero is to make sure that the “min-height” takes on the full page. In some cases you may not want to have a scroll bar showing when the page is blank.

TLDR

Of course this is what worked and made sense to me i’m open to update this post or remove it entirely 🙂 have a great evening. (Yes this is a repost on a footer topic that i tried to cover and understand and to which i didn’t understand, so this should work i’m sure of it)

html,
body {
  margin: 0;
  padding: 0;
  
}
.wrapper {
    min-height: 100vh;
    position: relative;
    background-color: rgb(227, 228, 231);
}

.content {
    min-height: 100%;
}

.footer {
    position: absolute;
    width: 100%;
    color: rgb(42, 63, 121);
    height: 100px;
    bottom: 0px;
    left: 0px;
}

Notes:

html, body style updates is to ensure that the wrapper class takes in the whole screen size without padding

.wrapper has that min-height: 100vh (100% of the view height of the screen/device,
position is relative, think of it as a note of where this element is

.footer position absolute, accordance to the relative positioned element
bottom and left refers to setting the element relative to the other element and
place element at the 0th bottom left px of the screen…of the element

Sadly i only have an angular sample project, but it is better than nothing and the results stay the same this uses basic css and works on IE so.. apparently flex box and sticky footer doesn’t work for IE so i could be corrected on this.


Repo for your tinkering: tony2tones github

[newbie] How to add flags on Angular Fast

I am assuming you have already built your angular app.
ok.
As always lets cut to it.

Html syntax required:

// Lists country flags
<div *ngFor="let country of countries">
      <ul>
        <li class="item">
          <a class="flag-icon flag-icon-{{ country.code }}"></a>
          {{ country.name }}
        </li>
      </ul>
    </div>
// Hardcode flag
<div>
 <a class="flag-icon flag-icon-za></a>
</div>

The above sample code will list some flags that have been populated by the countries array. Here is a countries array I made you can use to get started.

 countries: Country[] = [
    {
      name: "South Africa",
      code: "za",
    },
    {
      name: "France",
      code: "fr",
    },
    {
      name: "Switzerland",
      code: "ch",
    }
]

Add this line of code from CDN in your index file’s <header> tag.

https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.5.0/css/flag-icon.min.css
Should look something like this if you not sure.

You’re DONE!
If you are having any troubles you can take a look at
the repo goodbye , good luck and stay safe.