In Step 4.1 we looked at using the web framework Aurelia to reduce code. Another popular and valid choice is Angular2 (3, 4… it’s just Angular ). I have many links I’ve been collecting and will be continuing to post as I learn more.
My code can be found
on GitHub
. I created the project using the
Angular Command Line Interface (CLI)
. This made it quick and easy to create project (ng new
) and serve it on port 4200 with WebPack (ng serve
). See my
readme on that GitHub project
for more info.
This project may be a good start to comparing it with Aurelia, but more complex features is needed to give a through comparison. The choice between the two depends on the experience and preferences of the team. Angular2+ is not an update to Angular1, but a complete re-write. I haven’t used Angular1 much, but there are many differences. It doesn’t look easy to migrate from 1 to 2 (though maybe it’s not so bad as mentioned on DotNetRocks and Auth0 ) so it is still an opportunity to compare to Aurelia, React, Vue, Svelete, Ember, etc. All the options get overwhelming quickly, so you may just have to pick a horse and run with it.
I recommend starting with the Angular QuickStart or walking through the Angular Tutorial to get started learning Angular.
git clone https://github.com/aligneddev/JQueryToAurelia
cd src\angular2\AngularSolarEnergy
code .
npm install
ng serve
The app gets bootstrapped and setup in the main.ts.
import './polyfills.ts';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import { AppModule } from './app/';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
Angular’s main setup is in the AppModule (that’s what I called it and set it in the bootstrapModule(AppModule)
in main.ts). In order for Angular to know about your components you need to declare them. You also need to manually specify the imports as well.
The CLI tool helps get components setup and placed in here ng g component my-new-component
speeds things up a lot.
@NgModule({
declarations: [
AppComponent,
EnergyComponent,
EnergyDetailsComponent,
NotesComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
// us the in memory data service => InMemoryWebApiModule.forRoot(InMemoryDataService),
AppRoutingModule,
NgbModule.forRoot()
],
providers: [{ provide: IEnergyDataServiceToken, useClass: EnergyDataJsonService }],
bootstrap: [AppComponent]
})
export class AppModule { }
Components are the building blocks of Angular . “You write Angular applications by composing HTML templates with Angularized markup, writing component classes to manage those templates, adding application logic in services, and boxing components and services in modules.” “A component controls a patch of screen called a view.”
Components are based on the W3C Web Components ideas (in my opinion) and allow us to write composable smaller pieces and put them together. This helps us create more maintainable and reusable code.
There is a tied html file as declared in the templateUrl of the @Component decorator.
Notice the dependency injection capabilities by looking at the constructor. My Example: Energy Data Details view. This is navigated to when you click on a data row.
import { Inject, Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { Location } from '@angular/common';
import 'rxjs/add/operator/switchMap';
import {IEnergyDataService} from 'app/energy/energy-data-service.interface';
import {IEnergyDataServiceToken} from 'app/energy/energy-data-service.token';
import EnergyDataDto from '../energyDataDto';
@Component({
selector: 'app-energy-details',
templateUrl: './energy-details.component.html',
styleUrls: ['./energy-details.component.css']
})
export class EnergyDetailsComponent implements OnInit {
public selectedEnergyData: EnergyDataDto = new EnergyDataDto();
constructor(@Inject(IEnergyDataServiceToken) private energyDataService: IEnergyDataService,
private route: ActivatedRoute,
private location: Location) { }
ngOnInit() {
this.route.params
.switchMap((params: Params) => {
return this.energyDataService.getEnergyDataByIdAndYear(params['id'], params['year']);
})
.subscribe(data => {
this.selectedEnergyData = data;
});
}
public goBack() {
this.location.back();
}
}
You’ll see {{}}
for string interpolation, [ngModel]
, (click)="clickMethodInComponent
, and
more
.
Don’t forget
“Bananas in a box for 2 way binding [()]”
.
<section>
<h1>Details for {{selectedEnergyData.countryName}} in {{selectedEnergyData.year}}</h1>
<ul>
<li><b>Quantity:</b> {{selectedEnergyData.quantity}}</li>
<li><b>Year:</b> {{selectedEnergyData.year}}</li>
<li><b>TransactionName:</b> {{selectedEnergyData.commodityTransactionName}}</li>
<li><b>Unit:</b> {{selectedEnergyData.unit}}</li>
</ul>
<br />
<button (click)="goBack()">Back to Main</button>
</section>
A service is a good choice for interacting with an HTTP/REST API endpoint.
Tutorial on Promise and Observables
The InMemoryWebApiModule.forRoot(InMemoryDataService),
option in AppModule (
tutorial link
) is a cool feature to have dummy static data for testing or data before your API is ready. You can also look at my code and pull the data from a .json file.
Note: the @Injectable attribute allows EnergyDataService to be injected into other classes. It’s registered in AppModule.
My Example: energy-data.service.ts
@Injectable()
export default class EnergyDataService implements IEnergyDataService {
private yearOptions: string[] = [];
private energyDataCache: EnergyDataDto[] = [];
protected apiUrl = '/api/';
protected solarUrl = 'solar';
constructor(private http: Http) { }
...
public getEnergyData(option: string): Promise<EnergyDataDto[]> {
return this.http.get(this.getEnergyDataApiUrl(option)).toPromise().then((response) => {
this.energyDataCache = this.parseEnergyDataResponse(response);
return this.energyDataCache;
}).catch(this.handleError);
}
...
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
...
}
There is a lot to learn for forms in Angular. I created a quick notes example , but you’ll learn much more from their tutorial.
I was even more overwhelmed by the Angular Testing options and capabilities. I collected a lot of articles and I still don’t have a good handle on all the options and how to approach it. It appears that there are many opportunities to write tests that avoid UI tests and do a good job covering your code.
If you are interested in Test Driven Development (TDD), the best information I found was
Angular2 TDD in ES6
. videos cover 2.0.0-beta.13
, so beware that there are a lot of changes since then.
Many of these are similar to my “Goods” in Step 4 .
Please checkout the other steps in my investigation of Cleaner Code in JavaScript projects.
There should be a ReactJs one coming soon. A friend did an implementation in React .
I’ve had ups and downs with Angular so far. Here’s how I graphed it on the white board.
Please consider using Brave and adding me to your BAT payment ledger. Then you won't have to see ads! (when I get to $100 in Google Ads for a payout (I'm at $95.73!), I pledge to turn off ads)
Also check out my Resources Page for referrals that would help me.