Sunday 30 December 2018

How to write your own attribute directive in Angular?

Background

In the last post, we saw how to use structural directives like *ngIf and *ngFor that can be used to modify DOM elements. 
Attribute directives can change the appearance or behavior of an element, component, or another directive. In this post, I am going to show you how to write your own attribute directives in Angular.

For this, we are going to create a directive which on single click will enlarge our text and on double click get it back to original size. 

How to write your own attribute directive in Angular?

Let's start by writing our directive class file. Under the app folder create a new file called enlarge.directive.ts.  In this file add following code -


import { Directive, ElementRef, HostListener, Input, Renderer2 } from '@angular/core';
@Directive({
  selector: '[appEnlarge]'
})
export class EnlargeDirective {


  constructor(private el: ElementRef, private renderer: Renderer2) { }


  @Input('appEnlarge') appEnlargeSize: string;


  @HostListener('click') onclick() {
    this.enlarge( this.appEnlargeSize || '100px');
  }


  @HostListener('dblclick') ondblclick() {
    this.enlarge('50px');
  }


  private enlarge(enlargeSize: string) {
    this.renderer.setStyle(this.el.nativeElement, 'font-size', enlargeSize);
  }
}


Let's go over this code and try to understand what we are doing here.  1st line has a couple of imports that we will understand as we go ahead. Next line has an annotation called @Directive which states that this class is a directive and its selector is appEnlarge. So you could use this directive as follows -
  • <p appEnlarge>Directive applied for this content!</p>
We will see this in action in some time. Next, we have a constructor where we have access to the native element and the renderer. We can use APIs from renderer or Native element to actually make changes to the element.

Next, we have an input called appEnlargeSize. Here the user can specify how much the context needs to be enlarged. Notice how we have used an alias here in the bracket. This is so that we could specify input and directive in the same binding as below -
  • <p [appEnlarge]="'120px'">Directive applied for this content!</p>
Then we are using HostListener APIs for single and double click to actually do our transformation - which is increasing the font size. You can see all HostListener APIs here -
 Notice how in enlarge function we have used renderer API of setStyle to apply our desired style. You can see all renderer2 APIs here -

Now that your directive is done let's import it and declare it in our main module. Go to app.module.ts  and import it. Also, add it in the declaration section. Your app module should look like below -

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


import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import {EnlargeDirective} from './enlarge.directive'

@NgModule({
  declarations: [
    AppComponent,
    EnlargeDirective
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule { }

And that's it. Save all your changes and start your angular app using -
  • ng serve
Go to http://localhost:4200/ and see your changes.

Single click on the text to enlarge it and double click it to bring it to its original size.






This is not a great example with perfect CSS and animation but I hope this gives you an idea of how you can write custom directives in angular.  These are very powerful techniques to change the appearance of your components. Let me know if you have any questions. Thanks.


This is the last post of the year 2018 :). So wishing all a very happy new year! Hoping coming year would be more awesome with a lot of more learning and sharing!

Related Links

Thursday 27 December 2018

Using structural directives in Angular

Background

There are 3 kinds of directives in 
  1. Components—directives with a template.
  2. Structural directives—change the DOM layout by adding and removing DOM elements.
  3.  Attribute directives—change the appearance or behavior of an element, component, or another directive.
We have already seen how to create components, how components interact with each other. Structural Directives change the structure of the view whereas Attribute directives are used as attributes of elements. You can use build in directives provide by angular or build your own.

In this post, I will explain structural directives such as *ngIf and *ngFor.


Using structural directives in Angular

As mentioned before structural directives manipulate the DOM structure by adding or removing elements from the DOM.  An asterisk (*) precedes the directive attribute name. Let's see an example by using *mgIf. This structural directive is used to decide if the element on which it is applied (including its children) are added in DOM or not.

So in your AppComponent code make changes so that the HTML template looks like below -

<div class="hello-world">

  <h1 *ngIf="showMessage">Hello World!</h1>
  <br/>

  <button (click)="toggleVisibility()">Toggle Visibility</button>
</div>


Notice the way we are using *ngIf. It says if showMessage variable evaluates to true then show this h1 element and if not remove it from the DOM. Then we have a button which says "Toggle Visibility" that essentially toggles the showMessage variable flag. Let's see the component typescript code to understand this better. Your component code would look like following -

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


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  showMessage: boolean = false;

  toggleVisibility = () => {
    this.showMessage = !this.showMessage;
  }

}


Notice the showMessage variable of type boolean. It is set to false at the beginning and as you click the button this flag is toggles which change the visibility of our H1 element. Please note that *ngIf removes the element from the DOM and does not just change the visibility. So when I say changes visibility I mean it being part of the DOM. So let's give this a try. Start your app with -
  • ng serve





Notice how the h1 elements take part of DOM and when it is not visible it gets removed. Your button position will get adjusted based on that.

NOTE: When the condition is false, NgIf removes its host element from the DOM, detaches it from DOM events (the attachments that it made), detaches the component from Angular change detection, and destroys it. The component and DOM nodes can be garbage-collected and free up memory.

The asterisk is "syntactic sugar" for something a bit more complicated. Internally, Angular translates the *ngIf attribute into a <ng-template> element, wrapped around the host element.


Now let's take a look at *ngFor directive.

Change the component code to have an array of cities.


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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  cities: string[] = ["Mumbai", "Bangalore","Delhi","Chennai","Hyderabad"];

}


Now you can change this components HTML code as follows -

<div class="hello-world">
  <ul>
      <li *ngFor="let city of cities">{{city}}</li>
  </ul>
</div>


This essentially creates an unordered list element and inside it, iterates over each of the cities in the array and creates a list element. This would look like below -




NOTE: Angular desugars this notation into a marked-up <ng-template> that surrounds the host element and its descendants. Each structural directive does something different with that template.

As mentioned before you could also create your own structural directives. To read more on these go to the angular documentation - https://angular.io/guide/structural-directives

Related Links

Wednesday 26 December 2018

How to dynamically create a component in Angular?

Background

In the last few posts, we have been seeing how to write applications in Angular. If you wish to revisit some of them take a look at the Related Links section at the bottom of this post. In this post, I will show you how to dynamically create components on Angular. I am assuming you already have the boilerplate code we have written so far. This would be an extension to it.


How to dynamically create a component in Angular?

Let us start making changes from the AppComponent. If you remember this is the component we have added in the bootstrap property of our root module. Go to the HTML content of this component, remove all the code we had added before for routing and replace it with the following code -

<div class="hello-world">
  <h1>{{title}}</h1>


  <button (click)="genComponent('Botton 1 Clicked!')">Button 1</button>
  <button (click)="genComponent('Botton 2 Clicked!')">Button 2</button>


  <template #messagecontainer>
  </template>


</div>

It is a simple HTML content. Let me explain this first. 

  • We have a simple h1 tag which has a bound value called title. title value would be provided by the corresponding component definition in the typescript file. We will come to the changes in typescript file in a moment. 
  • Next, we have 2 buttons that call the function genComponent on the click event. This function definition would again go in the typescript file which we will see shortly.
  • Lastly, we have a template tag where we will dynamically load our component. This new component as we will see has a bound value called msg which is what you see as the argument of genComponent function.
Now let's see how the typescript file for this looks like -

I am going to create a new component in the same AppComponent file. If you wish you can create a new file for it. The component is as follows -

@Component({
  selector: 'app-child',
  template: `
<h2>Message : {{msg}}</h2>
`
})
export class ChildComponent {
  @Input() msg: string;
}

As you can see this ChildComponent which we intend to create dynamically take an argument msg as input. We will see how we can pass this input when we dynamically create this. You can also see it's HTML content - It simply has an H2 tag with the bound msg input.

Now, let's take a look at AppComponents definition -

import { Component, Input, ViewChild, ViewContainerRef, ComponentFactoryResolver, OnDestroy } from '@angular/core';




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


  @ViewChild('messagecontainer', { read: ViewContainerRef }) entry: ViewContainerRef;


  constructor(private resolver: ComponentFactoryResolver) { }


  genComponent(msg) {
    this.entry.clear();
    const factory = this.resolver.resolveComponentFactory(ChildComponent);
    this.componentRef = this.entry.createComponent(factory);
    this.componentRef.instance.msg = msg;
  }
  destroyComponent() {
    this.componentRef.destroy();
  }


  ngOnDestroy() {
    this.destroyComponent();
  }
}

Let us see what this is doing -
  • We already say the content of app.component.html above where we removed the navigator outlet and added 2 buttons and a template for dynamically loading our CHildComponent.
  • Inside the component definition, we have a variable called title which we say in the HTML template inside h1 tag.
  • Then we have an entry variable which points to the template tag we have created in AppCpmponents HTML file.
  • We can access template as the ViewChild inside the Component class. The template is a container in which, we want to load the ChildComponent dynamically. Therefore, we have to access template as ViewConatinerRef.ViewContainerRef represents container where one or more view can be attached.
  • Next, we have defined a constructor where we have injected ComponentFactoryResolver dependency. We need this to create the component dynamically.
  • Then we have 2 methods  - genComponent and destroyComponent that is used to create and destroy our ChildComponent dynamically. Notice how we are storing the reference of the new component in componentRef and using it.
  • In genCompinent we are doing the following -
    • Clearing the container
    • Creating a factory for ChildComponent
    • Creating component using above factory
    • Passing the value msg input using component reference instance method
  • Also, notice we are calling destroyComponent in ngOnDestroy lifecycle hook of angular component. You could add this login inside an event of your own as well. 
  • You also saw how our ChildComponent has an input called msg and you can see in genComponent function we are passing this input as this.componentRef.instance.msg.
  • Also, take care of all the imports that are on the 1st line of the above code.
NOTE: The entry component which is a reference to the template tag has APIs to create and destroy components.

The final changes that we need would be in the AppModule itself. We need to define our new Child component in declaration and entry components. So import the new ChildComponent in the AppModule and put it under declaration and entryComponents 


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

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NewEmployeeComponent } from './employee/new-employee/new-employee.component';
import { SubempComponent } from './employee/subemp/subemp.component';



@NgModule({
  declarations: [
    AppComponent,
    NewEmployeeComponent,
    SubempComponent,
    ChildComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents: [ChildComponent]
})
export class AppModule { }

Now you should be all set to test out your code. Start your angular application with -

  • ng serve
and open your application on the set port (default 4200)-






Related Links

Tuesday 25 December 2018

How to write your own webpack plugin?

Background

In the last post,


we saw how we can customize webpack build configuration without using "ng build" command with angular CLI 6. In this post, I will show you how we can build our webpack plugin and use it in our angular project.


Setup

We already created a custom webpack configuration file in the last post. So let's start from there. Our relevant angular.json webpack config has the following part - 

"architect": {
  "build": {
    "builder": "@angular-builders/custom-webpack:browser",
    "options": {
"customWebpackConfig": {"path": "./custom-webpack.config.js"},


So our custom webpack config file is -
  • ./custom-webpack.config.js
Let's go ahead and make changes to this file so that we can provide it our own plugin to work. Add the following code to it -


const MyWebPackPlugin = require("./webpack-plugin.js")
 
module.exports = {
    plugins: [
        new MyWebPackPlugin({
            message: 'Hellow World!'
        })
    ]
}

As you can see it tells webpack that it needs to use a custom webpack plugin supplied. Also if you remember from last post configurations in this file are merged with the default ones. So no need to provide all webpack configurations in this file. Just the ones to add/edit should suffice.


In the above code, we are saying we need a plugin wrote in a separate file called ./webpack-plugin.js. Once we import it we create an instance of the plugin class and pass a variable called message to it. We will see this plugin class in a moment. So whenever webpack runs it will use this plugin. 

For the actual plugin code create a file called custom-webpack.config.js in the same folder as webpack-plugin.js and add the following code to it.


class MyWebPackPlugin {
    constructor(optionInput) {
        this.options = optionInput;
    }
    apply(compiler) {
        compiler.hooks.done.tap("MyWebPackPlugin", () => {
            console.log("Message is : " + this.options.message);
        });
    }
}
module.exports = MyWebPackPlugin;



This is essentially creating a Plugin class called MyWebPackPlugin. It has a constructor which takes in options. If you revisit code in custom-webpack.config.js  written above you will notice we are passing options to the instance of MyWebPackPlugin which has a message variable. 

The directory structure for your reference is as follows -


Understanding the Plugin

A webpack plugin is a JavaScript object that has an apply method. This apply method is called by the webpack compiler, giving access to the entire compilation lifecycle.


So you see there is an apply method in the class we wrote above which takes an argument called compiler. This gives us access to complete compilation lifecycle. In the above example, we are looking for "done" event and getting a callback for that. To see a list of all hooks available visit - 
To see all plugin APIs refer -

Finally, in the callback, we are printing out the value of message we got from our angular app.

NOTE: We are using webpack 4. Plugin code would look slightly different for webpack 3.

Let's run ng build and see if our changes worked!




And you can see our message getting printed in the console.


Related Links




Monday 24 December 2018

How to customize build configuration with custom webpack config in Angular CLI 6

Background

In Angular CLI 1.x (Angular 5) we had a command called "ng eject" which ejected underlying webpack configuration so that you could make changes based on your requirements. This has been disabled with Angular CLI 6.


As you can see it will be completely removed in Angular CLI 8.0 version. In this post, I will show you how you can customize your builds with custom webpack configuration without using ng eject. For this, we will use a library called angular-builders. This post assumes you have done necessary setup and have basic knowledge of Angular 6. I have written multiple posts previously on these. If you are not following it then take a look at the links in the related section at the end of this post.

This uses the concept of Builders. You can provide a builder of your own or can use one that is provided by the community.


How to customize build configuration with custom webpack config in Angular CLI 6

Let's start by adding new dependencies. Go to package.json and add following dependencies under devDependencies =

"@angular-builders/custom-webpack": "^7.0.0",
"@angular-builders/dev-server": "^7.0.0",
"@angular-devkit/build-angular": "~0.11.0", 

Make sure build-angular dependency is ~0.11.0. This is something that you may need to upgrade version for. We will see in a  moment how to use this. Once done go to your apps root folder and run -
  • npm install
This should install the required additional dependencies in the node_modules folder in the same directory.


Now go to angular.json file. Here you need to change the builder from "@angular-devkit/build-angular:browser" to "@angular-builders/custom-webpack:browser".

NOTE: If you are building an universal app and would like to change server build configuration use @angular-builders/custom-webpack:server instead of @angular-builders/custom-webpack:browser.


Next, you need to add customWebpackConfig property to your build target options to point it to your custom webback config file.

"customWebpackConfig": {"path": "./custom-webpack.config.js"},

Now your angular.json build configuration should look something like -

      "architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "customWebpackConfig": {"path": "./custom-webpack.config.js"},
            "outputPath": "dist/angular-demo",
            "index": "src/index.html",
            ....


Now you can create a file called custom-webpack.config.js in the root directory (Same place where the angular.json file exists).

In this file, you can add your custom webpack config. For example, if you want to add a custom loader for files with extension .example you can do something like below -


const path = require("path");

module.exports = {
  module: {
    rules: [
      {
        test: /\.example$/,
        use: ["example-loader"],
        include: path.resolve(__dirname, "./")
      }
    ]
  }
};



NOTE: Unlike ng eject command this configuration will be merged with default angular build configuration. So you need to add configuration to this file which you wish to change/add (and not the whole thing).


How to use ng serve with custom webpack configuration we set up above?

If you wish to use ng serve with above setup - i.e with custom webpack configuration make following additional changes -

Inside serve target in angular.json file change "builder": "@angular-devkit/build-angular:dev-server" to "builder": "@angular-builders/dev-server:generic".

Your serve target should look something like below -


"serve": {
  "builder": "@angular-builders/dev-server:generic",
  "options": {
    "browserTarget": "angulardemo:build"
  },
  "configurations": {
    "production": {
      "browserTarget": "angulardemo:build:production"
    }
  }
},


Now you can do an ng serve and custom webpack configuration changes we did will be used.

In the next post we will see how we can create a custom webpack plugin with setup in place. So stay tuned :)


Related Links

Wednesday 5 December 2018

Passing data between the nested component in Angular

Background

In the last post, we saw how we can create nested components in Angular -
We also saw a few other angular things - links creating a new App, using Angular CLI, understanding project structure etc. All the links are in the related links section at the bottom. In this post, I will show you how to pass data from parent component to child component and listen for data to be passed from child to parent. 

I am going to continue using previous code example that we have built so far. So if you need additional guidance before we start with this code, look up the previous post that talks about building nested components

Passing data between the nested component in Angular

At this point, you should have a parent component called NewEmployeeComponent and a child component called SubempComponent. Child component just has a static HTML saying that subcomponent works. And it gets rendered as part of the parent component. All of this works and we saw it in the last post. If you do have a question till here I would recommend to go back and read my previous post -
Now let's add some input and output properties in the child component. Your child component code should look like below -

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
  selector: 'app-subemp',
  templateUrl: './subemp.component.html',
  styleUrls: ['./subemp.component.css']
})
export class SubempComponent implements OnInit {


  @Input()
  department:string;


  @Input()
  designation:string;


  @Output()
  joined:EventEmitter<string>;


  constructor() {
    this.joined = new EventEmitter();
  }


  ngOnInit() {
    console.log("SubempComponent initialized");
  }


  onButtonClick = function(event) {
    console.log("Button clicked. Emitting now!")
    this.joined.emit("Joined department " + this.department + " with designation " + this.designation);
  }


}

Notice here that department and designation are two parameters which are input and are of type string. So we would expect the parent component to send it to this child component. Next, we have an output parameter called joined which is an EventEmitter. Parent component which creates this child component can catch and handle this output and we will see how in a moment. Finally, we have a function onButtonClick that actually emits a string saying that the button was clicked with the particular designation and department. We will now see when this function will get called. But essentially once this function is called we emit the string which the parent component can intercept and handle.

Now let's see child components HTML code -

<h1>This is sub components heading</h1>
<p>
  Yay! subemp works!
  Department : {{department}} <br/>
  Designation : {{designation}} <br/>


  <button (click)="onButtonClick($event)">Click to join!</button>
</p>


From the previous version of the code, I have just added lines to print department, designation and a button on click of which we call function onButtonClick which we just saw above. This function will, in turn, emit the event that will be caught and handled in the parent. We will now see changes in parent component and once done we will execute our code and see it in action.


Make changes to parent component typescript file so that it looks like below -

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

@Component({
  selector: 'app-new-employee',
  templateUrl: './new-employee.component.html',
  styleUrls: ['./new-employee.component.css']
})
export class NewEmployeeComponent implements OnInit {

  name: string;
  age: number;

  constructor() { }

  ngOnInit() {
    this.name = "Aniket";
    this.age = 27;
  }

  childClickedButton = function(event) {
    console.log("Child component clicked. event : " + event);
  }

}



Notice that the only new change here is a new function called childClickedButton that we will use to catch and handle the output of child component we say above.

Now make changes to the parent's HTML file so that it looks like below -

<h1>Welcome to the Employee portal</h1>

<h3>Name : {{name}}</h3>

<h3>Age : {{age}}</h3>

<app-subemp

    [department]="'IT'"
    [designation]="'Software developer'"
    (joined)="childClickedButton($event)"
></app-subemp>

</pre>



We have changed some things in the way we add child component in the HTML file. This is how we send input to the child component and handle the output. It's called data binding. So we are essentially sending department and designation as inputs to the child component. We saw these as @input() variables in child component. Similarly, we are now catching joined which was a output and calling our user defined function childClickedButton function. So the string emitted by the child on the actual button clicked will be sent as the event to this function.

Now let's see this in action. Run the app with command -

  • ng serve -o
You should see the following screen -




Make sure you go to the correct URL path to render the components. Now you can click the "click to join" button in the parent and see the console logs. You should see the following -






You can see the button click event happened which emitted the event from the child. Parent captured it and printed another console log. That's how you can configure inputs and outputs for nested angular components and pass data.


Related Links



  • Angular Hello World example(OSFG)
  • Understanding angular application folder structure(OSFG)
  • Routing and navigation in Angular(OSFG)
  • Building nested components in Angular (OSFG)
  • Tuesday 27 November 2018

    Building nested components in Angular

    Background

    So far in learning Angular, we have seen following posts -
    1. Angular Hello World example
    2. Understanding angular application folder structure
    3. Routing and navigation in Angular
    This post is the continuation of the same series. If you are directly landing on this post please do take a look at above posts to understand the basics. This post assumes you have an Angular project set up with a component and it's navigation.

    In this post, we will try to add a new component that will be used in our existing component.


    Building nested components in Angular

    In the last post, we created a new component new-employee and set up navigation for it. Following is the final output from it.



    In this post, we will create a new component and add it inside our new-employee component. So let's create a new component. To do that execute the following command -

    • ng g c employee/subemp
    This is shorthand for -
    • ng generate component employee/subemp
    Your output should look like -


    athakur@athakur-Inspiron-7560:~/Documents/per_code/angulardemo$ ng g c employee/subemp
    CREATE src/app/employee/subemp/subemp.component.css (0 bytes)
    CREATE src/app/employee/subemp/subemp.component.html (25 bytes)
    CREATE src/app/employee/subemp/subemp.component.spec.ts (628 bytes)
    CREATE src/app/employee/subemp/subemp.component.ts (269 bytes)
    UPDATE src/app/app.module.ts (597 bytes)
    

    Notice the new files created and the root module updated with import and declaration of the new component. This is exactly the same steps we did for our earlier component. If you recall in the last post we generated the new-employee component similar way -
    • ng generate component employee/new-employee 
    The directory structure should look like below now -




    Now let's start adding code. First, go to subemp.component.ts and add/edit code so that it looks like below -

    import { Component, OnInit, Input } from '@angular/core';
    @Component({
      selector: 'app-subemp',
      templateUrl: './subemp.component.html',
      styleUrls: ['./subemp.component.css']
    })
    export class SubempComponent implements OnInit {
      constructor() { }
      ngOnInit() {
        console.log("SubempComponent initialized");
      }
    }
    


    This is a very basic boilerplate code.  Notice that this components HTML is in file './subemp.component.html' and similarly, CSS is in './subemp.component.css'. Also, note that this components selector is called 'app-subemp'. So that's the tag we will use in the parent's HTML template file.

    Let's make changes to the child's HTML template now. Go to './subemp.component.html'  and add following code.

    <h1>This is sub components heading</h1>
    <p>
      Yay! subemp works!
    </p>
    
    

    There are no changes needed in the CSS file. But if you are defining custom CSS then you can add it in 
    './subemp.component.html'. Now finally let's add the child component in the parent component. So go to parent components HTML file - new-employee.component.html and make sure it looks like below -


    <h1>Welcome to the Employee portal</h1>
    <h3>Name : {{name}}</h3>
    <h3>Age : {{age}}</h3>
    <app-subemp></app-subemp>
    


    The only new thing that we have added here is an <app-subemp></app-subemp> tag that we say was the selector of the child component. Now finally run -
    • ng serve -o
    to build and run your angular app and you should see below output in the browser.




    You can see how the sub-component renders inside the parent component.

    Also, note that we added this route in the last post. So we are just navigating to this route and seeing the changes.

    If you are wondering how it figures out the app-subemp tag then you can look at the app.module.ts file which is the angular root module file. Here we have imported this new component and added in the declaration section. This automatically happens when you use angular cli to generate a new component like we did above with command -

    • ng generate component <component_name>
    In the subsequent posts, we will see some more angular topics so stay tuned.



    Related Links

    Sunday 25 November 2018

    Routing and navigation in Angular

    Background

    This post is in continuation of previous two posts on Angular -
    In this post, we will see how we can set up routing and navigation in Angular. If you are new to Angular please read the Hello World go through the posts above first. This post assumes you have a base project already setup as we did in the last post.

    Our current angular project looks something like below -




    Routing and navigation in Angular

    Before we start adding routing and navigation let's add a new component first and then we would add routing to that component. To generate a new component we can use the following command -
    • ng generate component <component-name>
    In our case, we will create a new component called new-employee and we will put it under a directory called employee. So use the following command -
    • ng generate component employee/new-employee 



    You can see it creates/updates following files -
    • CREATE src/app/employee/new-employee/new-employee.component.css (0 bytes)
    • CREATE src/app/employee/new-employee/new-employee.component.html (31 bytes)
    • CREATE src/app/employee/new-employee/new-employee.component.spec.ts (664 bytes)
    • CREATE src/app/employee/new-employee/new-employee.component.ts (292 bytes)
    • UPDATE src/app/app.module.ts 

    Let's try to understand what each file is -
    • new-employee.component.ts : Components typescript file
    • new-employee.component.html : Components HTML file
    • new-employee.component.css:  Components CSS file
    • new-employee.component.spec.ts : File corresponding to the test for the component
    • src/app/app.module.ts : New Component is added to imports and declaration in the main module file.
    Now that we have generated our new component let's add some HTML for it. Notice it is similar to the root component in terms of file and structure. Root component is used to render the main page and all the remaining component can be rendered/navigated through the main component. Root component is always added in the bootstrap property of the main angular module. In our case it is AppComponent. Our code and directory structure should look like below -


    Now let's add some code to our new component. First, we will add some variables that we can dynamically set and bind in our HTML file. So go in the components typescript file (new-employee.component.ts) and add name and age as variables. In the ngOnInit method, initialize these to the values you want. So the typescript file looks like below -


    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-new-employee',
      templateUrl: './new-employee.component.html',
      styleUrls: ['./new-employee.component.css']
    })
    
    export class NewEmployeeComponent implements OnInit {
    
      name: string;
      age: number;
      constructor() { }
      ngOnInit() {
        this.name = "Aniket";
        this.age = 27;
      }
    }
    

    Now let's write the corresponding HTML file (new-employee.component.html). Remove any existing code that might be present there and add below code -

    <h1>Welcome to the Employee portal</h1>
    
    
    <h3>Name : {{name}}</h3>
    <h3>Age : {{age}}</h3>
    

    Notice how we are binding name and age variables from our typescript file. You can possibly change this values on events and the changes should immediately reflect in the rendered page.


    Now that we have our components HTML and typescript file ready let's do our navigation setup. Note you can also add your custom CSS in new-employee.component.css. To add navigation we will make changes in app-routing.module.ts file.

    If you remember our first tutorial we when we created our angular app we said setup routing to yes. This should create an app-routing.module.ts file for you. This should already have the boilerplate code for routing like importing router modules and exporting the module itself so that it can be imported into our main module. Make changes to this file so that it looks like below -

    import { NgModule } from '@angular/core';
    import { Routes, RouterModule } from '@angular/router';
    import {NewEmployeeComponent} from './employee/new-employee/new-employee.component'
    
    const routes: Routes = [
      { path: 'newemployee', component: NewEmployeeComponent }
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    
    export class AppRoutingModule { }
    


    Here we have imported our new component. That's line -
    • import {NewEmployeeComponent} from './employee/new-employee/new-employee.component'
    Then we have added a route for this component in the empty array the boilerplate code had. This essentially says if anyone tried to access the "/newemployee" path then use the NewEmployeeComponent and render it to the router outlet. We will come to router outlets in a moment. 

    So that's the two changes we have done. Now go back to app.module.ts and verify that 
    1. NewEmployeeComponent is imported and added to the declaration section.  
    2. AppRoutingModule is imported and added to the imports section
    Once you have verified this, we have one last thing to do - add router outlet. Before I proceed let me summarize the angular bootstrap process that happens. We know our configuration is in the angular.json file which points to our main file main.ts that essentially bootstraps our main module app.component.ts. The main module will try to load the root component app.component.ts that has selector app-root by default. This selector is used in our main index.html page which us again configurable from angular.json. You can also notice that default index.html file has the tag   <app-root></app-root> in the body which is where our root component renders. You would also see that AppComponent which is our root component is listed in the bootstrap property in the main module. 


    As you must have already been wondering there is no routing support added so far. And that is correct. We need to tell angular where the component should render. And for this, we use a special tag called -
    • <router-outlet></router-outlet>
    So let's add this in our root component HTML file. So go to app.component.html and make changes so that it looks like below -


    <div class="hello-world">
      <h1>Hello World!</h1>
    
      <p>----------</p>
      <h1>Routed modules go below</h1>
      <p>----------</p>
      <router-outlet></router-outlet>
      <p>----------</p>
    </div>
    


    Notice that <router-outlet></router-outlet> tag I have added. This is where our new component would get rendered. Now go to the app in the command line and execute -
    • ng serve -o
    You should see below the screen when you navigate to -

    • http://localhost:4200/newemployee

    You can see how our new component got rendered inside our root component. Root component generally has the layout design and based on users navigation we can render the custom component. We will continue to see more angular concepts in upcoming posts. So stay tuned!




    Related Links

    Sunday 18 November 2018

    Understanding angular application folder structure

    Background

    In the last post, we saw how to write a simple "Hello World!" application -
    In this post, I will try to explain the directory structure and importance of various files and folders in the angular project that we generated.


    NOTE: This is for angular 7. Folder structure and file names might be different in previous versions of angular.

     Understanding the angular application folder structure

     If you see the previous post the directory structure generated was as follows -


    We go try to see all the files and folders in the above picture and see what each does.

    e2e

    e2e stands for end to end. This consists of your end to end integration tests. these tests are run as if it is a real user testing but are actually simulated one. This includes opening a browser, navigating to the page, clicking on UI elements etc.


    This uses a package called protractor. You can find more details about protractor in https://www.protractortest.org/#/.

    node_modules

    If you are familiar with node environment this requires no special introduction. Angular app is essentially a node package. You can see there is a file called package.json in the root folder of your generated application. It defines dependencies of your node package. So that when you run "npm install" these dependencies are installed. These dependencies go under a folder called "node_modules" which is in the same folder as package.json. 


    src/app

    This folder is the source folder of your angular application. It contains all the source code that you write for your angular app to render. This will have files corresponding to your module, components, templates, css/saas files etc. The angular app will have at least one module and component.

    src/assets

     As the name suggests this folder should store all your static assets like images, icons etc.

    src/enviroments

    This folder contains the configuration for environments you define. By default, it would have 2 environments -
    1. environment.prod.ts : For production environment
    2. environment.ts  : For development environment

    favicon.ico

    This is the icon that gets showed when your browser loads your page.


    index.html

    This is the main HTML file that loads. You can see it has tag -
    • <app-root></app-root>
    This tag corresponds to the selector of bootstrap component(app.component.ts) that is defined in your root module(app.module.ts).


    main.ts

    This is our main type script file. Here we can bootstrap our module as -

    platformBrowserDynamic().bootstrapModule(AppModule)
      .catch(err => console.error(err));
     
    

    polyfills.ts

    This type script file contains scripts that are needed by angular since the javascript feature may not be available in the browser. So basically it fills the gap to provide the features of JavaScript that are needed by Angular application and the features supported by your current browser.

    For example, IE may not support a File or a blob object. In this file, you can add your custom definitions.

    style.css

    This file contains your common styles that are global to the application. It could be a css or a saas file depending on what you choose during creation of your angular application.

    karma.conf.js

    This file is used to store the setting of Karma. Karma is used for unit tests while protractor that we saw above is used for end to end tests. For details see https://karma-runner.github.io/latest/index.html

    NOTE: Karma is a great tool for unit testing, and Protractor is intended for end to end or integration testing. This means that small tests for the logic of your individual controllers, directives, and services should be run using Karma. Big tests in which you have a running instance of your entire application should be run using Protractor. Protractor is intended to run tests from a user's point of view - if your test could be written down as instructions for a human interacting with your application, it should be an end to end test written with Protractor.

    test.ts

    This file is required for doing the testing setup.  This file is required by karma.conf.js and loads recursively all the .spec and framework files.


    angular.json

    This is the main file from which angular configuration is loaded. If you see this file it will have reference to all files - mian.ts, indes.html etc. All configuration needed for your angular application to build and run resides here.


    NOTE: In previous versions of angular this file was called angular-cli.json.


    package.json

    As mentioned in node_modules section, package.json is a descriptor file for any node project. It defines project name, it's dependencies etc.

    tsconfig.json

    This has configurations related to your typescript compiler. Your typescript compiler will look at these settings and converts type script to javascript that the browser understands.

    tslint.json

    This file has the liniting configuration. Rules that developers must follow to maintain the codebase in a standard way.

    .gitignore

    This is a file that git understands and whatever you add inside this file will be ignored by git for version control.




    Related Links

    Angular Hello World example

    Background

    In some of the earlier post, we saw Angular JS which is the older version of angular. 

    Current LTS version of angular is angular 6 (at the time of this writing). We will however be using angular 7 which is the active angular release.  In this post I will show you how to write a simple angular Hello World app. In the subsequent posts we will try to understand all files in the angular app and their purpose, angular routing, data binding etc.


    Angular CLI

    For generating angular app and it's components we are going to use Angular CLI (command line interface). You can see the wiki here. You need to have npm (node package manager) installed for this. If not please refer to my earlier posts on NodeJS(Links in the related section at the bottom).

    To install Angular CLI execute following command -
    • npm install -g @angular/cli 
     NOTE: You may have to run it with sudo of you are seeing permission issues. Once installed you can verify the installation by typing

    • ng --version



     Once angular CLI is installed you are all set to create your 1st angular app.



    Angular Hello World example

    Now let's create a new angular app, to begin with. To create a new angular application execute following command -

    • ng new angulardemo
     It if of format
    • "ng new projectname"

     You will now be asked for choices like would you like to add routing to the application. Would you be using CSS, SASS etc? For now, select Yes for routing and CSS as an option. We will see this later. For our current demo, these are not really essential.




     Once done you can go into the project directory and run.
    • ng serve -o
     This should build your app and open it in your browser.




     This is what the default application looks like. Now it's time to make some changes of our own. To do that open your application in your favorite IDE. I prefer using Visual Studio code. If you ae using this you can just open your project by going into the project directory and running -
    • code .
    The directory structure looks like below -



     As you can see there are bunch of files here but not to worry. We will see each in time. In this post, we will see how we can make changes and deploy our own code.


    The entry point is a file called angular.json. This file has all the configuration information used for building and developing your angular app. Look at the following part-


              "options": {
                "outputPath": "dist/angulardemo",
                "index": "src/index.html",
                "main": "src/main.ts",
                "polyfills": "src/polyfills.ts",
                "tsConfig": "src/tsconfig.app.json",
                "assets": [
                  "src/favicon.ico",
                  "src/assets"
                ],
                "styles": [
                  "src/styles.css"
                ],
                "scripts": []
              }
    

    You can see the important files we would have to check. You can see the index file is "src/index.html", the corresponding type file is "src/main.ts". Similarly, the CSS file is "src/styles.css". There are other files but not to worry about it as of now. We will just worry about these files for now.

    Now let's go to our index.html and here you can see the following tag -
    • <app-root></app-root>
    Now let's try to understand what would get rendered in this tag.  As I mentioned before the main file in "main.html" and corresponding typescript file is "main.ts". If you go to main.ts you will see -

    import { AppModule } from './app/app.module';
    platformBrowserDynamic().bootstrapModule(AppModule)
      .catch(err => console.error(err));
    


    This basically instructs to bootstrap a module called AppModule which is located at './app/app.module'. So go to this file. And you will see the following content in it -


    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        AppRoutingModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    
    export class AppModule { }
    


    This is the main module of your Angular app. A module can have multiple components. An angular can have multiple modules as well. You can see in the above example it imports 2 modules BrowserModule, AppRoutingModule. You can see where it is imported from. The important part to see here is the bootstrap part because that is the component that actually gets rendered on loading an angular app. So lets go to ./app.component file.


    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    
    export class AppComponent {
      title = 'angulardemo';
    }
    


    Here you can see AppComponent is a component. Also, you can see it's selector is "app-root" which we saw in index.html. You can also see the HTML file and CSS file this component is using to render itself. So let's go its HTML file './app.component.html'. You can see this has some HTML code that got rendered when we ran "ng serve" command above.

    Time to make some changes. Remove this code completely and replace it with following code.


    <div class="hello-world">
      <h1>Hello World!</h1>
    </div>
    


    Notice we have added a class for the div called "hello-world". Let's add this class to our CSS file - './app.component.css'

     .hello-world {
        font-style: italic;
    }
    


    That's it. If you already have "ng serve -o" command running your changes should get reflected immediately in the browser. If you killed the command, run it again and you should see the changes reflecting in the browser.



    You can see in above picture that "Hello world!" comes in h1 tag and in italics()as our class defined it.





    Related Links

    Saturday 27 October 2018

    Keep learning, Keep sharing!

    A wise man once said -
     If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.


    I crossed 40k reputation on Stack Overflow(SO).  And that accounts to 2544 rank in the world!




    It has been almost 5 and a half years since added my 1st answer to the site. And today 1,130 answers, 144 questions and a people reach of ~21.4 million later here I am going back to where it all started. I still remember the 1st answer that I wrote - it was downvoted just because an admin read it wrong and when he realized it, he was the 1st person to upvote the answer and that's how the journey began. I am taking this opportunity to stress a very important point - Knowledge increases by sharing.



    I am sure every developer has relied on some SO answers for finding directions to get their issues resolved. The reason I am sharing this today is to stress the point that if it has helped you, it would probably help a hundred others around the globe. So make sure to upvote that answer. If the answer did not work out for you but it helped you in the correct direction go ahead and add it as a new answer or a comment. Innovation is not always in doing different things, it can be doing things differently. Never hold back anything thinking the answer or question might be silly. You already know the outcome if you don't, so why not give it a try and see how it goes. If it's stupid but it works, it isn't stupid - as simple as that. Worst case scenario - someone correct you which not only helps you understand it better but also everyone else who is in the same boat. I personally consider this the best scenario - You don't learn anything if you think you are always right!



    Personally other than technical learning aspect of it, this has helped me a lot in terms of interviews, communicating with fellow developers and expanding personal reach. I get this question a lot during the technical interview - "Why do you have so many questions answered as compared to the questions asked with just 5 years of experience?". What I have learned during the course of last 5 years is that the same question has many different angles and like I said before if you are facing a problem there would be many others facing the same issue. It could be different OS, different library version, different runtime, a different flavor of language etc. I have always tried to add more content to the answers based on the issue I have faced and today based on the shown stats there are around 21.4 million developers who were in the same boat. That's a win-win scenario!


    I will conclude this post by saying - "Keep learning, Keep sharing!". Good luck :)

    Sharing few more stats - Just for fun :)







    PS: If you need my help in getting traction to your question in terms of upvote or bounties feel free to reach out to me at - opensourceforgeeks@gmail.com.

    t> UA-39527780-1 back to top