Advertisement

#7 Every Good Form Needs a Textarea

In this article we will be adding a new control to our library namely a textarea control. We will make the job of adding new controls infinitely easier by making use of the mixin capabilities of both pug and scss.

Specifying the control value

  • WebUi
    • Source
      • forms
        • controls
          • input
            • xc-input.component.ts
          • xc-form-control.ts
        • xc-form-group.component.ts

We are going to start by making a small change to the definition for our form control base class by making it a generic class where we must specify the type of value the form control will take (a). My main reason, at least for right now, in doing this is to specify in code my expectation for the input control we have already created. That expectation is that although an html input make contain a boolean value, as in the case for a checkbox, our input will be used for html elements that contain a string value. With that change made we have to update the class declaration for the input (b) and provide a type to our query list in the form group (c).

xc-form-control.ts (1)

export abstract class XcFormControl<TValue> extends ... {
    public get value() { return this.formControlInternal.value as TValue; }
    public set value(value: TValue) { this.formControlInternal.setValue(value); }
}
(a) Updating our form control so that it takes in a generic type for the type of value that the form control will contain.

xc-input.component.ts (1)

...
export class XcInputComponent extends XcFormControl<string> {
    ...
}
(b) Updating our input so that we specify that it is to be used for any html input that contains a string value.

xc-form-group.component.ts (1)

...
export class XcFormGroupComponent implements ... {
    @ContentChildren(XcFormControl) private readonly _formControls: QueryList<XcFormControl<any>> = null;
    ...
}
(c) Updating our form group to add a type specification to our query list.

Why are we using pug instead of html?

  • WebUi
    • Source
      • forms
        • controls
          • input
            • xc-input.component.pug
            • xc-input.component.scss
          • controls.mixins.pug
          • controls.mixins.scss

Before we add a new control we are going to make use of the fact that we are using pug instead just html for our component templates. To do this we are just going to create a mixin file (d) that will, you guessed it, contain the mixins that we will use in all of our control templates. With the mixins created we can simply include them in our input template as shown in (e).

controls.mixins.pug (1)

mixin formControlGroup
    div.xc-form-control-group(*ngIf="tGroup", [formGroup]="tGroup")
        label(*ngIf="tLabel") {{tLabel}}
        block

mixin input
    input([type]="tType", [formControlName]="tName")
(d) Pug mixins that we can use in our form control templates.

xc-input.component.pug (1)

include ../controls.mixins.pug

+formControlGroup
    +input
(e) Updating our input so that it makes use of the mixins that we just created.

Although we really do not have any styling that we would like to share between our controls we will in the future. So we will just do the same thing that we did with our pug templates and create a mixins file for our scss as well (f). And once again we will include the mixin within our style file for our input component (g).

controls.mixins.scss (1)

@mixin formControlGroup {
    .xc-form-control-group {
    }
}
(f) Mixins file that we will use to provide common styling to our controls.

xc-input.component.scss (1)

@import "../controls.mixins.scss";

@include formControlGroup;
(g) Updating our input style file to make use of the mixin that we just created.

Welcome to the party textarea

  • WebUi
    • Source
      • forms
        • controls
          • textarea
            • xc-textarea.component.pug
            • xc-textarea.component.scss
            • xc-textarea.component.ts
          • controls.mixins.pug
        • examples
          • form-examples.module.ts

We are going to start by adding a textarea control since it is just about the same as the input we have already created. The first thing we will do is create a mixin for the textarea (h).

controls.mixins.pug (2)

...
mixin textarea
    textarea([formControlName]="tName")
(h) Returning to our control pug mixin file and creating a mixin for a textarea.

To create our textarea control it is now just a simple matter of creating the template (i), the styling (j) and the component definition (k).

xc-textarea.component.pug (1)

include ../controls.mixins.pug

+formControlGroup
    +textarea
(i) The template is created just the same way as the input control except that we substitute in a call to the textarea mixin instead of the input mixin.

xc-textarea.component.scss (1)

@import "../controls.mixins.scss";

@include formControlGroup;
(j) Time to bring in the styling.

xc-textarea.component.ts (1)

import { forwardRef, Component } from "@angular/core";

import { XcFormControl } from "../xc-form-control";

@Component({
    selector: "xc-textarea",
    template: require("./xc-textarea.component.pug"),
    styles: [require("./xc-textarea.component.scss")],
    providers: [{ provide: XcFormControl, useExisting: forwardRef(() => XcTextAreaComponent) }]
})
export class XcTextAreaComponent extends XcFormControl<string> {
    protected get tagName() { return "xc-textarea"; }
}
(k) In this case the component definition is even simplier than for the input.
Advertisement

Of course we can't forget to add an export for our textarea to the controls index file (l). While we are at it we might as well add a declaration for our textarea control to the form examples module definition (m).

controls.index.ts (1)

...
export * from "./textarea/xc-textarea.component";
(l) Adding an export statement to our controls index file.

form-examples.module.ts (1)

...
import {
    ..., XcTextAreaComponent
} from "./form-examples.index";
...
@NgModule({
    ...,
    declarations: [
        ...,
        XcTextAreaComponent
    ],
    ...
})
export class FormExamplesModule { }
platformBrowserDynamic().bootstrapModule(FormExamplesModule);
(m) Add a reference to our textarea to the form examples module definition.

Always a correction to be made

  • WebUi
    • Source
      • forms
        • examples
          • basic
            • basic-example.component.pug
            • basic-example.component.scss

Before we add the textarea to our basic example we need to make some adjustments. We will start by changing the css class inside our form group from 'controls' to 'control-row' (n). As the previous name implies it was going to be the container for all of the controls but that would require us to update our grid layout every time we added a control. While this is not impossible it is annoying so instead we will simple wrap each of our controls with the 'control-row' div. The next change is not super important but there is no reason for anything not related to a form control to be contained within our form group so we just need to outdent the hr and the following div. With that done we need to update our style file (o).

basic-example.component.pug (1)

div.example-container
    div.example-content
        ...
        div.controls-template-component
            xc-form-group(... )
                div.control-row <!-- <-- Renamed from controls-->
            hr <!-- <-- Outdent by one level -->
            div.template-component <!-- <-- Outdent by one level -->
                ...
(n) Updating the template so that our css class from 'controls' to 'control-row' and outdenting the hr and the div.template-component and its contents to remove it from our form group.

basic-example.component.scss (1)

...
.control-row { /*<-- Renamed from controls*/
    ...
}
...
(o) Since we changed the css class in the template we need to update our styling as well.

The more the mixins the merrier

  • WebUi
    • Source
      • forms
        • examples
          • basic
            • basic-example.component.pug
          • examples.mixins.pug

Of course every time we add a control to our example it will have the same general shape in the html so it's time to add another mixin (p). And next up is updating our example template to make use of the new mixin (q).

examples.mixins.pug (1)

mixin controlRow(key)
    div.control-row
        div.control
            block
        div.template
            label Template
            pre
                code.language-pug {{tGetSnippetTemplate("#{key}")}}
        div.component
            label Component
            pre
                code.language-typescript {{tGetSnippetComponent("#{key}")}}
(p) Creating another mixin to make it that much easier to add a control row.

basic-example.component.pug (2)

include ../examples.mixins.pug

div.example-container
    div.example-content
        ...
        div.controls-template-component
            xc-form-group(... )
                +controlRow("input")
                    xc-input(label="Input", name="input" )
                ...
(q) Updaing our basic example to use the mixin we just created.

Finally we have a textarea control

  • WebUi
    • Source
      • forms
        • examples
          • basic
            • basic-example.component.pug
            • basic-example.component.ts

With all of that done it is a simple matter to add the textarea to our example template (r). Of course to make everything work right we need to add a snippet to our snippet manager (s). And voila we have a textarea control.

basic-example.component.pug (3)

...
div.example-container
    div.example-content
        ...
        div.controls-template-component
            xc-form-group(... )
                ...
                +controlRow("textarea")
                    xc-textarea(label="Textarea", name="textarea" )
            ...
(r) Adding the textarea to our example.

basic-example.component.ts (1)

...
export class BasicExampleComponent implements ... {
    ...
    private readonly _snippets = new SnippetsManager([
        ...,
        ["textarea", { template: 'xc-textarea(label="Textarea", name="textarea" )' }]
    ]);
    ...
}
(s) Adding a snippet to our snippet manager.
Exciton Interactive LLC
Advertisement