Page 16 - MSDN Magazine, July 2018
P. 16

The Working Programmer TED NEWARD How To Be MEAN: Dynamically Angular
Welcome back again, MEANers.
In my last column, “How To Be MEAN: Reactive Programming”
(msdn.com/magazine/mt846724), I examined the reactive forms mod- ule of Angular, which offers a different way to construct a form and respond to the events the user creates within that. At the end of that article, I posed a question: What if I have a situation where there’s a fairly large number of controls, or the controls created need to change based on the changing nature of the model object underneath? This is one of those cases where, frankly, relying on the traditional “template” system that Angular employs won’t cut it. If I have to create a template for every possible combination of possibilities, it’s going to be a really long day.
Let’s assume, for the moment, that a conference wishes to build a poll system for attendees to evaluate speakers, talks, the confer- ence venue, the Web site, you name it. They want to be able to roll out new questions pretty quickly, potentially even during the con- ference itself should the need arise. This means, then, that I want Web pages that know how to generate fields based on the question types being asked, and those question types will be coming from an external source (such as a JSON service or even a file).
It’s not magic. In any GUI system (Web-based or otherwise) that supports the construction of controls via a runtime construct (such as being able to “new” up the controls themselves), this is a reasonable and quite doable thing. It’s certainly doable in Angular: I can build a system that builds a form entirely off of model objects and the associated (implicit or explicit) metadata therein.
So, to continue with the questionnaire example, if I build a simple Angular service that knows how to obtain a series of “question” objects, an associated Angular form can take some or all of those objects and construct the corresponding collection of form elements to present the questions and capture the answers, presumably for storage somewhere. The key to all of this will be the FormGroup and FormControls that Angular uses to represent those controls at runtime.
Dynamic Model
Let’s start with a base class for all questions, which will help capture some common behavior I expect (and will need) for any question and its related control. Here’s the code for that:
export type ControlType = "textbox" | "dropdown";
export abstract class Question { constructor(public value: string = '',
public key: string = '',
public label: string = '',
public required: boolean = false,
public controlType: ControlType = 'textbox')
{} }
Most of this is going to be pretty straightforward, because most of the class here is just properties (what the patterns folks sometimes call a DTO, or Data Transfer Object), but the key element is going to be the controlType field. It will be the descriptor that corresponds to what HTML constructs I generate. Currently, it has all of two possibili- ties: a textbox (allowing for open-ended text entry) or a dropdown (a single-item selected from a bounded range of possibilities).
Equally obvious, Question is an abstract class, because I expect derived types to be created here, one for each type of Question. The code for TextboxQuestion looks like this:
export class TextboxQuestion extends Question { constructor(value: string = '',
key: string = '',
label: string = '',
required: boolean = false,
public type: string = '') {
super(value, key, label, required, 'textbox');
And the code for DropdownQuestion like this:
export class DropdownQuestion extends Question { constructor(value: string = '',
key: string = '',
label: string = '',
required: boolean = false,
public options: {key: string, value: string}[] = [])
{
super(value, key, label, required, 'dropdown');
} }
Each question passes the set of base parameters up to its parent, and each adds one thing to the mix. In the case of Textbox- Question, it adds a type parameter for the textbox in case I want to signify that this is a password or e-mail textbox. In the case of DropdownQuestion, it adds an array of key/value pairs to use as the dropdown possibilities.
Next, however, I have to figure out how to turn these into Form- Control and FormGroup objects. Arguably, according to the way
Figure 1 The AppComponent
} }
@Component({
selector: 'app-root', template: `
<div>
<h2>How was our conference?</h2>
<app-questionnaire [questions]="questions"></app-questionnaire>
</div> `,
providers: [QuestionService] })
export class AppComponent { questions: Question[];
constructor(service: QuestionService) { this.questions = service.getQuestions();
} }
12 msdn magazine


































































































   14   15   16   17   18