Creating an Angular2 Image Gallery

In order to make this tutorial easier for beginners I’m going to start by creating the simplest possible gallery, from there I’m going to develop and add more functionalities to it, which will increasingly make the gallery more complex as we proceed. If you are already familiar and have some experience with angular2 this entire tutorial will be easy for you, but if you’re a beginner it’s really important that you understand every detail from one step before you move on to the next, with that in mind let’s get started!

The first step, of course, is to create an angular2 project, if you don’t know how to create one just follow the instructions from the Angular2 Quickstart.

Before we begin let’s add the bootstrap and jquery scripts to our project, we’re going to need them later, just copy/paste the following code to your index.html.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js" ></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" ></link>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" ></link>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" ></script>

Now we can start working on the gallery component, as I said before let’s focus on the basics first, for now all we need is a gallery that shows a list of thumbnails and a dialog with the selected image. This is how it should look like in code:

gallery.component.ts

import {Component, Input} from '@angular/core';
 
@Component({
  selector: 'gallery',
  template: `
	<div class="modal fade" id="selectedImageModal" >
	  <div class="modal-dialog" role="document">
	    <div class="modal-content">
	      <div class="modal-body">
	         <img *ngIf="selectedImage" src="{{selectedImage.url}}" >
	      </div>
	    </div>
	  </div>
	</div>
  	<ul id="thumbnailsList">
  	   <li *ngFor="let image of datasource" >
  	      <img src="{{image.url}}" class="tn"
  		  width="191" height="146"  
  		  data-toggle="modal" data-target="#selectedImageModal"
                  (click)=setSelectedImage(image)>
  	   </li>
  	</ul>
  `,
  styles: [`
  	ul { padding:0; width:780px; margin:20px auto}
  	li { display:inline;}
        .tn{ 
	   margin:2px 0px;
	   box-shadow:#999 1px 1px 3px 1px; 
	   cursor: pointer 
        }
  	.modal-content {
	    width: 670px !important;
	}
  `]
})
export class GalleryComponent { 
 
   @Input() datasource;
   selectedImage;
 
   setSelectedImage(image){
      this.selectedImage= image;	
   }
}

Look how simple the template is, we have just two elements: the selectedImageModal and the thumbnailsList. The first one is a Bootstrap dialog with the selected image and the second is the list of thumbnails.

In the GalleryComponent class we have a variable called datasource that provides everything we need to render the component, it is an array of objects containing all the data regarding each image (url, caption, title, etc), all we have to do is to iterate over this dasaset creating an img element for each object on the array, the result will be our thumbnails list.

A really important detail is that the variable datasource is decorated with @Input(), which means that it must be passed to our component as an attribute (I’m going to show how to do that in a moment), this will allow us to reuse the component to show different sets of images across the application.

We also have the selectedImage variable, as the name suggests this variable holds the object with the selected image properties. To select an image the user must click on its thumbnail, when the click occurs the method setCurrentImage will be called thanks to the (click)=setSelectedImage(image) we’ve put on the thumbnails, then a bootstrap dialog will pop up showing the full-sized selected image.

Lastly, I had to do some styling to make this component look like a gallery, one way to use CSS in an angular2 component is to just add the attribute styles to the @Component decorator like I did in this example.

Now we already have a basic gallery, let’s see how we can use it:

app.component.ts

import {Component } from '@angular/core';
 
@Component({
  selector: 'my-app',
  template: `
    <gallery [datasource]=images></gallery>
  `,
})
export class AppComponent { 
   images;
 
   constructor(){
      this.images = [
	{"url":"http://your_image1_url"},
	{"url":"http://your_image2_url"},
	{"url":"http://your_image3_url"},
	{"url":"http://your_image4_url"},
	{"url":"http://your_image5_url"},
	{"url":"http://your_image6_url"},
	{"url":"http://your_image7_url"},
	{"url":"http://your_image8_url"},
	{"url":"http://your_image9_url"},
	{"url":"http://your_image10_url"},
	{"url":"http://your_image11_url"},
	{"url":"http://your_image12_url"}
      ];
   }
}

The usage is very simple, the only thing we have to be concerned here is to pass a datasource to the gallery, in this class I have the images variable that will serve as a datasource, I’m passing it by adding the [datasource]=images to the gallery element on the template.

This is the result so far:

Angular2 Image Gallery - Thumbnails
Angular2 Image Gallery – Thumbnails
Angular2 Image Gallery – Selected Image
Angular2 Image Gallery – Selected Image

Adding the Title and Caption

As I just explained, we have to pass to the gallery component an array of objects containing all the data regarding the images, in our case the variable images from the app.component.ts is our datasource, let’s take a closer look at one of the objects that composes it:

{"url":"http://your_image1_url"}

Since the url is the only property we’ve used so far, it’s the only attribute in the object. To be able to show the title and caption we have to modify the datasource by adding these two properties to the objects, this is how it should look like after the modification:

{
  "url":"http://your_image1_url",
  "title":"Aliquam erat volutpat",
  "caption":"imperdiet imperdiet. Nullam ut ligula vitae arcu vulputate dictum ut quis elit."
}

Now we can use these new attributes on the gallery.component.ts, when a user clicks on the thumbnail we’re currently showing the selected image with this img element:

<img *ngIf="selectedImage" src="{{selectedImage.url}}" >

Let’s replace the img with a div that contains, besides the image, also the title and caption:

<div class="selectedImage" *ngIf="selectedImage">
   <img src="{{selectedImage.url}}" >
   <div class="caption">
      <p><strong>{{selectedImage.title}}</strong></p>
      <p>{{selectedImage.caption}}</p>
   </div>
</div>

And once again we have to add some styles to the component:

.selectedImage{ 
	width:640px;
	position:relative }
.caption{
	position:absolute;
        height:70px;
	width:100%;
	top:410;
	left:0;
	opacity:0.9;
	background-color:black;
	color:white;
	padding:5px;
	font-family:verdana;
	font-size:12px;
}
p {
   -webkit-margin-before: 5px !important;
   -webkit-margin-after: 5px !important;
}

This is the result:

Image Title and Caption
Image Title and Caption

Adding the Navigation Arrows

After running your application you should’ve noticed that when you select an image there’s no way to select another without closing the dialog first, we can make things much easier for the user by adding navigation arrows, for that to be possible we have to modify the template again by adding two new divs above the caption:

<div class="selectedImage" *ngIf="selectedImage">
   <img src="{{selectedImage.url}}" >
   <div class="arrow-back" (click)=navigate(false)>
      &lt;
   </div>
   <div class="arrow-forward" (click)=navigate(true)>
      &gt;
   </div>
   <div class="caption">
      <p><strong>{{selectedImage.title}}</strong></p>
      <p>{{selectedImage.caption}}</p>
   </div>
</div>

The new divs will serve as the navigation arrows, notice that they are calling the function navigate, that’s the function responsible for changing the selected image, let’s see how it works:

navigate(forward){
   var index = this.datasource.indexOf(this.selectedImage)+(forward ? 1: -1);
   if(index >= 0 && index < this.datasource.length){
      this.selectedImage = this.datasource[index];	
   }
}

The function receives a boolean as parameter, its value will be false if we click on back and true if we click on the forward arrow. To be able to change the selected image we first have to find out its index, we can easily do that by using indexOf, then we add/subtract 1 from this value and we already have a new index, now we can use this index to get the next/previous image from the datasource and assign it to the selectedImage variable.

Lastly, let’s take care of the styles:

.btn-back, .btn-forward{
	position:absolute;
	opacity:0.9;
	background-color:black;
	padding:10px;
	top:190;
	color:white;
	text-weight:bold;
	cursor:pointer;
}
 
.btn-forward{
	left:612;
}

This is the result:

Navigation Arrows
Navigation Arrows

Adding Keyboard Shortcuts

I’m not going to go into details about this because I’ve already written a post about keyboard shortcuts, you basically have to add the element host to your component:

host: {'(window:keydown)': 'hotkeys($event)'}

This allows us to call a function on the keydown event, in this case I’m calling the function hotkeys:

hotkeys(event){
   if(this.selectedImage){
      if (event.keyCode == 37){
         this.navigate(false);
      }else if(event.keyCode == 39){
         this.navigate(true);
      }
   }
}

In this function I’m just checking the keycode and taking actions accordingly, if the user presses the left arrow (keycode 37) I’m calling navigate(false) and if he presses the right arrow (keycode 38) I’m calling navigate(true).

That’s it guys! I’m going to leave it like that for now, if there are other functionalities you want to add please leave a comment, all suggestions are welcome!

Recommended for you

Angular 2 Tutorial: Adding HotKeys (Keyboard shortcuts) to a Component

Arguably hotkeys can substantially increase the usability of an application, the less the users have to touch the mouse the better will be their experience with the application.

Luckily for us there is a very easy way of defining hotkeys on angular2, which is by adding a listener to the host component, we can accomplish this by just adding the element host to the @Component decorator.

Let’s take a look at an example:

import {Component } from '@angular/core';
 
@Component({
  selector: 'hotkeys-app',
  host: {'(window:keydown)': 'hotkeys($event)'},
  template: `
  	<button (click)=showMessage()>Hotkey Test</button>
  `,
})
export class AppComponent { 
 
   hotkeys(event){
      if (event.keyCode == 65){
         this.showMessage();
      }
   }
 
   showMessage(){
      alert('Hotkey Test');
   }
}

As you can see I’ve used the element host to add a listener to the window:keydown event, it will call the function hotkeys(event) every time this event occurs, all we have to do now on this function is to determine which key was pressed and take actions accordingly.

As an example I’ve placed a button on the template, let’s suppose we want the action of this button, which is the showMessage() funtion, to execute when the user presses the letter 'a' on the keyboard. On the hotkeys function we have the event parameter containing the keyCode, we have to check this value to see which key was pressed, in this case I’m calling showMessage() when the keycode is 65 (which is code for the letter 'a').

It’s also very common to use combinations as hotkeys, like for example ctrl+a. To do that we just have to change our condition a little bit:

if (event.keyCode == 65 && event.ctrlKey){

The only diference is that besides checking the keyCode I’m also using the event.ctrlKey to check if the ctrl key is pressed.

That’s it guys! Just leave a comment if you have any doubts.

Recommended for you

Angular2 Forms Tutorial: Creating Custom Validators

Every now and then developers come across situations where existing validators are not suitable for their needs, if you are facing this situation your best option is to create a custom validatior, to illustrate how you can do that in angular2 I’m going to create a simple custom validator that will verify if the field value starts with a given string, it’ll be something like this:

<input type="text" startWith="ABC" ...>

In this example the attribute startWith is my validator, for this input to be valid it must contain a value that starts with ABC.

Now let’s see how it works, a custom validator is nothing more than a attribute directive that implements the Validator class, before we proceed to the details let’s take a look at the code:

import { Directive, Input } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl } from '@angular/forms';
 
@Directive({ 
  selector: '[startWith]',
  providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}] 
})
export class CustomValidatorDirective implements Validator{
  @Input('startWith') expr: string;
 
  validate(control: AbstractControl) {
    if(control.value && !control.value.startsWith(this.expr)){
        return {'startWith': control.value};
    }
    return null;
  }
}

Every validator has a validate() method, angular2 will call it every time the application needs to validate the field, note that it receives an AbstractControl as a parameter, which is the form control itself, this parameter will give us access to all of the field attributes, including the value (the only one we’re going to use in this tutorial). Also note that I’ve declared an @Input, this is how I’m getting the value "ABC" passed to the directive in the example above.

Now that we have the field value and the input we can implement the validate method and check if the field value contains the expression. If the field is valid the function returns null, otherwise it returns the validation error object.

Lastly, before you can use the validator, you have to register it in the app.modules.ts:

...
import { CustomValidatorDirective } from './customValidator.directive';
 
@NgModule({
  declarations: [ ... ,CustomValidatorDirective],
  ...
})
export class AppModule { }

Recommended for you

Angular2 Tutorial: Creating Attribute Directives

According to Angular2 documentation, directives are classes that can change the component behavior or/and appearance, which basically means they can add CSS classes and styles, register events and manipulate the component’s properties.

In this tutorial I’m going to show you how to create a very simple directive that will register the click event and add a CSS style to the component. I know we can do this without directives, but keep in mind that this is just an example I’m using to illustrate how directives work.

So let’s jump right into the code:

message.directive.ts

import { Directive, ElementRef, Input, Renderer } from '@angular/core';
 
@Directive({ selector: '[showMessage]' })
export class MessageDirective {
 
    constructor(el: ElementRef, renderer: Renderer) {
       renderer.setElementStyle(el.nativeElement, 'cursor', 'pointer');
       renderer.listen(el.nativeElement, 'click', function(){
         alert('Test');
       });
    }
}

As you can see, a directive is just a regular class decorated with @Directive, this decorator allows you to specify a selector, which is the name you’re going to use to call your directive later, in this example the selector is showMessage.

Now let’s take a look at the constructor, to make things easier angular2 is injecting two objects for us: ElementRef and Renderer. The first one allows us to access the DOM element, as the second is used to add/modify its properties.

There are two things I’m doing in this constructor, in the first line I’m using the Renderer’s setElementStyle function to change the cursor style to pointer, and in the second I’m just registering a callback function to the click event.

To make our directive work we also have to declare it in the app.module.ts:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }   from './app.component';
import { FormsModule }   from '@angular/forms';
import { MessageDirective } from './message.directive';
 
@NgModule({
  imports:      [ BrowserModule, FormsModule],
  declarations: [ AppComponent, MessageDirective],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

That’s it, easy right! Now we can use the directive by just adding its selector to the component as follows:

<p showMessage>Click Here</p>

If you run your application you’ll see that this p element looks like a link, when you click on it the message 'Test' pops up.

Recommended for you

JSF Tutorial: How to use ui:include and ui:fragment with Parameters

Most of developers are not as concerned about code organization in the front-end as they are in the back-end, it’s much easier to find duplicated code in a JSF page than it is in a Java class, making it a lot harder and time consuming for the developer to maintain the pages.

To solve that problem we have to treat blocks of JSF code as functions, let’s take a look at the code bellow as an example:

<h:form>
   <div class="form-group">
      <h:outputLabel styleClass="col-sm-2 control-label" value="First Name"/>
      <h:inputText styleClass="form-control col-sm-2" value="#{testMbean.name}"/>
   </div>
   <div class="form-group">
      <h:outputLabel styleClass="col-sm-2 control-label" value="Last Name"/>
      <h:inputText styleClass="form-control col-sm-2" value="#{testMbean.lastName}"/>
   </div>
   ...
</h:form>

Here we have a form with multiple fields that look exactly the same, the only difference is the label and the input value, if this form was a Java class we would certainly create a method receiving these two attributes, but as we are in a JSF page our best option is to create a ui:fragment containing a single field:

field.xhtml

<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
             xmlns:h="http://xmlns.jcp.org/jsf/html"
             xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
 
    <div class="form-group">
        <h:outputLabel styleClass="col-sm-2 control-label" value="#{label}"/>
        <h:inputText styleClass="form-control col-sm-2" value="#{value}"/>
    </div>
</ui:fragment>

Note that now I’m using the variables #{label} and #{value}, so every time I include this fragment I have to pass these parameters.

When using the fragment our form looks like this:

<h:form>
   <ui:include src="field.xhtml">
      <ui:param name="label" value="Name"/>
      <ui:param name="value" value="#{testMbean.name}"/>
   </ui:include>
   <ui:include src="field.xhtml">
      <ui:param name="label" value="Last Name"/>
      <ui:param name="value" value="#{testMbean.lastName}"/>
   </ui:include>
   ...
</h:form>

It doesn’t seen much of an advantage to use fragments, but imagine if you had to add a style class to your input, it would be much easier to add it only in the fragment instead of having to find every input on your project and add the class to each one of them one by one.

Angular2 Forms Tutorial: Validating Required Fields

Angular2 Form Validation
Angular2 Form Validation

In this tutorial I’ll give you a simple example of how to validate a form with angular2. As you can see in the image, the example consists of a form with two required fields, the form can only be submitted if both fields are valid.

I’m going to use bootstrap for styling, if you want your form to look like the image above you just have to add the follwoing scripts to your index.html:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" >
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" ></script>

Now let’s take a look at our component:

import {Component} from '@angular/core';
 
@Component({
  selector: 'form-validation-example',
  template: `
     <form (ngSubmit)="submit()" >
	<div class="form-group has-feedback" 
	     [ngClass]="{ 'has-error' : !firstNameControl.valid && submitAttempt }">
           <label class="control-label" >First Name</label>
           <input type="text" class="form-control"
	      name="firstName" [(ngModel)]="firstName" #firstNameControl="ngModel" required>
           <span *ngIf="!firstNameControl.valid && submitAttempt"
	      class="glyphicon glyphicon-remove form-control-feedback" ></span>
	</div>
	<div class="form-group has-feedback" 
	     [ngClass]="{ 'has-error' : !emailControl.valid && submitAttempt }">
	   <label class="control-label">E-mail</label>
	   <input type="text" class="form-control"
              name="email" [(ngModel)]="email" #emailControl="ngModel" required>
           <span *ngIf="!emailControl.valid && submitAttempt"
	      class="glyphicon glyphicon-remove form-control-feedback" ></span>
	</div>
	<button type="submit" class="btn btn-default" (click)=initSubmit()>Submit</button>
     </form>
  `
})
export class FormComponent {
      submitAttempt = false;
 
      initSubmit(){
	  this.submitAttempt = true;
      }
 
      submit(){
 	  console.log('success!');
      }
}

This is just a regular form, what makes the fields required is the required attribute at the end of each input, just using this attribute will already be enough to prevent the form from submitting, but it won’t change the field style as shown in the demo at the beginning.

To be able to change the style of the input we first have to know if the field is valid or not, an easy way to achieve this is to declare a template reference variable for each field, if you take a look at the code you’ll see the attribute #firstNameControl="ngModel" on the first input and #emailControl="ngModel" on the second, that’s how template reference variables are declared. Now I can use the names firstNameControl and emailControl to access properties of my inputs on other parts of my template, but the only one that matters to us is the property valid.

We also need a way to determine if the submit button was clicked or not, that’s why I’ve created the variable submitAttempt, it’s false by default but it’ll be set to true once the button is clicked.

By using the template reference variables and the submitAttempt variable we can now write the condition that changes the styles, which is !firstNameControl.valid && submitAttempt for the first field and !emailControl.valid && submitAttempt for the second. These conditions are used to add the bootstrap class has-error on each form-group and also to render the icon at the end of the input.

Lastly we have the submit() function which will just print the string ‘success!’ on the console, this function will only be called if both fields are valid.

Recommended for you

Interacting with Child Components in Angular2

There are lots of situations where we have to divide a component into several sub-components, resulting in a parent with N child components that somehow have to interact with the parent, like for example a menu component like this:

<menu-component>
   <menu-item [label]="'Item 1'"></menu-item>
   <menu-item [label]="'Item 2'"></menu-item>
   <menu-item [label]="'Item 3'"></menu-item>
   <menu-item [label]="'Item 4'"></menu-item>
   <menu-item [label]="'Item 5'"></menu-item>
</menu-component>

In this case the menu-component class must have access to every menu-item in order to completely render the component, that’s what I’m going to show you in this tutorial, but before we begin keep in mind that this is not a real menu component, it’s just an example I’m using to demonstrate how the components can interact.

Now let’s see how it works, here are the sources of both components:

MenuItemComponent

@Component({
  selector: 'menu-item',
  template: ``,
})
export class MenuItemComponent {
  @Input() label;
 
  constructor(menu: MenuComponent) {
    menu.items.push(this);
  }
}

MenuComponent

@Component({
  selector: 'menu-component',
  template: `
      <ul>
         <li *ngFor="let item of items">{{item.label}}</li>
      </ul>
  `
})
export class MenuComponent { 
  items: MenuItemComponent[] = [];
}

The parent iterates over a list of menu items in the template in order to display the label of each one of them in a li element, but as you can see the items array is empty and I’m not adding anything to it in this class, now if you take a look at the MenuItemComponent‘s constructor you’ll see that Angular2 makes things very easy for us by injecting the parent component, allowing each item to access the array in the parent and add itself to it.

That’s pretty much it guys, this was a very short tutorial but I hope it was helpful for you, just leave a comment if you have any doubts.

Recommended for you

Creating an Angular2 Datatable from Scratch PART 2: Filtering the Data

Continuing from where we stopped at Part 1, today we’re going to add the filter functionality to the table, but before we start let’s do some styling. I’m going to use Bootstrap, but if you don’t want you don’t have to, feel free to style your component as you like. But if you decide to use Bootstrap as well you’ll have to add these scripts to your index.html:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" >
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" ></script>

Now I’m going to add the class table to the table element in the DatatableComponent, this class will make the grid look like this:

Table With Bootstrap Style
Table With Bootstrap Style

It looks so much better already! Now let’s get started with the filter, most of the modifications will be made on the datatable.component.ts file, here’s the component after the changes:

import {Http, Response} from '@angular/http';
import {Injectable, Component, Input} from '@angular/core';
import {ColumnComponent} from './column.component';
 
@Component({
  selector: 'datatable',
  template: `
      <input type="text" class="form-control" *ngIf=enableFilter [(ngModel)]=query 
         (keyup)=filter() placeholder="Filter" />
      <table class="table">
        <thead>
          <tr>
            <th *ngFor="let column of columns">{{column.header}}</th>
          </tr>
        </thead>
        <tbody *ngFor="let row of getData()">
	  <tr>
	    <td *ngFor="let column of columns">{{row[column.value]}}</td>
	  </tr>
        </tbody>
      </table>
  `
})
export class DatatableComponent { 
 
  @Input() dataset;
  @Input() enableFilter = false;
  columns: ColumnComponent[] = [];
  query = "";
  filteredList;
 
  addColumn(column){
    this.columns.push(column);
  }
 
  getData(){
    if(this.query !== ""){
      return this.filteredList;
    }else{
      return this.dataset;  
    }
  }
 
  filter(){
    this.filteredList = this.dataset.filter(function(el){
      var result="";
        for(var key in el){
          result+= el[key];
        }
        return result.toLowerCase().indexOf(this.query.toLowerCase()) > -1;
    }.bind(this));
  }
}

Let’s start by talking about the new attributes:

enableFilter: This is an input that indicates weather the filter is going to be enabled or not, it’s false by default.
query: Variable that stores the filter typed by the user.
filteredList: This variable is going to store the new dataset after the filtering, it’s necessary to use a different array in order to preserve the original data.

Now the new functions:

filter(): Function responsible for filtering the data when the user types something on the input, it’ll filter the data from the dataset variable and assign the result to the filteredList.
getData(): Our table will work simultaneously with two arrays, the dataset and filteredList, this function is responsible for telling which one will be used at any given moment, if the table has filtered data to show it’ll use the filteredList otherwise it’ll use the dataset.

Besides the new attributes and functions I’ve also modified the template a little bit, in the tbody I’ve change the ngFor from let row of dataset to let row of getData(), and as you can see there is an input above the table where the user can type, it’ll call the filter() function on the keyup event and it’ll only be visible when the enableFilter is true (For this input to work we also have to import the FormsModule on the app.module.js).

Now your datatable can be used like this:

<datatable [dataset]=cities [enableFilter]=true >
      <column [value]="'id'" [header]="'Id'"></column>
      <column [value]="'city'" [header]="'City'"></column>
      <column [value]="'country'" [header]="'Country'"></column>
 </datatable>

The only thing that has changed is that now we have the option enableFilter that will render an input above the table when set to true.

Recommended for you

Creating an Angular2 Datatable from Scratch

Some time ago I’ve posted a tutorial on how to create a datatable with ag-grid, it didn’t take long before people start complaining that ag-grid wasn’t working the way I described in the tutorial, that’s because angular2 is changing rapidly rendering the component and/or the tutorial obsolete.

Today I’m going to show you again how to create a datatable, but this time I’m going to do it without ag-grid or any other third-party component, this is how our component will look like after we’re done:

<datatable [dataset]=cities>
    <column [value]="'id'" [header]="'Id'"></column>
    <column [value]="'city'" [header]="'City'"></column>
    <column [value]="'country'" [header]="'Country'"></column>
</datatable>

That’s the simplest datatable structure I could come up with, as you can see we’re going to create two components: datatable and column.

Let’s take a look at the column component first:

import {Component, Input} from '@angular/core';
import {DatatableComponent} from './datatable.component';
 
@Component({
  selector: 'column',
  template: ``,
 
})
export class ColumnComponent {
	@Input() value;
	@Input() header;
 
	constructor(table: DatatableComponent) {
    	   table.addColumn(this)
  	}
}

This component has two attributes as inputs: value and header.

Value: This is the name of the attribute from your JSON dataset that will be displayed on this column (I’m going to talk about the dataset in a minute).
Header: As the name suggests, this is the column header text.

Besides these two attributes, there’s also the constructor, which very conveniently injects the DatatableComponent, allowing us to add this column to an array from the parent component. To fully understand why I’m doing this we have to take a look at the DatatableComponent:

import {Http, Response} from '@angular/http';
import {Injectable, Component, Input} from '@angular/core';
import {ColumnComponent} from './column.component';
 
@Component({
  selector: 'datatable',
  template: `<table>
               <thead>
                 <tr>
                   <th *ngFor="let column of columns">{{column.header}}</th>
                 </tr>
               </thead>
	       <tbody *ngFor="let row of dataset">
	  	 <tr>
	  	   <td *ngFor="let column of columns">{{row[column.value]}}</td>
	         </tr>
	       </tbody>
  	     </table>
  `
})
export class DatatableComponent { 
 
  @Input() dataset;
  columns: ColumnComponent[] = [];
 
  addColumn(column){
    this.columns.push(column);
  }
}

In this component we have the attribute dataset as an input (which will receive the JSON dataset) and the array of columns I just mentioned, each column will add itself to this array as we’ve seen on the ColumnComponent‘s constructor. In the template I’m iterating over both the dataset (rows) and the columns to create a regular HTML table.

After creating these two components we can use the datatable as I showed in the beginning, here is the app.component.ts:

import {Http, Response} from '@angular/http';
import {Injectable, Component } from '@angular/core';
 
@Component({
  selector: 'my-app',
  template: `<datatable [dataset]=cities>
                  <column [value]="'id'" [header]="'Id'"></column>
                  <column [value]="'city'" [header]="'City'"></column>
                  <column [value]="'country'" [header]="'Country'"></column>
             </datatable>
             `,
 
})
export class AppComponent { 
    cities;
 
    constructor(private http:Http) {
        this.http.get('data/cities.json')
                .subscribe(res => this.cities = res.json());
    }
}

Note that in the constructor I’m loading my dataset from the file cities.json, for more datails about that click here.

We’re almost done, the last thing we have to do is to declare our components in the app.module.ts:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule }      from '@angular/http';
import { AppComponent }   from './app.component';
import {DatatableComponent} from './datatable.component';
import {ColumnComponent} from './column.component';
 
@NgModule({
  imports:      [ BrowserModule, HttpModule ],
  declarations: [ AppComponent,DatatableComponent, ColumnComponent],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

That’s it for now guys! Click here to see the part 2 of this tutorial where I’m showing how to add the filter functionality, if you need other specific features please let me know in the comments, any suggestions are welcome!

Recommended for you

Adding the Multiselect feature to an Angular2 Autocomplete

Angular2 Multi Selection Autocomplete
Angular2 Multi Selection Autocomplete

After I wrote the tutorial on how to create an angular2 autocomplete, lots of people have been asking me to add the multiselect feature to it, that’s the reason why I decided to write this one. I’m going to continue from where I stopped, so make sure you followed and understood every step from the previous tutorial before you proceed.

The first thing we have to do is to create a variable called selected, it’s just an array we’re going to use to store all the items selected by the user.

public selected = [];

Now let’s change a little bit the select() function, instead of assigning the item to the this.query variable we’re going to add it to the selected array and clean the this.query. This is the modification that will make the multiple selection possible. Here’s the code after the modification:

select(item){
    this.selected.push(item);
    this.query = '';
    this.filteredList = [];
}

We also need a way to remove items from the array, I’m going to create a function called remove (obviously), here’s the code:

remove(item){
    this.selected.splice(this.selected.indexOf(item),1);
}

This is a really straightforward function, it just receives an item and uses the splice() function to remove it from the array.

The template will also suffer some changes:

<div class="container" >
    <div class="input-field col s12">
      <input id="country" type="text" class="validate filter-input" [(ngModel)]=query (keyup)=filter()>
      <label for="country">Country</label>
    </div>
    <div class="suggestions" *ngIf="filteredList.length > 0">
        <ul *ngFor="#item of filteredList" >
            <li >
                <a (click)="select(item)">{{item}}</a>
            </li>
        </ul>
    </div>
    <div *ngFor="#item of selected">
        <div class="selected" >
            <span>{{item}}</span>
            <a (click)="remove(item)">x</a>
        </div>
    </div>
</div>

Notice that I’ve added another div bellow the suggestions list, that’s where the selected items will be displayed, also notice that each item will an ‘x’ that will call the remove function when clicked.

Lastly we have to do the styling, in this example I’ve used the following css to adjust how the selected items are displayed, but feel free to do as you like.

.selected{
	border:solid #4CAF50 1px;
	float:left; 
	margin:2px;
	padding:2px 15px;
}
 
.selected a{
	cursor:pointer;
	font-weight:bold;
}

That’s it guys! With just a few changes we can now select multiple items with our autocomplete, just leave a comment if you have any doubts.

Recommended for you