#5 Form Snippets Manager
Friday, July 6, 2018
<p> In this article we will layout the left hand side of our interface as well as provide some styling. The format and layout that we are using will be used multiple times so to make it easier to implement for other examples we will create a snippets manager that we can reuse latter on. </p>
Parts
- Part 14: Pipes to the Rescue
- Part 13: Rest of the Examples
- Part 12: Checkbox Example
- Part 11: Adding a Radio Button
- Part 10: Adding a Radio Group
- Part 9: Adding a Select
- Part 8: Adding a Checkbox
- Part 7: Adding a Textarea
- Part 6: Highlighting with Prismjs
- Part 5: Form Snippets Manager
- Part 4: Accessing Form Data
- Part 3: Angular Form Group Interop
- Part 2: The Form Group
- Part 1: Forms Project Creation
Correction and small addition
-
WebUi
-
Source
-
forms
-
examples
-
basic
- basic-example.component.scss
-
basic
-
examples
-
forms
-
Source
We are going to start by make a correction for the previous video. In that video I incorrectly used the
.controls
class in the basic example component's scss file instead of
the correct .controls-template-component
as shown in (a).
While we are at it we are also going to add the overflow: auto;
as well.
basic-example.component.scss (1)
...
.controls-template-component { // <-- Renamed from .controls
grid-area: controls;
padding: $gutter;
overflow: auto; // <-- Added
}
Time to stub out the component and template
-
WebUi
-
Source
-
forms
-
examples
-
basic
- basic-example.component.pug
- basic-example.component.scss
- basic-example.component.ts
-
basic
-
examples
-
forms
-
Source
As I have stated previously we are going to display some code snippets to the user to show how to use our components. Both in their templates as well as any configuration contained within the component if any. We start by creating a copy of methods that will return the component and template snippets (b). Next we need to update our template to display the information (c). Lastly we need to add some styling (d).
basic-example.component.ts (1)
...
export class BasicExampleComponent {
...
private tGetSnippetComponent = (key: string) => {
return `component ${key}`;
}
private tGetSnippetTemplate = (key: string) => {
return `template ${key}`;
}
}
basic-example.component.pug (1)
div.example-container
div.example-content
...
div.controls-template-component
xc-form-group(#basicFormGroup="", name="Basic Form Group" )
div.controls
div.control
xc-input(label="Input", name="input" )
div.template
label Template
pre
code.language-pug {{tGetSnippetTemplate("input")}}
div.component
label Component
pre
code.language-typescript {{tGetSnippetComponent("input")}}
basic-example.component.scss (2)
...
.controls {
display: grid;
grid-template-columns: auto 1fr 1fr;
grid-template-areas: "control template component";
grid-column-gap: $gutter;
.control {
grid-area: control;
width: 18.75em;
}
.component {
grid-area: component;
}
.template {
grid-area: template;
}
}
Enter the snippet manager
-
WebUi
-
Source
-
forms
-
examples
-
basic
- basic-example.component.ts
-
basic
- forms.index.ts
- snippets-manager.ts
-
examples
-
forms
-
Source
The displaying of these snippets will be core feature of the all of the example components that we create. Because of that we will create a class that will help us create and serve up the snippets (e). Next let us add the snippets manager to our forms index (f) for easy importing. And with the snippets manager created we can update our basic example to make use of it (g).
snippets-manager.ts (1)
type Snippet = { component?: string; template: string; };
export class SnippetsManager {
private readonly _snippets: Map<string, Snippet> = null;
constructor(snippets: Array<[string, Snippet]>) {
this._snippets = new Map(snippets);
}
public getComponent = (key: string) => {
return this._snippets.get(key).component || "// none required";
}
public getTemplate = (key: string) => {
return this._snippets.get(key).template;
}
}
forms.index.ts (1)
...
export * from "./snippets-manager";
...
basic-example.component.ts (2)
...
import { SnippetsManager, ... } from "../../forms.index";
...
export class BasicExampleComponent {
...
private _snippets = new SnippetsManager([
["input", { template: 'xc-input(label="Input", name="input")' }]
]);
...
private tGetSnippetComponent = (key: string) => {
return this._snippets.getComponent(key);
}
private tGetSnippetTemplate = (key: string) => {
return this._snippets.getTemplate(key);
}
}
Display the overall template and component
-
WebUi
-
Source
-
forms
-
examples
-
basic
- basic-example.component.pug
- basic-example.component.scss
- basic-example.component.ts
-
basic
-
examples
-
forms
-
Source
In addition to showing the component configuration and template for each individual control we are also going to show and overall component configuration and template. So just as before we will start by stubbing out the functionality within our basic example component (h). Next we will update our template (i) and add some styling (j).
basic-example.component.ts (3)
...
export class BasicExampleComponent {
...
private get tComponent() {
return `import { Component, ViewChild } from "@angular/core";
import { XcFormGroupComponent } from "../../forms.index";
@Component({
selector: "basic-example",
template: require("./basic-example.component.pug"),
styles: [require("./basic-example.component.scss")]
})
export class BasicExampleComponent {
@ViewChild("basicFormGroup") private readonly _form: XcFormGroupComponent = null;
/// To be added
}`;
}
...
private get tTemplate() {
return `xc-form-group.form-group(#basicFormGroup="", name="Basic Form Group" )
/// To be added`;
}
...
}
basic-example.component.pug (2)
div.example-container
div.example-content
...
div.controls-template-component
xc-form-group(#basicFormGroup="", name="Basic Form Group" )
...
hr
div.template-component
div.template
label Template
pre
code.language-pug {{tTemplate}}
div.component
label Component
pre
code.language-typescript {{tComponent}}
basic-example.component.scss (3)
...
.template-component {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-areas: "template component";
grid-column-gap: $gutter;
.component {
grid-area: component;
}
.template {
grid-area: template;
}
}
Help us out again snippets manager
-
WebUi
-
Source
-
forms
-
examples
-
basic
- basic-example.component.ts
-
basic
- snippets-manager.ts
-
examples
-
forms
-
Source
Of course the last thing to do is to modify our snippets manager to provide us the component configuration and templates for the individual controls so that we can include them in the overall information (k). With the changes made to our snippets manager we can update our basic example component to take advantage of the actual information and not the temporary information that we used previously (l).
snippets-manager.ts (2)
import { of, from, range } from "rxjs";
import { filter, map, mergeMap, reduce, takeWhile } from "rxjs/operators";
...
export class SnippetsManager {
...
public snippetsToComponent = (indent: number = 1) => {
return this.snippetsToCode(indent, (s: Snippet) => s.component);
}
public snippetsToTemplate = (indent: number = 1) => {
return this.snippetsToCode(indent, (s: Snippet) => s.template);
}
private snippetsToCode = (indent: number, f: (s: Snippet) => string) => {
let res: string;
from(this._snippets)
.pipe(
map(x => this.indent(indent, f(x[1]))),
filter(x => typeof x !== "undefined" && x !== null),
reduce((acc, x) => `${acc}${x}\n`, "")
)
.subscribe(x => res = x);
return res.replace(/\n$/, "");
}
private indent = (indent: number, str: string) => {
if (typeof str === "undefined" || str === null) {
return null;
}
let space: string;
range(0, indent)
.pipe(
takeWhile(x => x < indent),
reduce((acc: string, _: number) => `${acc} `, "")
)
.subscribe((x: string) => space = x);
let res: string;
of(str)
.pipe(
mergeMap((x: string) => from(x.split(/\n/))),
reduce((acc: string, x: string) => `${acc}${space}${x}\n`, ""),
)
.subscribe(x => res = x);
return res.replace(/\n$/, "");
}
}
basic-example.component.ts (4)
...
export class BasicExampleComponent {
...
private get tComponent() {
return `import { Component, ViewChild } from "@angular/core";
import { XcFormGroupComponent } from "../../forms.index";
@Component({
selector: "basic-example",
template: require("./basic-example.component.pug"),
styles: [require("./basic-example.component.scss")]
})
export class BasicExampleComponent {
@ViewChild("basicFormGroup") private readonly _form: XcFormGroupComponent = null;
${this._snippets.snippetsToComponent()}
}`;
}
...
private get tTemplate() {
return `xc-form-group.form-group(#basicFormGroup="", name="Basic Form Group" )
${this._snippets.snippetsToTemplate()}`;
}
...
}