Back to Blog Home
← all posts

A Deep Dive into NativeScript UI's DataForm

January 25, 2017 — by Rob Lauer

Since the dawn of Visual Basic (ok, even before then), developers have been tasked with creating forms-over-data styles of user interfaces. You have some data in a database and you need to provide an easy for your end users to manage that data. Sound familiar? We've all done it so many times, your stomach probably drops an inch or two when you realize you have to create YET ANOTHER FORM to manage data!

Now add mobility to the equation. Not only are you developing for the web, but you have to consider how your mobile users are going to interact with that same data. Are the text fields too long (or not long enough)? Do the select boxes make sense? Can they properly tap on checkboxes? Ayyyy, count me out.

This is yet another reason why NativeScript UI is so exciting. With NativeScript UI we are building on the Telerik tradition of providing easy to use components that delight developers with their ease of use - and delight end users with their engaging features.

This post is part of our "week of NativeScript UI" where we go over the how-to of each NativeScript UI component. Today is all about the DataForm, and soon we will have an in-depth article for each component in our offering:

What is NativeScript UI?

NativeScript UI is a set of premium UI components for native cross-platform mobile apps written with the NativeScript framework. Our goal is to simplify NativeScript app development by providing pre-built, ready-to-use, components that are easy to implement in your app (and equally as easy to style to match your app's look and feel).

Let's get started with learning all about the DataForm component.

DataForm (a.k.a. RadDataForm)

The DataForm component (known in code as RadDataForm), allows you to automatically create a form based on existing data. For example, using the RadDataForm and some CSS, you can pretty easily create form-over-data UIs like this:

raddataform example

With RadDataForm, you can not only have forms created for you automatically, but you can easily customize those forms in your markup or with JavaScript. It's also very easy to add validation to your forms and group UI elements to make large forms more manageable.

Installing NativeScript UI's DataForm

Navigate to your NativeScript project directory and install NativeScript UI DataForm with the following command (no manual download required):

tns plugin add nativescript-ui-dataform

Getting Started with RadDataForm

Note that all of the code demonstrated here is available in this GitHub repo. For more code samples, check out the official NativeScript UI sample repo.

Plugin installed? Great! Now we'll need to add an XML namespace to the root of the page where we want to use RadDataForm. If "XML namespace" scares you, have no fear. You just need to add a property to your root <Page> element, like this:

<Page xmlns:df="nativescript-ui-dataform">

Finally, we need to add a RadDataForm component to our XML markup, as in:

<Page xmlns:df="nativescript-ui-dataform">
    <df:RadDataForm id="myDataForm" />
</Page>

Of course, this markup won't actually render anything useful (yet). Let's add some data and see what magic RadDataForm can provide!

Automagical Form Creation

The beauty of RadDataForm starts with the ability to auto-generate UI on top of an existing data structure. Sound too good to be true? Let's let the code prove our case and start with our UI markup:

<Page xmlns:df="nativescript-ui-dataform" xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
    <ActionBar title="RadDataForm Demo" class="action-bar" />
    <df:RadDataForm id="myDataForm" source="{{ album }}" />
</Page>

Nothing too crazy here:

  • We added a pageLoaded function to the loaded event (see below).
  • We inserted an ActionBar to show a title in our view.
  • We added source="{{ album }}" in which album is our Observable object (see below).

Next, we need some JavaScript to make it all work:

var Observable = require("data/observable").Observable;

var page;
var album = new Observable();
var pageData = new Observable();

exports.pageLoaded = function(args) {
    page = args.object;
    page.bindingContext = pageData;

    album = {
        bandName: "Arcade Fire",
        albumName: "Funeral",
        year: "2004",
        owned: true,
        myRating: "9.5"
    };

    pageData.set("album", album);
};

In this code block we have our pageLoaded function, which is executed when our main view/page loads. Within this function, we have an Observable object called album that contains data for one music album.

Looking for Angular code samples? Check out our complete docs for Angular as well!

Note that for demo purposes we are hardcoding data in our backend. In reality you would want to access data via your own API. Nic Raboy has some great sample code for this in this article.

This all results in the following:

raddataform simple example

Now remember, this is a fully functional UI on top of our data! We not only had data bound from an existing data source, but even the labels in our UI were translated properly from camel case!

Note that the styles you see come from the core light theme that is part of NativeScript, plus some customizations made with the NativeScript Theme Builder.

Customizing Individual Fields

While the default behavior of RadDataForm gets us a long way in providing a full UI on top of our data, there are usually some tweaks to be made.

Luckily, RadDataForm allows us to customize each individual form field label, the underlying data editor, and the order in which they are displayed. Let's take a look at how that is accomplished with the EntityProperty.

For each data entity, I can specify an EntityProperty. And those properties are fairly intuitive:

<df:RadDataForm id="myDataForm" source="{{ album }}">
    <df:RadDataForm.properties>
        <df:EntityProperty name="albumName" displayName="Name of Album" index="0" />
        <df:EntityProperty name="bandName" displayName="Name of Band" index="1" />
        <df:EntityProperty name="year" displayName="Release Year" index="2" />
        <df:EntityProperty name="myRating" displayName="My Rating" index="3" />
        <df:EntityProperty name="owned" displayName="Do I Own This?" index="4" />
    </df:RadDataForm.properties>
</df:RadDataForm>

In this case I've altered the displayName (or label) of these fields. I've also reordered the appearance of the items using the index property.

Check out the docs to see all of the properties you can edit, like readOnly, hintText, and required + validators which we will discuss later in this article.

Before we move on though, we need to customize the editor used for some of the form elements. Editing strings (like in our case albumName and bandName) are fine as-is. I'm also happy that the boolean owned property is translated into a switch on iOS and a checkbox on Android. But what about numeric values in year and myRating? Let's fix that:

<df:EntityProperty name="year" displayName="Release Year" index="2">
    <df:EntityProperty.editor>
        <df:PropertyEditor type="Number" />
    </df:EntityProperty.editor>
</df:EntityProperty>
<df:EntityProperty name="myRating" displayName="My Rating" index="3">
    <df:EntityProperty.editor>
        <df:PropertyEditor type="Slider">
            <df:PropertyEditor.params>
                <df:PropertyEditorParams minimum="0" maximum="10" />
            </df:PropertyEditor.params>
        </df:PropertyEditor>
    </df:EntityProperty.editor>
</df:EntityProperty>

For the year property, we are swapping in a Number PropertyEditor. And for the myRating property, we are using a Slider (which itself has minimum and maximum properties you may specify).

raddataform custom editors

Grouping Form Elements

Sometimes our forms get long. Too long. Especially on mobile this can make for an awkward user experience. RadDataForm allows us to group form elements together, to make long forms more manageable:

<df:RadDataForm id="myDataForm" source="{{ album }}">
    <df:RadDataForm.groups>
        <df:PropertyGroup collapsible="true" name="Album Info">
            <df:PropertyGroup.properties>
                <df:EntityProperty name="albumName" displayName="Name of Album" index="0" />
                <df:EntityProperty name="bandName" displayName="Name of Band" index="1" />
                <df:EntityProperty name="year" displayName="Release Year" index="2" />
            </df:PropertyGroup.properties>
        </df:PropertyGroup>
        <df:PropertyGroup collapsible="true" name="My Info">
            <df:PropertyGroup.properties>
                <df:EntityProperty name="myRating" displayName="My Rating" index="3" />
                <df:EntityProperty name="owned" displayName="Do I Own This?" index="4" />
            </df:PropertyGroup.properties>
        </df:PropertyGroup>
    </df:RadDataForm.groups>
</df:RadDataForm>

In this code, we have replaced the <df:RadDataForm.properties> element with the <df:RadDataForm.groups> element, allowing us to organize fields in groups. (Note that we've also removed the editor customizations, to make the code more legible here.)

This results in the following, with the second group collapsed:

raddataform groups

Validating Form Entries

The final RadDataForm feature we will look at is the all-important validation of form entries. There are two parts to look at here, whether or not a field is required and whether or not you want to validate the content of the field.

Let's take a look at how both of these are handled:

To specify that a field should be required, you'll simply add required="true" to an EntityProperty, like so:

<df:EntityProperty name="albumName" displayName="Name of Album" index="0" required="true" />

We can also validate a variety of scenarios with the built-in validators:

<df:EntityProperty name="year" displayName="Release Year" index="2">
    <df:EntityProperty.validators>
        <df:MinimumLengthValidator 
            errorMessage="Year must be at least 4 digits!" 
            length="4" />
        <df:MaximumLengthValidator 
            errorMessage="Year cannot be more than 4 digits!" 
            length="4" /> 
    </df:EntityProperty.validators>
</df:EntityProperty>

In this case we are adding a MinimumLengthValidator and a MaximumLengthValidator to make sure our year is exactly 4 digits. We will have to deal with the fallout from this in the year 9999 :).

raddataform validation

Anything Else?

I hope you've seen how easy it can be to add a pleasing form on top of existing data sources in your NativeScript app. We did not cover a few interesting parts of RadDataForm, like the commit mode, stack vs grid form layouts, how to style, and the ability to add images to your form labels.