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

    t> UA-39527780-1 back to top