Categories
Angular HTML Javascript

How to disable events in Angular

Sometimes we have an event bound to an element and for any reason we have to avoid that this event is triggered, so we have to disable that event. To do such tasks, in vanilla Javascript we have a method like preventDefault(). We will see how to disable events in Angular.

You can find more info here:

https://www.w3schools.com/jsref/event_preventdefault.asp

The way to accomplish this with Angular is very similar, and we can do do it through the $event object. This object contains information about an event, and it has properties like $event.target to reference the element which triggered the event. You can find more info about Event Binding in angular  here

The way to pass the event as a parameter to a method would be like this:

<button (click)="showModal($event)">Push button</button>

So, if we want to prevent that this click event is not triggered, all we have to do is using the preventDefault() method, this way:

<button (click)="showModal( $event.preventDefault() )">Push button</button>
 Example to apply what we have learned

We will see more clearly with this example.

Let´s assume we have a search bar. When we click on this bar, we will show the search history made by this user. Each element of this list will have some styles added to tell the users they can click the element to perform a new search with this text. It would be something like this:

software behavior to ilustrate how to disable events in angular

But, what if the search is empty? We will show a text to invite the user to enter a valid search. We will use the same HTML element we have to show the search history, but of course, this time, the element should not be clickable, because it is not a part of our search history. Something like this:

software behavior 2. Another example to show how to disable events in Angular.

As we see, “please enter valid search” has different styles and we have prevented the click event from being triggered. Nothing will happen if the user clicks on it.

How have we done it with Angular? This is the piece of code:

<ul class="d-flex flex-fill navbar-nav mb-lg-0">

  <li class="w-100">

    <input class="form-control me-2" type="search" placeholder="Search Gifs..." aria-label="Search" (keyup.enter)="search($event)" (click)="displaySearchHistory()" #searchInputElement>

    <ul id="search-history"  [@openClose]="isOpen ? 'history-open' : 'history-closed'" >

       <span *ngIf="isClickable;else enterValidSearch">

         <li class="clickable-list" *ngFor="let item of this._gifsService.historicObserv$ | async" (click)="search($event)">

            {{item}}

         </li>

       </span>

       <ng-template #enterValidSearch>

         <li (click)="$event.preventDefault()">Please enter valid search</li>

       </ng-template>

    </ul>

 </li>

</ul>

Note: There are parts of the code which are beyond the scope of this article and have nothing to do with how to disable events in angular, since I used things like Angular animations to apply smoother transitions when we show the list. If you want details about Angular animations check official examples here. Also you can see we used Observables and async pipe to show data. I recommend you to see this article to know a bit more about it.

Also the code we used on displaySearchHistory() and search() methods, or to validate if a search is empty or not, will not be detailed here. Many times angular forms are used to do those kinds of validations, but I used plain Javascript. The trim() method was very useful to accomplish it 🙂

The important things we must focus here are the (click) events, and the $event object.

What we did here is validate against a boolean property called isClickable if we will allow the click event to be triggered or not.

In the case isClickable is true, a <li> HTMLelement with the search history will be shown. Notice we will apply a class called "clickable-list" to show some styles when we hover over the result. Just in case you are curious, my css rules are:

.clickable-list{

    /*

        to make each LI element fill all the width of the UL element. As we can see on browser´s console

        it has a padding-left of 2rem, we adjust the margin left as the same negative value.

        The padding left here is to move the text a bit

    */

    margin-left: -2rem;

    padding-left: 2rem;

}

.clickable-list:hover{

    background-color:#FFC107;

    color: white;

}

As we said before, we will be able to control our (click) event and pass it to the search() method with the $event object as parameter. That is why we have written (click)="search($event)"

 <span *ngIf="isClickable;else enterValidSearch">

     <li class="clickable-list" *ngFor="let item of this._gifsService.historicObserv$ | async" (click)="search($event)">

         {{item}}

     </li>

 </span>

With this object we will be able to perform several operations we will need on our code.

But in the case isClickable property is false, we will show a different <li> element. This time, as we said, no operation can be triggered when the user clicks this element. The way to prevent this is using angular ng-template element. With a template variable called enterValidSearch we will reference this template on the *ngIf statement and will show it in the case isClickable is false (that will be validated in our .ts code and, as said, is beyond the scope of this article).

<ng-template #enterValidSearch>

    <li (click)="$event.preventDefault()">Please enter valid search</li>

</ng-template>

Also we can see we can prevent (click) event from firing with $event.preventDefault()

And that´s it! I hope this article is helpful to learn how to disable events in Angular. Please contact me if you see any errors or things I could improve.

*Featured image by Gerd Altmann found in Pixabay

Categories
Angular HTML Javascript

Angular and Observables: how to avoid the subscription with the help of Async Pipe

If you have been using Angular for a while, probably you have met and used the Observables. Observables are part of a paradigm called Reactive Programming, and are included in Angular with the rxjs library. As you can read on the links, Reactive programming and Observables help you work with asynchronous data streams.

You can read more info about Observables in this excellent article

As you can see there, in order to be able to use the Observables, you have to subscribe to them. Subscribing is like calling a function, or invoking the Observable, then you can see the results produced by the Observables.

But when you are using an Observable and want to show the data emitted by the Observable on your component´s template, you can avoid the subscription and, thus, a good amount of logic and code. That is possible with the Async pipe.

It unwraps a value from an asynchronous primitive so you can apply it on the observable and get its result without any subscription.

Let´s see it with a simple example

We have a regular angular component where we have defined an array of numbers and an Observable. The only thing we will do is, create an Observable from that array, and then we will use the Async pipe in the component´s template to show the results.

To create the observable we will use rxjs operators. In this case we will use the of( ) operator

With an array, the of( ) operator emits the whole array at once as an observable, then we can iterate over it and apply the Async pipe.

For more info about this operator and the difference with another commonly used operator to generate observables ( from( ) ), please check following links:

Enough talking, we will see the code:

 

observables-test.component.ts

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

import { Observable, of } from 'rxjs';

@Component({

  selector: 'app-observables-test',

  templateUrl: './observables-test.component.html',

  styleUrls: ['./observables-test.component.css']

})

export class ObservablesTestComponent implements OnInit {

  
 //Observable should have same type as the array, in this case, number[]
  public observableWithAsync$:Observable<number[]>;


  //this array will be passed to the observable using the of() operator

  public arrayToBePassed:number[];


  constructor() {

    this.observableWithAsync$=new Observable();

    this.arrayToBePassed=[0,1,2,3];

   }

  ngOnInit(): void {

    this.observableWithAsync$=of(this.arrayToBePassed);  


  }

}

If you want to know about the differences between the constructor and the ngOnInit, please read this useful link.

Summarizing:

Mostly we use ngOnInit for all the initialization/declaration and avoid stuff to work in the constructor. The constructor should only be used to initialize class members but shouldn’t do actual “work”.

So you should use constructor() to set up Dependency Injection and not much else. ngOnInit() is a better place to “start” – it’s where/when components’ bindings are resolved.

 

Also you could note, I created the Observables using a $ at the end. That has a reason:

https://stackoverflow.com/questions/37671700/angular2-style-guide-property-with-dollar-sign

OK, once we have created the Observable, all we have to do to use it on our template is this:

observables-test.component.html

<ul>

    <li *ngFor="let number of observableWithAsync$ | async">

        {{number}}

    </li>

</ul>

Now, we see all we have to do is iterating over the observable and apply the Async pipe. Output on the screen will be:

This way we will avoid subscriptions and will certainly simplify our code.

Image provided by Luisella Planeta Leoni LOVE PEACE 💛💙 en Pixabay

Categories
Angular GIT and GitHub Javascript

use of .gitignore to ignore a file or folder when you already pushed it to remote version

Let´s asume we have a basic angular scaffolding with a test-folder added. You can find and download it on my github here

As we see, once we create an angular project, it usually initializes a git repository, and  node_modules folder is added to .gitignore by default. If we use visual studio code editor, the files or folders added to .gitignore are colored in grey.

Note: an empty folder will  be nothing to git. That means, it has to contain at least one file in order git considers it has something that can be pushed.

This way, our remote version for this local project will be like this. No node_modules folder is pushed because it is specified on our .gitignore

But now we realized that, for some reason, we don’t want “test-folder” to be on our remote repository on github anymore; but we still need it on our local version, so we can´t simply delete it.

An option is add it on our .gitignore file

There we find the already  ignored files by default, for example:

So, everything should be as easy as adding our test-folder to this file and the problem should be solved…

Unfortunately it is not so easy.

Despite you add this update your .gitignore and push the changes, test-folder will still be on your remote:

The thing is, .gitignore won´t delete the ignored files or folders from your remote repository if they are already there.

To achieve what we want, once the folder or file we want to ignore is added to the .gitignore file, we should move the folder or file we want to ignore outside of the project, and then add, commit and push new changes to the remote.

First, we will move it outside our local project

Once we add, commit and push changes, we can see it also disappeared from remote

Right now, we can move again our test-folder inside our project:

Did you notice? Despite we added the folder again, now the master branch acts like nothing new is added; that is because the test-folder is on the .gitignore file.

To test if it works, we will make a change on any other file, to push changes into the remote.

Something simple, for example change the site title on the main component of the app

Now you can see, after adding, committing and pushing changes, the test-folder has been successfully ignored.

EDIT: When you try to push changes, you could see something like this:

As explained here, that can happen if you made some changes on the remote branch which are still not done on the local branch. Foe example if you deleted already existing files on remote and added them to .gitignore on local branch.

You have 2 ways to solve it, as pointed on the link:

  1. import new changes from REMOTE and merge it with your code and then push it to remote.
  2. You can use this command to force changes to the server with the local repository (). remote repo code will be replaced with your local repo code.
    git push -f origin master
    

    With the -f tag you will override the remote branch code with your local repo code.