The new builder, pt 2

In the first part I outlined why we creating a new “builder”. Let’s dig into how it does what it does and how you use it. By the way, this is mainly for those that are interested in the internals of Angular Schema Form (ASF). Just using Angular Schema Form will not expose you to the builder. With that said, let’s get cracking!

The builder is basically done but small changes will probably occur before release.

What does it do?

The builder is a function that recursively loops through a form definition, matching form types against templates and stitching them together. All in one go. It’s housed in the sfBuilder service which has one function: build (great name, right?)

Let’s check out a basic usage example.

Loading this up in a browser gives us the exciting output “Hello World”! So in whats happening here? Let us start with the actual call to the builder.

var documentFragment = sfBuilder.build(formDef, decorator);

The actual build function is very simple. It takes a canonical form definition, i.e. a list of object that at least have the property type. It also takes an object that maps type to template + other stuff, called a decorator. It returns a document fragment.

What about stuff in stuff?

So if you read part one you know that it was the form fields that included other fields that was the main performance hogs. So how does the new builder handle tree like form definitions? Let’s look at a fieldset.

This is how it looks in a browser:

Ok, so whats new here? Let’s start by looking at the form definition.

var formDef = [
{
type: 'fieldset',
items: [{type: 'example'}]
}
];

It’s the beginning of a simple tree structure, in theory it could become very deep and complicated. ASF used to solve this by having a bootstrap-decorator with a ng-repeat in its template. This is nice and readable but not very performant (see part one for more details.)

The builder is actually quite stupid by design, since the form definition can basically take any form it’s impossible to know if a particular form field has any children and if so under which properties, i.e. it’s not always items. To solve this we have small functions that help out in building each field. In the above example it’s called fieldsetBuilder.

Helping out

Each field can have a function, or a list of functions, associated with it in the decorator. And it’s in these helpers the grunt of the work is actually done. Let us look at the examples fieldsetBuilder. If we remove all comments it’s very small.

var fieldsetBuilder = function(args) {
var children = args.build(args.form.items);
args.fieldFrag.firstChild.appendChild(children);
};

The build helpers gets one argument, an “options” object. It contains lots of things, the most important being the form and the template of the field loaded into a document fragment. It also contains a special version of the main builder function to be used when recursing down into the children of a form definition.

So why is this better?

The astute reader might have noticed that the difference between the new builder and the old way ASF built it’s form is that the we’ve moved stuff from angular to plain old javascript. The fieldsets transclusion is no longer done by directives and ng-repeat but instead done by the builder and it’s helpers. The gain is that we can use the $compile service only once on the finished form.

The downside is that we get a bit more complicated. The templates does no longer tell us the entire story. But this is also a strength, the builder is basically framework agnostic. I hope this will help in creating a Angular 2 version of ASF.

But wait, there is more

The above ramblings only describes the basic functionality of the builder, I haven’t touched on how the form is hooked up, where $$value$$ has gone, how arrays work etc. I’m not going to either. But let me just briefly mention a couple of standard build helpers that are available to add-on and decorator authors.

simpleTransclusion is basically the fieldsetBuilder from the example, it checks for a items property and builds all the children and appends them to the first element.

transclusion helper function queries the template for a element with the attribute sf-field-transclude and appends recursively built children to it.

sfField helper adds the sf-field attribute directive to the first child of the document fragment. The directive is responsible for setting up scope and exporting form etc. It replaces what bootstrap-decorator did, sans templating.

ngModel queries the template fragment for a/any element with the attribute sf-field-model. That then get’s a ng-model with a proper value. This replaces the need for string replacement of $$value$$.

ngModelOption adds the ng-model-options directive to the fragment if it has a value in the form definition.

@davidlgj

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.