Posts on this Category



Angular2: How to Sort a JSON Dataset by Field

To be able to sort an array we don’t need anything specific from angular2, it can be accomplished just by using regular javascript, more specifically, we have to use the function sort() from the Array object, let’s see an example:

someArray.sort(function(a, b){
    if ( a.someField < b.someField )
        return -1;
    if ( a.someField > b.someField )
        return 1;
    return 0;
});

The sort function receives a comparator as a callback, which will compare each element of the array with the others (two at a time) in order to sort the dataset, the arguments a and b are the two objects being compared, we can implement this method and compare the objects as we want, but it must always return 1 if a is greater than b, -1 if b is greater than a or 0 if they are equal.

This is how it looks in an angular2 class:

export class AppComponent { 
     names = [{"id": 1,"first_name": "Jason","last_name": "Martin"}, 
     {"id": 2,"first_name": "Douglas","last_name": "Holmes"}, 
     {"id": 3,"first_name": "Randy","last_name": "Woods"}, 
     {"id": 4,"first_name": "Thomas","last_name": "Castillo"}, 
     {"id": 5,"first_name": "Ryan","last_name": "Butler"}, 
     {"id": 6,"first_name": "Jose","last_name": "Turner"}, 
     {"id": 7,"first_name": "Carl","last_name": "Taylor"}, 
     {"id": 8,"first_name": "Brandon","last_name": "Mendoza"}, 
     {"id": 9,"first_name": "Willie","last_name": "Ross"}, 
     {"id": 10,"first_name": "Howard","last_name": "Montgomery"}]
 
     ngOnInit(){
	this.names.sort( function(name1, name2) {
	    if ( name1.first_name < name2.first_name ){
	    	return -1;
	    }else if( name1.first_name > name2.first_name ){
	        return 1;
	    }else{
	    	return 0;	
	    }
	});
     }
}

In this example I’m using the sort function on the ngOnInit() to order my array of names by the field first_name, but I could be sorting by any other field if I wanted, or even more than one field.

Alternatively, we can use angular2 pipes to sort datasets, this is how we can implement one:

@Pipe({name: "sortBy"})
export class SortPipe {
  transform(array: Array<string>, args: string): Array<string> {
    array.sort((a: any, b: any) => {
	    if ( a[args] < b[args] ){
	    	return -1;
	    }else if( a[args] > b[args] ){
	        return 1;
	    }else{
	    	return 0;	
	    }
    });
    return array;
  }
}

One of the differences is that by doing this way we can sort an array directly on the *ngFor:

*ngFor="let name of names | sortBy : 'first_name'"

I personally think that this is a much better option than the previews one, by using a pipe you can sort any array you want without worrying about implementing the comparator function every time.

For more details about pipes click here.

Angular2 error: Error in ./AppComponent class AppComponent_Host – inline template:0:0 caused by: No provider for Http!

If you’re seeing this error when you run your application it’s probably because you’re trying to use http.get without importing the HttpModule.

This is what the error looks like on the browser console:

core.umd.js:5995 EXCEPTION: Error in ./AppComponent class AppComponent_Host - inline template:0:0 caused by: No provider for Http!ErrorHandler.handleError @ core.umd.js:5995(anonymous function) @ core.umd.js:9394ZoneDelegate.invoke @ zone.js:332onInvoke @ core.umd.js:8772ZoneDelegate.invoke @ zone.js:331Zone.run @ zone.js:225(anonymous function) @ zone.js:591ZoneDelegate.invokeTask @ zone.js:365onInvokeTask @ core.umd.js:8763ZoneDelegate.invokeTask @ zone.js:364Zone.runTask @ zone.js:265drainMicroTaskQueue @ zone.js:497ZoneTask.invoke @ zone.js:437
core.umd.js:5997 ORIGINAL EXCEPTION: No provider for Http!ErrorHandler.handleError @ core.umd.js:5997(anonymous function) @ core.umd.js:9394ZoneDelegate.invoke @ zone.js:332onInvoke @ core.umd.js:8772ZoneDelegate.invoke @ zone.js:331Zone.run @ zone.js:225(anonymous function) @ zone.js:591ZoneDelegate.invokeTask @ zone.js:365onInvokeTask @ core.umd.js:8763ZoneDelegate.invokeTask @ zone.js:364Zone.runTask @ zone.js:265drainMicroTaskQueue @ zone.js:497ZoneTask.invoke @ zone.js:437
core.umd.js:6000 ORIGINAL STACKTRACE:ErrorHandler.handleError @ core.umd.js:6000(anonymous function) @ core.umd.js:9394ZoneDelegate.invoke @ zone.js:332onInvoke @ core.umd.js:8772ZoneDelegate.invoke @ zone.js:331Zone.run @ zone.js:225(anonymous function) @ zone.js:591ZoneDelegate.invokeTask @ zone.js:365onInvokeTask @ core.umd.js:8763ZoneDelegate.invokeTask @ zone.js:364Zone.runTask @ zone.js:265drainMicroTaskQueue @ zone.js:497ZoneTask.invoke @ zone.js:437
core.umd.js:6001 Error: No provider for Http!
    at NoProviderError.Error (native)
    at NoProviderError.BaseError [as constructor] (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:1456:38)
    at NoProviderError.AbstractProviderError [as constructor] (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:1940:20)
    at new NoProviderError (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:1971:20)
    at ReflectiveInjector_._throwOrNull (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:3573:23)
    at ReflectiveInjector_._getByKeyDefault (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:3601:29)
    at ReflectiveInjector_._getByKey (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:3564:29)
    at ReflectiveInjector_.get (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:3373:25)
    at NgModuleInjector.get (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9756:56)
    at DebugAppView._View_AppComponent_Host0.createInternal (AppComponent_Host.ngfactory.js:16:70)ErrorHandler.handleError @ core.umd.js:6001(anonymous function) @ core.umd.js:9394ZoneDelegate.invoke @ zone.js:332onInvoke @ core.umd.js:8772ZoneDelegate.invoke @ zone.js:331Zone.run @ zone.js:225(anonymous function) @ zone.js:591ZoneDelegate.invokeTask @ zone.js:365onInvokeTask @ core.umd.js:8763ZoneDelegate.invokeTask @ zone.js:364Zone.runTask @ zone.js:265drainMicroTaskQueue @ zone.js:497ZoneTask.invoke @ zone.js:437
core.umd.js:6004 ERROR CONTEXT:ErrorHandler.handleError @ core.umd.js:6004(anonymous function) @ core.umd.js:9394ZoneDelegate.invoke @ zone.js:332onInvoke @ core.umd.js:8772ZoneDelegate.invoke @ zone.js:331Zone.run @ zone.js:225(anonymous function) @ zone.js:591ZoneDelegate.invokeTask @ zone.js:365onInvokeTask @ core.umd.js:8763ZoneDelegate.invokeTask @ zone.js:364Zone.runTask @ zone.js:265drainMicroTaskQueue @ zone.js:497ZoneTask.invoke @ zone.js:437
core.umd.js:6005 DebugContext {_view: _View_AppComponent_Host0, _nodeIndex: 0, _tplRow: 0, _tplCol: 0}ErrorHandler.handleError @ core.umd.js:6005(anonymous function) @ core.umd.js:9394ZoneDelegate.invoke @ zone.js:332onInvoke @ core.umd.js:8772ZoneDelegate.invoke @ zone.js:331Zone.run @ zone.js:225(anonymous function) @ zone.js:591ZoneDelegate.invokeTask @ zone.js:365onInvokeTask @ core.umd.js:8763ZoneDelegate.invokeTask @ zone.js:364Zone.runTask @ zone.js:265drainMicroTaskQueue @ zone.js:497ZoneTask.invoke @ zone.js:437
zone.js:484 Unhandled Promise rejection: Error in ./AppComponent class AppComponent_Host - inline template:0:0 caused by: No provider for Http! ; Zone: <root> ; Task: Promise.then ; Value: ViewWrappedError {_nativeError: Error: Error in ./AppComponent class AppComponent_Host - inline template:0:0 caused by: No provider …, originalError: NoProviderError, context: DebugContext} Error: No provider for Http!
    at NoProviderError.Error (native)
    at NoProviderError.BaseError [as constructor] (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:1456:38)
    at NoProviderError.AbstractProviderError [as constructor] (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:1940:20)
    at new NoProviderError (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:1971:20)
    at ReflectiveInjector_._throwOrNull (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:3573:23)
    at ReflectiveInjector_._getByKeyDefault (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:3601:29)
    at ReflectiveInjector_._getByKey (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:3564:29)
    at ReflectiveInjector_.get (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:3373:25)
    at NgModuleInjector.get (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9756:56)
    at DebugAppView._View_AppComponent_Host0.createInternal (AppComponent_Host.ngfactory.js:16:70)consoleError @ zone.js:484_loop_1 @ zone.js:511drainMicroTaskQueue @ zone.js:515ZoneTask.invoke @ zone.js:437
zone.js:486 Error: Uncaught (in promise): Error: Error in ./AppComponent class AppComponent_Host - inline template:0:0 caused by: No provider for Http!()

The solution is simple, just open your app.module.ts and add the HttpModule to the imports:

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

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 { }

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.

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.

Angular2 Error: Cannot assign to a reference or variable! ; Zone: <root> ; Task: Promise.then ; Value: Error: Cannot assign to a reference or variable!

This error occurs when you try to define a template reference variable with the same name of an existing variable, like for example in this case:

@Component({
  selector: 'example',
  template: `
        <label for="name">Name</label>
        <input type="text" [(ngModel)]=name #name="ngModel" >
  `
})
export class AppComponent {
	name;
}

As you can see, there’s the template reference variable #name on the input and there’s also a variable called name on my class, this will cause the following error when you try to run the application:

zone.js:355 Unhandled Promise rejection: Cannot assign to a reference or variable! ; Zone: <root> ; Task: Promise.then ; Value: Error: Cannot assign to a reference or variable!() Error: Cannot assign to a reference or variable!
    at _AstToIrVisitor.visitPropertyWrite (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:11686:25)
    at PropertyWrite.visit (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:3156:26)
    at ASTWithSource.visit (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:3342:27)
    at convertCdStatementToIr (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:11483:30)
    at CompileEventListener.addAction (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:11911:29)
    at eval (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:11984:20)
    at Array.forEach (native)
    at collectEventListeners (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:11981:18)
    at ViewBinderVisitor.visitElement (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:12319:11)
    at ElementAst.visit (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:349:26)consoleError @ zone.js:355_loop_1 @ zone.js:382drainMicroTaskQueue @ zone.js:386ZoneTask.invoke @ zone.js:308
zone.js:357 Error: Uncaught (in promise): Error: Cannot assign to a reference or variable!()

The solution for this problem is very simple and obvious, the only thing you have to do is change the name of one of your variables.

Angular2 Error: Can’t bind to ‘ngModel’ since it isn’t a known property of ‘input’.

Lots of people are having this problem since Angular2 introduced NgModule, this error occurs when you try to use something from an specific module without importing it, this is how the error looks on the console:

zone.js:355 Unhandled Promise rejection: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'. ("
        <input type="text" class="form-control" id="name"
               required
               [ERROR ->][(ngModel)]=name name="name" >
        <div [hidden]="name.valid || name.pristine" 
             clas"): FormComponent@4:15 ; Zone: <root> ; Task: Promise.then ; Value: Error: Template parse errors:() Error: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'. ("
        <input type="text" class="form-control" id="name"
               required
               [ERROR ->][(ngModel)]=name name="name" >
        <div [hidden]="name.valid || name.pristine" 
             clas"): FormComponent@4:15
    at TemplateParser.parse (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:8530:21)
    at RuntimeCompiler._compileTemplate (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:16905:53)
    at eval (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:16828:85)
    at Set.forEach (native)
    at compile (http://localhost:3000/node_modules/@angular/compiler/bundles/compiler.umd.js:16828:49)
    at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:203:28)
    at Zone.run (http://localhost:3000/node_modules/zone.js/dist/zone.js:96:43)
    at http://localhost:3000/node_modules/zone.js/dist/zone.js:462:57
    at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:236:37)
    at Zone.runTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:136:47)consoleError @ zone.js:355_loop_1 @ zone.js:382drainMicroTaskQueue @ zone.js:386ZoneTask.invoke @ zone.js:308
zone.js:357 Error: Uncaught (in promise): Error: Template parse errors:()

All you have to do to fix this is to import the FormsModule on your app.module.ts:

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

Tutorial: How to redirect in Angular2

In this tutorial I’m going to give you a very simple example of how to navigate between components on an Angular2 application, but before we begin there are some configurations we have to do.

We’re going to use 2 components in this example: Component1 and Component2, to be able to redirect and navigate from one to the other we’re going to use the RouterModule, and for that module to work we have to create a file called app.routing.ts:

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Component1 } from './component1.component';
import { Component2 } from './component2.component';
 
const appRoutes: Routes = [
  { path: 'component1', component: Component1 },
  { path: 'component2', component: Component2 }
];
 
export const appRoutingProviders: any[] = [];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);

This is the file where we can define the routes, it allows us to specify a path for each of our components, as you can see in the code I’ve defined the paths /component1 and /component2 which will allow me to redirect to both my components.

Next we have to import the routing configuration on the app.module.ts as follows:

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

Perfect! We’re done with the configurations, now you can redirect by passing the path to the routerLink attribute of a regular link:

<a routerLink="/component1" >Component 1</a>
<a routerLink="/component2" >Component 2</a>

This will have the same effect as typing http://localhost:3000/component1 on the browser.

Angular2 Error: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.

This is a very common error for Angular2 beginners, if you are reading this it’s probably because you’re using the RouterModule module for the first time, you’ve done everything right but when you run your application you see something like this on your firebug:

core.umd.js:3462 EXCEPTION: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.ErrorHandler.handleError @ core.umd.js:3462(anonymous function) @ core.umd.js:6860ZoneDelegate.invoke @ zone.js:192onInvoke @ core.umd.js:6242ZoneDelegate.invoke @ zone.js:191Zone.run @ zone.js:85(anonymous function) @ zone.js:451ZoneDelegate.invokeTask @ zone.js:225onInvokeTask @ core.umd.js:6233ZoneDelegate.invokeTask @ zone.js:224Zone.runTask @ zone.js:125drainMicroTaskQueue @ zone.js:357ZoneTask.invoke @ zone.js:297
core.umd.js:3467 ORIGINAL STACKTRACE:ErrorHandler.handleError @ core.umd.js:3467(anonymous function) @ core.umd.js:6860ZoneDelegate.invoke @ zone.js:192onInvoke @ core.umd.js:6242ZoneDelegate.invoke @ zone.js:191Zone.run @ zone.js:85(anonymous function) @ zone.js:451ZoneDelegate.invokeTask @ zone.js:225onInvokeTask @ core.umd.js:6233ZoneDelegate.invokeTask @ zone.js:224Zone.runTask @ zone.js:125drainMicroTaskQueue @ zone.js:357ZoneTask.invoke @ zone.js:297
core.umd.js:3468 Error: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.
    at new PathLocationStrategy (common.umd.js:669)
    at provideLocationStrategy (router.umd.js:3602)
    at NgModuleInjector.get (AppModule.ngfactory.js:125)
    at NgModuleInjector.get (AppModule.ngfactory.js:130)
    at NgModuleInjector.get (AppModule.ngfactory.js:167)
    at NgModuleInjector.get (AppModule.ngfactory.js:177)
    at NgModuleInjector.AppModuleInjector.getInternal (AppModule.ngfactory.js:235)
    at NgModuleInjector.get (core.umd.js:7221)
    at ApplicationRef_._loadComponent (core.umd.js:7070)
    at ApplicationRef_.bootstrap (core.umd.js:7058)ErrorHandler.handleError @ core.umd.js:3468(anonymous function) @ core.umd.js:6860ZoneDelegate.invoke @ zone.js:192onInvoke @ core.umd.js:6242ZoneDelegate.invoke @ zone.js:191Zone.run @ zone.js:85(anonymous function) @ zone.js:451ZoneDelegate.invokeTask @ zone.js:225onInvokeTask @ core.umd.js:6233ZoneDelegate.invokeTask @ zone.js:224Zone.runTask @ zone.js:125drainMicroTaskQueue @ zone.js:357ZoneTask.invoke @ zone.js:297
zone.js:344 Unhandled Promise rejection: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document. ; Zone: <root> ; Task: Promise.then ; Value: Error: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.() Error: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.
    at new PathLocationStrategy (http://localhost:3000/node_modules/@angular/common/bundles/common.umd.js:669:23)
    at provideLocationStrategy (http://localhost:3000/node_modules/@angular/router/bundles/router.umd.js:3602:13)
    at NgModuleInjector.get (AppModule.ngfactory.js:125:77)
    at NgModuleInjector.get (AppModule.ngfactory.js:130:84)
    at NgModuleInjector.get (AppModule.ngfactory.js:167:151)
    at NgModuleInjector.get (AppModule.ngfactory.js:177:132)
    at NgModuleInjector.AppModuleInjector.getInternal (AppModule.ngfactory.js:235:66)
    at NgModuleInjector.get (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:7221:31)
    at ApplicationRef_._loadComponent (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:7070:44)
    at ApplicationRef_.bootstrap (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:7058:18)
zone.js:346 Error: Uncaught (in promise): Error: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.()

Lucky for you this problem is very easy to solve, you just have to go to your index.html and add the following line on the head:

<head>
  <base href="/">
  ...
</head>

There, problem solved!!