Dimitry Karpenko
Java/Eclipse developer in MyEclipse and Webclipse teams.
Posted on Jun 12th 2017
Some time ago an article Creating My First Web App with Angular 2 in Eclipse was published. Since then, Angular was upgraded and became Angular 4, and new tooling for it in Webclipse (now CodeMix) appeared. Let’s see how creating a simple application using Angular 4 and new Angular tooling looks.
Prerequisites
- Angular IDE or CodeMix or MyEclipse 2017+—Choose any of these Eclipse-based IDEs to follow along.
- Node.js, NPM, Angular CLI—These are the core tools for Angular development. They are installed automatically by the IDE.
- Basic TypeScript, HTML and Eclipse usage knowledge.
Creating a New Angular project
Switch to Angular perspective using the button at the top-right corner of your IDE.
Right-click the empty area in Project Explorer/Project Explorer+, and choose New > Angular Project:
You’ll see the new Angular project wizard, where you can select Node.js, NPM and Angular CLI versions you want to use. For now, let’s enter project name “vehicles” and leave all versions default.
After that, you can either click “Finish” or “Next> “ and see a list of the commands which would be executed in local terminal to create your project.
In Terminal+ view you can see how commands are executed while creating your project. Also, Terminal+ is used while performing any Angular CLI commands – for creating new elements, starting server, etc. You can use it for entering your own commands as well.
Creating Model classes & Elements
We’ll create a simple master-details view application, like the one in the previous example. Let’s start – right-click newly created project, expand it, expand src/app folder, create folder model inside, right-click it and choose New > Typescript Class. Enter “Vehicle” into the “Name” field.
Make newly created Vehicle class to be the following:
export class Vehicle {
id;
name;
type;
mass;
}
Right-click app folder again, choose New > Component:
In the newly opened wizard, enter element name vehicle-list:
Vehicle-list.component.ts file would be opened. It contains basic component’s infrastructure looking like following:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-vehicle-list',
templateUrl: './vehicle-list.component.html',
styleUrls: ['./vehicle-list.component.css']
})
export class VehicleListComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
All the basic component infrastructure is present here.
- The first line is importing the Component decorator function and OnInit interface. This decorator function is describing metadata for any Angular 2 reusable UI component, OnInit interface extension is used to register init lifecycle hook (see below).
- Selector specifies the tag name that would trigger this component’s insertion.
- TemplateUrl and styleUrls specify file names that contain an html-based template for the component UI and css styling for it.
- Class VehiclesListComponent should contain almost all inner component logic written in TypeScript. For now it contains only an empty constructor and empty ngOnInit lifecycle hook. This hook can be useful for some “heavy” initialization like network or database calls, constructor should be used only for basic initialization, without any heavy IO.
OK, we’ll definitely need to store a list of our vehicles somewhere. Let’s add field vehicles: Vehicle[]; to the VehiclesListComponent class. Of course, Vehicle will be highlighted in red—currently, the TS compiler knows nothing about it. To fix this, just target your muse on Vehicle class name underlined with red, or put caret into it and click Ctrl+1. You’ll see the following quick fix suggestion:
Click onto the link with the given suggestion, import statement for Vehicle class would be added to the top of the file.
Service
Well, now we have a vehicle list, but how can we interact with it? Passing it to the constructor would make our code less flexible by requiring a concrete list to be specified when creating a vehicle list component. There’s a better solution—Angular supports Dependency Injection out-of-the-box, and it can be accomplished using Angular Services.
Right-click src folder again, choose New > Service. In the opened wizard, enter element name “vehicle”, press “Finish”. Vehicle.service.ts file would be created in the app folder.
Angular Service is used when some common functionality needs to be provided to several modules . For now we won’t implement any complex logic to obtain the list and will just hard code our vehicle entries. In the following code we import the Injectable decorator, set up our list, assign given list to class field and return it by demand:
import { Injectable } from '@angular/core';
const vehicles = [
{
id: 1,
name: 'Trailer - 1',
type: 'Truck',
mass: 40
},
{
id: 2,
name: 'An-2',
type: 'Plane',
mass: 5
},
{
id: 3,
name: 'LandCruiser 80',
type: 'Jeep',
mass: 2
},
];
@Injectable()
export class VehicleService {
private vehicles;
constructor() {
this.vehicles = vehicles;
}
getVehicles() {
return this.vehicles;
}
}
Now let’s go back to vehicles-list.component.ts, import VehicleService and make 2 more edits: add providers: [VehicleService] to @Component and change constructor to:
constructor(private vehicleService: VehicleService) {
this.vehicles = this.vehicleService.getVehicles();
}
We’re basically done with the component, let’s switch to UI. Open vehicle-list.component.html and replace its mock contents with our table.
<table class="tftable">
<tr><th>ID</th><th>Name</th><th>Type</th><th>Mass</th>
<tr *ngFor="let vehicle of vehicles">
<td>{{vehicle.id}}</td> <td>{{vehicle.name}}</td> <td>{{vehicle.type}}</td> <td>{{vehicle.mass}}</td>
</tr>
</table>
We do a conceptually simple thing here—create a table with a constant header and then iterate over vehicles list, creating a table row for each vehicle. A row is composed of cells with corresponding properties.
- *ngFor is a built-in directive iterating over a list (vehicles in our case).
- {{ }} tells Angular to read a given property from the TypeScript model and render it.
Also, we specify table class here because we want to have some styling for it—corresponding styles are put into vehicles-list.component.css. You can download the sample project and open them if necessary.
Plugging In
Ok, we’re done with our initial UI. To see the result, just add our selector tag to app.component.html:
<app-vehicles-list></app-vehicles-list>
Then go to Servers view (or open it if necessary), select your newly created project and click “Start Server”
You can monitor the startup process in Terminal+ view. Also, CLI would dispatch changes to project files and rebuild app immediately after changes are saved – this process is also reflected in Terminal+.
Open your browser (it’s highly recommended to use Chrome) and type localhost:4200 in its address bar. Here we go, application works!
Master-Details
Our table is pretty, but not very interactive, huh? OK, let’s make it a bit more “dynamic” by adding a Details view that displays a clicked table row and allows the fields to be edited. Let’s create VehicleDetailsComponent – choose New > Component and enter “vehicle-details” as a name.
Just like for Vehicle List, a folder with ts and html/css files will be created. We’ll need to modify two of them. VehicleDetailsComponent in vehicle-details.component.ts needs to have a field for current vehicle—vehicle:Vehicle, with @Input directive above. This decorator declares the vehicle field as an input, which makes passing an actual value to it much easier.
Now let’s take a closer look at the template file for it:
<div *ngIf="vehicle">
<h2>{{vehicle.name}} properties</h2>
<table>
<tr>
<td><label>ID: </label></td>
<td>{{vehicle.id}}</td>
</tr>
<tr>
<td><label>Name: </label></td>
<td><input [(ngModel)]="vehicle.name" placeholder="name" /></td>
</tr>
<tr>
<td><label>Type: </label></td>
<td><input [(ngModel)]="vehicle.type" placeholder="type" /></td>
</tr>
<tr>
<td><label>Mass: </label></td>
<td><input [(ngModel)]="vehicle.mass" placeholder="mass" /></td>
</tr>
</table>
</div>
- *ngIf=”vehicle”—Designates to only proceed with the content when vehicle field has value, which is needed to avoid errors when selection is empty.
- [(ngModel)]=”vehicle.name” (same for type and mass)—Implements bi-directional data binding between input field and corresponding property.
If an error with text like “Can’t bind to ‘ngModel’ since it isn’t a known property of ‘input’” appears – then it means that app modules weren’t properly configured. Go to src/app/app.module.ts and add FormsModule to imports section, so finaly app.module.ts should look like following:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { VehicleListComponent } from './vehicle-list/vehicle-list.component';
import { VehicleDetailsComponent } from './vehicle-details/vehicle-details.component';
@NgModule({
declarations: [
AppComponent,
VehicleListComponent,
VehicleDetailsComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
No compilation errors should happen after this. Warning could remain, but it doesn’t break down any functionality.
Now, we need to change our VehicleListComponent to handle selection. Let’s add a selectedVehicle field and a method onSelect to handle selection.
Also, in the html template we’ll need to add a tag for the details component. To make it work, we need to import VehicleDetailsComponent and add the corresponding directive. After given changes, vehicle-list.component.ts will look like the following:
import { Component, OnInit } from '@angular/core';
import { VehicleService } from '../model/vehicle.service';
import { Vehicle } from '../model/vehicle';
@Component({
selector: 'app-vehicle-list',
templateUrl: 'vehicle-list.component.html',
styleUrls: ['vehicle-list.component.css'],
providers: [VehicleService]
})
export class VehicleListComponent implements OnInit {
vehicles: Vehicle[];
selectedVehicle: Vehicle;
constructor(private vehicleService: VehicleService) {
this.vehicles = this.vehicleService.getVehicles();
}
ngOnInit() {
}
onSelect(vehicle: Vehicle) { this.selectedVehicle = vehicle; }
}
Next, let’s change the vehicles list template, vehicle-list.component.html. We need to add the click handler to each table row to call the corresponding selection method—(click)=”onSelect(vehicle)“. Also, let’s add a tag for the vehicle details component below our table:
<table class="tftable">
<tr><th>ID</th><th>Name</th><th>Type</th><th>Mass</th>
<tr *ngFor="let vehicle of vehicles"
(click)="onSelect(vehicle)">
<td>{{vehicle.id}}</td> <td>{{vehicle.name}}</td> <td>{{vehicle.type}}</td> <td>{{vehicle.mass}}</td>
</tr>
</table>
<vehicle-details [vehicle]="selectedVehicle"></vehicle-details>
Your changes should be automatically picked up and compiled; please, look at Terminal+. If you haven’t closed your browser, you don’t need to do anything – the browser should be updated automatically. Switch to it and you’ll see:
Perfect, it works. You can try editing any value under the “properties”, and the change will be immediately reflected in the table — nothing extra needed for it.
A Little Bit of Styling
It looks pretty good now, but it’s a bit difficult to determine which row is selected. Let’s fix this. Add an attribute [class.selected]=”vehicle === selectedVehicle” to the <tr> tag in vehicle-list.component.html. Its meaning is pretty obvious—add a CSS class for the case when the current row’s vehicle equals the selected one. Of course, to make this work, we need to add corresponding style to vehicle-list.component.css:
.selected { background-color: #CFD8DC !important;}
Let’s add hovering style too! It’s as easy as adding one line to the css file:
table.tftable tr:hover {background-color: #DDD; left: .1em;}
Great, our table looks much more interactive after this.
Inspecting
Possibly you’ve noticed that small vertical toolbar at the top right corner of the page in browser? It’s CodeLive toolbox, which can be very helpful for finding out what’s happening in your application and which components are being displayed. Let’s see how it works.
Click that wand icon – you’ll be able to see which component is under your cursor pointer. If you now click that grayed area – the component tree will be opened.
You can also see the component tree by clicking list icon, which is above the wand icon in CodeLive toolbox.
In our case a tree is pretty simple, but in case of real applications, which could consist of significant amount of components, such a tree with an ability to filter it could be very useful.
If you put your cursor near one of the items of this tree, you’ll see 3 actions allowing to open ts, html and css files for a given component. It could be very useful for those who want to investigate an application created by some other person.
Debugging
Some guys who are switching from Desktop & Mobile development to Web one are complaining about poor debugging tools offered for Web developers – in the best case they need to debug in browser, and in the worst one – using old tricks like printing values to console or showing them in the pop-ups. Don’t worry – CodeMix tooling allows debugging in your favorite IDE.
Let’s put a breakpoint e.g. into onSelect handler of our VehicleListComponent.
Then go down to Servers view and click on “Debug application in Chrome” icon.
Chrome would be re-launched. Click some entry in Vehicles list to select it. The IDE would suggest you to switch to Debug perspective, after this you’d see the stuff well-known for Desktop or Android app developers – debug line mark, debug stack trace and variables view:
In the “Loaded JavaScript view” to the right of the source editor area you can see js files, which are loaded by the app.
Conclusion
As I said in the previous article, Typescript and Angular are great tools to start Web development with – they allow to write code in Object-oriented style, without much headache with different browsers support, dynamic typing etc.
Using Webclipse Angular tooling makes this even more convenient and friendly – you can create projects or components using modern GUI (without a direct use of the command line), inspect your component model using convenient and intuitive tooling, and debug your application inside the IDE in a way well-known to almost any programmer. On the other hand, you don’t lose the flexibility of plain old command line – it’s still accessible for you in Terminal+ view, as well as an output of CLI commands called by wizards – IDE doesn’t try to hide any details from you.
In my opinion, the described set of tools is a very good choice for anyone who wants to start his or her experience in Web development.
Resources
vehicles.zip—Sample project for this blog