Drie manieren om de productiviteit te verhogen van Angular

Angular is een populair framework voor het snel realiseren van moderne web-apps met maximale flexibiliteit en controle over de werking van alle elementen. Daar staat tegenover dat deze maximale controle en flexibiliteit ten koste gaat van productiviteit wegens het lage abstractieniveau. Toch zijn er meerdere manieren waarop de productiviteit van het werken met Angular verhoogd kan worden.

In een eerdere blog hebben we al gekeken naar de mogelijkheden om aanvullende componentenbibliotheken (Angular Material, PrimeNG etc.) te gebruiken. In dit artikel slaan we een andere richting in en kijken we naar zaken zoals herbruikbare componenten en code-generatie.

1. Formly – Het aanmaken van formulieren

Angular heeft veel sterke punten, maar het genereren van formulieren behoort hier niet toe. Dit proces bestaat kort gezegd vaak uit het met de hand aanmaken van veel componenten, zoals de daadwerkelijke invoervelden, de bijbehorende labels en soms extra velden voor bijvoorbeeld datum pickers. Doordat er veel handmatig gedaan moet worden, is er het risico van code-duplicatie.

Een oplossing om het formulierenproces te versoepelen wordt geboden door Formly. Dit is een framework waarmee je op declaratieve wijze formulieren kunt aanmaken. In plaats van het schrijven veel HTML voor een formulier kun je volstaan met het volgende:

<form [formGroup]="form" (ngSubmit)="submit(task)">
<formly-form [form]="form" [fields]="fields" [model]="task"></formly-form>
<button class="btn btn-secondary" type="button" (mousedown)="back()">Back</button>
<button type="submit" class="btn btn-secondary">Submit</button>
</form>

Zoals je ziet gebruiken we een “formly-form” tag waarmee we een aantal velden binden aan een model-object (in dit geval “task”). Deze velden zijn uiteraard gedefinieerd in de bijbehorende TypeScript-file. Dit ziet er zó uit:

  fields: FormlyFieldConfig[] = [{
key: 'taskTitle',
type: 'input',
defaultValue: 'New Task',
templateOptions: {
label: 'Title',
placeholder: 'Enter name',
required: true,
}
},
{
key: 'description',
type: 'input',
templateOptions: {
label: 'Description',
placeholder: 'Enter description',
required: true,
}
},

Zoals je ziet, wordt een veld in de eerste plaats gedefinieerd door een sleutel (“key”) en een “type” (het type HTML-component zoals “input”, “select”). Binnen de “templateOptions” kun je vervolgens extra eigenschappen opgeven zoals titel, placeholder en of het veld verplicht is. Het is ook mogelijk om declaratief aan te geven wanneer een veld uitgeschakeld of zichtbaar moet zijn. Dat bespaart je de moeite om hiervoor (weinig spannende) TypeScript-functies te moeten schrijven.

Formly voegt ook een aantal handige functionaliteiten toe, zoals een datumveld en fatsoenlijk werkende validatie voor numerieke velden. Het maakt het bovendien eenvoudig om je eigen validaties toe te voegen. Een minpuntje is het vullen van selectie-componenten met dynamische opties, want hiervoor is het helaas nodig om zelf een paar regels code te schrijven om je modelobjecten te vertalen naar het door Formly verwachte formaat. Dit is niet onoverkomelijk, maar had toch wel iets makkelijker gekund.

Ondanks deze kanttekeningen heeft Formly veel potentie voor het genereren van formulieren. Hoewel het declareren van alle velden nog steeds redelijk veel code vereist, is het een verbetering ten opzichte van het definiëren van alle velden in HTML. De Formly aanpak leidt tot minder regels code, minder inspanning en een betere scheiding van presentatie en logica. Bovendien kun je Formly eenvoudig combineren met frameworks als Bootstrap en PrimeNG.

Formly leidt wel tot het verlies van flexibiliteit. Als je ervoor kiest, zit je er wel aan vast voor alle componenten van het formulier. Dat kan lastig zijn als je een bijzonder of uniek component nodig hebt. Daarnaast ziet het Formly-formulier er iets anders uit dan de “standaard” Angular/Boostrap-formulieren. Het is daarom niet raadzaam Formly alleen voor een gedeelte van je formulieren te gebruiken.

Voorbeeld schermen interface

2. Het zelf definiëren van herbruikbare componenten

Een andere manier om code-duplicatie tegen te gaan, is om zelf je eigen herbruikbare componenten te maken. In de basis komt dit neer op het maken van wrappers om de standaardcomponenten (tekstveld, radio button etc.) heen. Voor een tekstveld kan dit er als volgt uitzien:

<div class="form-group">
     <label for="{{name}}">{{label}}</label><input class="form-control" id="{{name}}" name="{{name}}" type="text"
        [(ngModel)]="value" #tf="ngModel" (change)="onModelChange(tf.value)" [attr.maxlength]="maxlength"
        [attr.minlength]="minlength" [required]="required" />
    <div *ngIf="tf.invalid && (tf.dirty || tf.touched)" class="alert alert-danger">
        <div *ngIf="tf.errors.required">
            {{label}} is required
        </div>
        <div *ngIf="tf.errors.minlength">
            {{label}} must be at least {{minlength}} characters long
        </div>
        <div *ngIf="tf.errors.maxlength">
            {{label}} must be at most {{maxlength}} characters long
        </div>        
    </div>
</div>

Hier maken we een “form group” aan die bestaat uit een invoercomponent, bijbehorend label, en een aantal elementen om verschillende types validatiefouten te kunnen laten zien. Dit component bevat ook een aantal placeholders voor naam, label en “value” (de gebonden waarde). Het is ook mogelijk om validatie-gerelateerde zaken (minlength, maxlength, required) in te stellen. Let er vooral op dat we een lokale naam “(#tf)” aan het component toekennen en deze gebruiken voor het laten zien van de fouten.

In het formulier zelf kunnen we de component dan als volgt gebruiken:

<app-text-field name="projectName" label="Name" [(value)]="project.projectName" maxlength="20" minlength="5" required="true" ></app-text-field>

Zoals je ziet, geven we waardes mee voor (een aantal van de) placeholders en binden we de veldwaarde aan de property “project.projectName”.

Het achterliggende TypeScript-component is vervolgens vrij eenvoudig en doet niet veel meer dan het definiëren van input- en outputwaardes.

@Component({
selector: 'app-text-field',
templateUrl: './text-field.component.html',
styleUrls: ['./text-field.component.css'],
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
})
export class TextFieldComponent implements OnInit {

@Input() name: string;

@Input() label: string;

<etc>

@Output() valueChange: EventEmitter<any> = new EventEmitter<any>();

onModelChange(value: string) {
this.valueChange.emit(value);
}
}

Let erop dat in de @Component-definitie een viewProvider is opgenomen. Dit is nodig om ervoor te zorgen dat validatie van het component goed gaat. Zonder deze viewProvider zie je bij validatiefouten van componenten wel meldingen verschijnen, maar wordt het formulier zelf niet als ongeldig gemarkeerd.

Het bovenstaande geeft een eerste indruk en hopelijk een goed beeld van hoe je een set aan herbruikbare componenten kunt opzetten om duplicatie van code te voorkomen. Natuurlijk: het kost de nodige inspanning, maar verdient zich op den duur terug. In tegenstelling tot Formly hou je op deze manier wel het aanmaken van formulieren zelf in de hand. Wanneer mogelijk gebruik je de herbruikbare componenten – als dit niet mogelijk is,  kun je altijd nog terugvallen op maatwerk.

Developer in office

3. De Swagger Angular Generator voor het genereren van services en modelobjecten

Tot nu toe hebben we vooral gekeken naar het genereren van formulieren, maar er is nog een belangrijk punt waarop winst te behalen valt, namelijk het genereren van de code voor de services en modelobjecten. De Swagger Angular generator kan hierbij van pas komen. Zoals de naam doet vermoeden maakt de generator code aan op basis van Swagger, een populaire manier om documentatie voor REST-services te genereren.

Om de generator te gebruiken volg je de installatie-instructies op de website, gevolgd door de volgende stappen:

  • Sla je Swagger documentatie (ruwe JSON) op in een bestand genaamd api-docs.json en plaats dit in de root van de directory die je source code bevat.
  • Voer de generator uit – het kan nodig zijn dat je de locatie nog eerst aan je pad toe moet voegen. De generator bevindt zich in de node_modules/bin directory.
swagger-angular-generator --src <your_directory>\api-docs.json --no-store -w
  • De -w parameter zorgt ervoor dat er geen parameter-objecten gegenereerd worden voor methodes met maar 1 parameter. Dit maakt het weer wat eenvoudiger.
  • Het kan zijn dat het bovenstaande commando faalt met een melding over ontbrekende directory’s. In dat geval kun je gewoon de ontbrekende directory’s aanmaken in de root directory van het project.

Het succesvol uitvoeren van de code leidt ertoe dat er veel code wordt aangemaakt in de src/api directory, o.a.:

  • DTO/model objecten
  • Services die de operaties bevatten die gedefinieerd zijn in de Swagger-documentatie
  • Form services (zie verderop).

Het zware werk is nu gedaan. Je dient wel de gegenereerde services toe te voegen aan app.module.ts, maar daarna is het aanroepen ervan erg eenvoudig:

    this.projectService.getProjectsUsingGET1({ 
      pageNumber : page, 
      sort : event.sortField, 
      sortOrder: event.sortOrder === 1 ? 'asc' : 'desc',
      pageSize : event.rows
    }).subscribe(projects => {this.projects = projects; this.loading = false });

De naamgeving van de methodes is wellicht een beetje onhandig, maar afgezien daarvan werkt het zoals je zou verwachten.

De Swagger Angular Generator gaat nog een stapje verder en genereert ook Form Services. Een Form Service is een service die een FormGroup en een verzameling FormControls bevat die je als basis kunt gebruiken voor het maken van reactive forms. Als ontwikkelaar moet je dan nog wel de HTML files uitwerken, maar een groot gedeelte van de TypeScript boilerplate wordt voor je aangemaakt.

Hou er overigens rekening mee dat, als je op een later moment wijzigingen in de API aanbrengt en de generator de code opnieuw moet aanmaken, je alle zelf gemaakte wijzigingen kwijtraakt. Wees dus voorzichtig met veranderingen, omdat je telkens wijzigingen handmatig terug moet mergen.

Samenvattend

In dit artikel hebben we kort enkele manieren aangestipt om de productiviteit van het werken met Angular te verhogen. We hebben daarbij gekeken naar het gebruik van Formly, het zelf definiëren van herbruikbare componenten, en het gebruik van de Swagger Angular Generator voor het genereren van services en modelobjecten. Hopelijk geven deze korte verhandelingen een goed beeld van aanvullende mogelijkheden. In de toekomst kun je meer van ons verwachten rondom deze onderwerpen.

Geïnteresseerd?

Wil je eens praten over wat we voor jou kunnen betekenen? Neem vrijblijvend contact met ons op of bel naar +31 40 30 41 330.

Meer artikelen

OCS Academy in het teken van Scrum Awareness

OCS Academy in het teken van Scrum Awareness

De OCS Academy is een repeterend jaarprogramma gericht op de startende consultant. Die leert van een ervaren rot in het vak, die zijn kennis en ervaring op een specifiek onderwerp met zijn jongere collega’s deelt. Dit keer stond de OCS Academy in het teken van Scrum...

OCS Family Event in de Efteling

OCS Family Event in de Efteling

Bij Open Circle Solutions weten we dat er meer is dan alleen werk... Nee, serieus: onderling contact buiten werkuren ís erg belangrijk voor onze cultuur en samenwerking. Niet voor niets organiseren we meerdere events per jaar waar onze medewerkers elkaar treffen in...

Nieuwsbrief

Meld je nu aan voor Open Circle Stories en krijg een verzameling artikelen, tips, nieuws en verdiepingen in je mailbox.

Pin It on Pinterest

Share This