Search This Blog

Showing posts with label event binding. Show all posts
Showing posts with label event binding. Show all posts

Sunday, November 27, 2016

Bootstrap and Two-way binding with Angular2

In my previous post, we had examined event and property binding in Angular 2, along with setting up angular from scratch. In this post, we will add bootstrap 4 to our Angular2 environment, and then test a component to see some of the capabilities of the library.  We will also examine two way binding using the bootstrap components..

Creating a new project

Since we already installed angular-cli in the previous blog, lets create a new project called ng2-2 using "ng new" command. Let us also cd into the newly created project directory..


ng new ng2-2
cd ng2-2

This creates the new project.

Installing bootstrap

First step is to install bootstrap. We will install angular2 compliant bootstrap version called ng2-bootstrap. ng2-bootstrap utilizes the new Angular2 concepts to provide a Typescript based bootstrap library. Importantly it does not directly access the DOM.

This step requires the following commands to be run from within the ng2 folder on the command line.. Please note that we are deploying an alpha version of the bootstrap 4 library. Needless to say, it will have to be updated with the latest versions as they are released.


npm install --save bootstrap@4.0.0-alpha.5
npm install --save @ng-bootstrap/ng-bootstrap

Results will be similar to screen below


Making ng2-bootstrap available to the project

To make the newly added ng2-bootstrap library available to the entire project, we need to add it to the app.module.ts file.. We add the following the two lines to our file


import {NgbModule} from '@ng-bootstrap/ng-bootstrap';

imports: [
    NgbModule.forRoot(), ...
  ],

The following content shows these two lines added to my app.module.ts file

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
import { AppComponent } from './app.component';
import { LikesComponent } from './likes/likes.component';

@NgModule({
  declarations: [
    AppComponent,
    LikesComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    NgbModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

It looks as follows in my editor


Creating a new component

At this step, we will create a new component within our project called "likes". This is the component that will be used within our example. To create a new component using angular-cli, we just need to type the command ng generate component . I used the following command..

ng generate component likes

This generated the component in our project, and we can open the project in vscode (or your preferred IDE). In my vscode, the newly created project with the new component looks like the following:


In the next steps, we will make changes to the generated files to try two way binding in Angular2 as well as bootstrap components provided by ng-bootstrap.


Overall logic

Overall logic is fairly straightforward. We want to use the a rating component in our test. We want the component to be initialized based on a value in our business logic. When the user changes the values on the ratings, we want the component's internal value to be updated.

We would like to use angular2 two way binding. Angular2 provides an event and a property binding that would suffice to implement two-way binding. However, Angular2 also provides a short-hand way of implementing two-way binding. In this post, we shall try both. As we shall see separating the event binding also allows us to add additional behaviour. Here is the final screen..



Let us first start with the component's presentation logic

Component Presentation logic

The component presentation logic requires changes to ./app/likes/likes.component.html. Here we want the following items displayed on the page..

  • A label for implicit two way binding in Angular2
  • The ngb-rating component configured using Angular's shorthand two-way binding approach. Notice the square and regular brackets around the rate property of the rating component. In html components where two-way binding has not been built in, another way to implement implicit two way binding is to use [(ngModel)] directive. The ngb-rating component also contains a max property that controls number of stars displayed
  • Another ngb-rating component configured using a separate property and event binding, called through the onRate method in the component class. This allows us to program additional behaviour
  • An input text box that also implements explicit two way binding. Its value gets updated from the component, and any changed value updates the component as well using the updateRating() method in the component class. The implicit way to implement two-way binding would be to use the [(ngModel)] directive mentioned earlier.
  • A label showing number of ratings selected through the value of the ratings property.
  • A label for Total likes

<p>
  likes works!
</p>
<p>Implicit two way binding</p>
<ngb-rating [max]="maxStars" [(rate)]="ratings">
</ngb-rating>
<p> Explicit Two way binding</p>
<br/>
<ngb-rating [max]="maxStars" [rate]="ratings" (rateChange)="onRate($event)">
</ngb-rating>
<br/>
<input type="text" [value]="ratings" (change)="updateRating($event)">
<br/>
<p> Current rate: {{ratings}}</p>
<br/>
<span>Total likes: {{totalLikes}} </span>

Here is how the same code looks on my vscode screen.


The application logic

The application logic is also straightforward

  • Our component decorator selects the "likes" tag and inserts our component's presentation code specified in the previous step within likes.component.html
  • We declare 3 component level properties for totalLikes, ratings and maxStars, each initialized appropriately
  • An updateRating() method, called when the text box is updated, updates the ratings property with the value entered in the text box.
  • An onRate() method, sets the value of the ratings property based on value selected in the second component.


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

@Component({
  selector: 'likes',
  templateUrl: './likes.component.html',
  styleUrls: ['./likes.component.css']
})
export class LikesComponent implements OnInit {

@Input() totalLikes = 6;
@Input() ratings = 4;
@Input() maxStars = 7;

  constructor() { }

  ngOnInit() {
  }

  onClick(){
  }

  updateRating($event) {
    this.ratings = $event.target.value;
  }

  onRate(value) {
    console.log("Rate changed to " + value);
    this.ratings = value;
   }
}

This is how it looks on my vscode screen


Putting it together

To put it together, we just need to update our app.component.ts to add the Likes command..

<h1>
  {{title}}
</h1>
<likes></likes>

On my vscode screen



The behaviour

The behaviour is straightforward

  1. The page loads with the default settings for the page



2. Clicking the first component, updates values for all the other components. We increase the value to 6, as shown below:



3. Now we click the second component and bring the value down to 2.


4. Finally, we edit the value in the text box and that should update values for all components as well.


I am sure more creative ways can be conjured to demonstrate the same, but this should explain how the two way binding works with Angular2 and bootstrap.


Saturday, November 26, 2016

Angular2 project using angular-cli with property and event binding

In this setup I am going to walk-through setting up an Angular2 project using angular-cli. We are then going to create a project and show some simple event and property binding using Angular2 and typescript.

The project

Our project is simple. We will create a simple page with a heading, a label and 3 inputs. These are
  1. A page heading showing application state and most recent event
  2. A text label that shows value from the underlying component
  3. An input text field that also shows an initial value from the underlying component.
  4. An input clear button, that clears the value in the underlying component and also the label and input field
  5. An input reset button that sets everything back.
To demonstrate, we will load the page, and cycle through the 2 events. Lets get started...

The steps

First lets setup angular-cli

The step to do that is to run the following command in your target folder


sudo npm install -g angular-cli



This will create the appropriate setup ashown below


Next, we will create the project, I call mine "ng2-1". I will use the angular-cli directive "ng new" to create the new project..


ng new ng2-1


This command creates the necessary files needed for setting up the project, as we can see from the screenshot below..




Now that the project is created, we will open the created files in our favourite code editor and take a look at the generated seed project. I use Vscode, an open source editor from Microsoft that is also available for Ubuntu.

We need to add the created project to our editor.. We can do that by Opening the folder we created at the start, using the Open folder command..


Next I navigate to the root folder for the project, and click OK to start working...



We will now navigate to the appropriate files within the created project. This should be within the ./app/src folder, and the two files we will use are called app.component.ts and app.component.html


The presentation logic

The generated project created a app.component.html file which is our root component's html representation. The default setup just created a heading based on the root object's "title" property. We will add additional presentation logic in terms of the following

  • A label text "My name is ..." using for the myname property defined in the root object.
  • An input text field that takes in its value from the "myname" property defined in the root object (same as the label defined above).
  • A Clear button that calls the clearClick() function in the component class when clicked.
  • A Reset button that calls the resetClick() function in the component class when clicked.

Let's modify the system generated .html file as follows..Notice how the property binding is done by boxing the attribute in square brackets. The onXXX event is called by surrounding the XXX with parentheses, and calling the method name of the component class.

<h1>
  {{title}}
</h1>
  <label>My name is {{myname}}</label>
  <br/>
  <input name="txtName" type="text" [value]="myname"/>
  <input name="btnClear" type="button" value="Clear" (click)="clearClick($event)">
  <input name="btnReset" type="button" value="Reset" (click)="resetClick($event)">

The above code as shown in my editor


The application logic

The application logic is contained in the file called app.component.ts. The system generated code only has a single property called title, but we will extend the logic as follows:
  • A new property called myname
  • A constructor that simply logs an event
  • A clearClick() method that is called when Clear button is clicked. This logs on the console, sets the myname property to "", marks the clear button as disabled, as well as updates the title property to indicate that Clear button has been clicked.
  • A resetClick() method which called when reset button is clicked. This again logs on the console, resets the "myname" property to my name, and updates the title property to indicate that Reset button has been clicked.

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';
  myname = 'Arthgallo';
  isActive=false;
 
  constructor() {
    console.log("Starting now");
  }
  
  clearClick($event) {
    console.log("Clear clicked");
    this.myname = '';
    $event.target.disabled=true;
    this.title="Clear clicked!"
  }

  resetClick($event) {
    console.log("Reset clicked");
    this.myname='Arthgallo';
    this.title="Reset clicked!"
   }
}

This is how the code appears on my screen..


and finally the web page in action. This can be done by entering the command "ng serve" on the command line.


ng serve


By default the webpage can be accessed at http://localhost:4200.. Lets test our property and event binding.

1. Initial load


2. On clicking the clear button



3. And finally the reset button clicked


That's it..