How to Update NativeScript RadDataForm Programmatically

How do you update a value field when using the RadDataForm in NativeScript? At the time of writing, you can't do it using any JavaScript API…

Take control of your career. Build JavaScript mobile apps.

How do you update a value field when using the RadDataForm in NativeScript? At the time of writing, you can't do it using any JavaScript API.


In this short NativeScript tutorial, I'll show you a workaround.


TL;DR

If you prefer video, I cover how to programmatically update NativeScript RadDataForm in the short video below.



The Problem

The RadDataForm, (or DataForm as it's commonly known) is one of the free NativeScript Professional UI components that is built by the official NativeScript team. It automatically generates UI for editing the properties of a supplied object, thus helping you quickly build mobile forms. It uses iOS and Android libraries under the hood and implements JavaScript versions of the native libraries on top, while exposing TypeScript declarations. It's pretty cool!


While using the RadDataForm in a client project I had, I came upon a roadblock while trying to update some fields with user input. The issue has been reported and has been open for quite some time on GitHub. At the time of writing, there is still no solution, but there is a workaround, which we'll quickly go over.


The Solution

Before we get to the solution, let's first take a look at the demo app we'll use.


Demo app


It's a simple app with a form containing one field. Above the form is a button which when tapped, we want it to update the value of the form's field.


Here's the code for that page:


<Page xmlns="http://www.nativescript.org/tns.xsd" navigatingTo="navigatingTo"
  class="page" xmlns:df="nativescript-ui-dataform">

  <StackLayout class="p-20">
      <Label text="Tap the button" class="h1 text-center"/>
      <Button text="TAP" tap="{{ onTap }}" class="btn btn-primary btn-active"/>

      <df:RadDataForm id=myDataForm" source="{{ formModel }}" />
  </StackLayout>

</Page>

You can see the Button and the RadDataForm which is bound to the formModel data source.


The form model has one property with a title property which is the name of the field in the form that will be generated.


import { Observable } from 'tns-core-modules/data/observable';

export class HelloWorldModel extends Observable {
  public formModel = {
    title: 'Hello World'
  };
  public onTap() {}
}

To update the form's Title field's value when the button is tapped, we first need to get a reference to the DataForm in code:


import { EventData } from 'tns-core-modules/data/observable';
import { Page } from 'tns-core-modules/ui/page';
import { HelloWorldModel } from './main-view-model';
import { RadDataForm } from 'nativescript-ui-dataform';

export function navigatingTo(args: EventData) {
  const page = <Page>args.object;
  const dataForm = page.getViewById('myDataForm') as RadDataForm;
  page.bindingContext = new HelloWorldModel(dataForm);
}

Notice we pass dataFrom into the view model:


page.bindingContext = new HelloWorldModel(dataForm);

It's preferable for the UI to be kept separate from the view model, but for the sake of simplicity in the demo, we let that slide here.


In the HelloWorldModel, we add a constructor that accepts a RadDataForm:


import { Observable } from 'tns-core-modules/data/observable';
import { RadDataForm } from 'nativescript-ui-dataform';

export class HelloWorldModel extends Observable {

  constructor(private dataForm: RadDataForm) {
      super();
  }
 ...
}

Now that we have a reference to the DataForm, we can use it in onTap() and do all sorts of things with it.


Since there is no API to update the form's fields, we'll need to reload it. Before reloading the form, we first change the title.


public onTap() {
  this.set('formModel', { title: 'Hi' });
  this.dataForm.reload();
}

You might have been tempted to change the field directly with this.formModel.title = "Hi";. This won't work.


Since HelloWorldModel is an Observable class, we use set() to set the property of a complex object that's part of the Observable. If you don't call set() then the UI won't know that something has changed.


Improving the Solution

When calling the set() function, we pass it the name of the Observable property as well as an object with the properties we want to change.


In our example, the DataForm has only one property. Your form might not be so simple—it might have multiple properties. In this case, it might be better to refactor the code as shown:


public onTap() {
  const newFormModel = { ...this.formModel, title: 'Hi there' };
  this.set('formModel', newFormModel);
  this.dataForm.reload();
}

Here, we create a new object with the properties of the existing formModel and the property we want to update, before passing it to set().


Caveat...

We can now change the value of a RadDataForm field in code. However, the solution isn't perfect. Every time we change the form's data, it is reloaded. So, if you have the form in focus, you will lose that focus.


Hopefully, the issue will be resolved soon. But for now, we hope that that the tutorial was useful to you.


For more video tutorials about NativeScript, look at our courses on NativeScripting.com. If you are interested in learning about DataForm beyond the basics, we go pretty deep into creating custom editors in the NativeScript with Angular Pro course.


Let me know if you enjoyed this short tutorial on Twitter: @digitalix or comment down below. You can also send me your NativeScript related questions that I can answer in video form. If I select your question to make a video answer, I'll send you swag. Use the hashtag #iScriptNative.



Alex lives in Washington, DC. He's a speaker, trainer, and a Telerik Developer Expert. He's been invloved in NativeScript projects since 2015 and has created courses for Pluralsight, LinkedIn, and Coursera.

Did you enjoy this? Share it!

Take control of your career. Build JavaScript mobile apps.