NativeScript & Vue.JS

RadDataForm Editors

If you followed the getting started section, you now know how to edit an object's properties with RadDataForm for NativeScript. This article will explain how to change the editor that is used for a property, what editors are supported by RadDataForm and how to use them.

Figure 1: Some of the editors supported by RadDataForm on Android (left) and iOS (right)

NativeScriptUI-DataForm-Editors-Android NativeScriptUI-DataForm-Editors-iOS

Usage

By default, RadDataForm will load a default editor depending on the type of each property of the source object. If you need to change the type, you can provide another editor through HTML or code-behind. This is demonstrated in the following examples:

Example 1: Change the editor that is used for a property

import { TicketOrder, getMovies, Movie, MovieConverter } from '../data';

const description = 'Editors';
const movies = getMovies();

export default {
  name: 'Editors',
  description: description,
  template: `
  <Page>
    <ActionBar :title="title">
      <NavigationButton text="Back" android.systemIcon="ic_menu_back" @tap="onNavigationButtonTap"></NavigationButton>
    </ActionBar>
    <RadDataForm
      :source="ticket"
      :metadata="ticketMetadata">
    </RadDataForm>
  </Page>
  `,
  data () {
    return {
      title: description,
      ticket: new TicketOrder(),
      ticketMetadata: {
        'isReadOnly': false,
        'commitMode': 'Immediate',
        'validationMode': 'Immediate',
        'propertyAnnotations':
        [
          {
            'name': 'movie',
            'displayName': 'Movie Name',
            'index': 0,
            'editor': 'Picker',
            'valuesProvider': movies.map((value: Movie) => value.name),
            'converter': new MovieConverter(movies),
          },
          {
            'name': 'date',
            'displayName': 'Date',
            'index': 1,
            'editor': 'DatePicker',
          },
          {
            'name': 'time',
            'displayName': 'Time',
            'index': 2,
            'editor': 'TimePicker',
          },
          {
            'name': 'type',
            'displayName': 'Type',
            'index': 3,
            'editor': 'SegmentedEditor',
            'valuesProvider': ['2D', '3D'],
          },
          {
            'name': 'price',
            'displayName': 'Price',
            'index': 4,
            'editor': 'Decimal',
            'readOnly': true,
          },
          {
            'name': 'numberOfTickets',
            'displayName': 'Number Of Tickets',
            'index': 5,
            'editor': 'Stepper',
            'editorParams': {
              'minimum': 0,
              'maximum': 20,
              'step': 2,
            }
          },
          {
            'name': 'contactName',
            'displayName': 'Contact Name',
            'index': 6,
            'editor': 'Text',
          },
          {
            'name': 'contactPhone',
            'displayName': 'Contact Phone',
            'index': 7,
            'editor': 'Phone',
          },
          {
            'name': 'contactEmail',
            'displayName': 'Contact Email',
            'index': 8,
            'editor': 'Email',
          },
          {
            'name': 'agreeTerms',
            'displayName': 'I Agree with Terms',
            'index': 9,
            'editor': 'Switch',
          },
        ]
      }
    };
  },
  methods: {
    onNavigationButtonTap() {
      Frame.topmost().goBack();
    },
  }
};

Note that the valuesProvider property will be taken into consideration only for editors that support predefined list of values. These editors are Picker, SegmentedEditor, List and AutoCompleteInline. You can read more about the providers here.

Converters

In the example in the beginning of the article the valuesProvider of the EntityProperty was set to an array of strings and the value of the property of the source object that was edited was also of type string. In some scenarios you will need to save a value which differs from the one that an editor displays. Consider the following example where you have a class Movie with two properties - name and id. If you want to save the value of the id and also display the value of the name in an editor, you can create a converter that will convert between the two values. Here's a sample implementation of the aforementioned scenario:

Example 3: Use a converter to change the type of the editor value before it is saved in the source object

The following example is written in TypeScript:

export class Movie {
  public id: number;
  public name: string;

  constructor(id: number, name: string) {
      this.id = id;
      this.name = name;
  }
}

export class MovieConverter implements PropertyConverter {
  constructor(private _movies: Array<Movie>) { }

  convertFrom(id: number) {
      return this._movies.filter((movie: Movie) => movie.id === id)[0].name;
  }

  convertTo(name: string) {
      return this._movies.filter((movie: Movie) => movie.name === name)[0].id;
  }
}

export const getMovies = () => {
  let movies = new Array<Movie>();
  movies.push(new Movie(123, 'Zootopia'));
  movies.push(new Movie(217, 'Captain America'));
  movies.push(new Movie(324, 'The Jungle Book'));
  return movies;
};

As you can see in the Movie model you can have a property of type number which represents the id of a movie which gets converted to the name of the movie with the same id. Similarly, when an item is selected from the list, its name is converted to the id which is the value that gets committed to the source object. An instance of the created converter has to be set to the converter property of the EntityProperty object.

Additional Parameters

The Stepper and Slider editors have additional properties which you can be setup through PropertyEditorParams. The following example of the Stepper editor shows how to limit its bounds and define its step:

Example 4: Use editor params to adjust an editor

import { TicketOrder, getMovies, Movie, MovieConverter } from '../data';

const description = 'Editors';
const movies = getMovies();

export default {
  name: 'Editors',
  description: description,
  template: `
  <Page>
    <ActionBar :title="title">
      <NavigationButton text="Back" android.systemIcon="ic_menu_back" @tap="onNavigationButtonTap"></NavigationButton>
    </ActionBar>
    <RadDataForm
      :source="ticket"
      :metadata="ticketMetadata">
    </RadDataForm>
  </Page>
  `,
  data () {
    return {
      title: description,
      ticket: new TicketOrder(),
      ticketMetadata: {
        'isReadOnly': false,
        'commitMode': 'Immediate',
        'validationMode': 'Immediate',
        'propertyAnnotations':
        [
          {
            'name': 'movie',
            'displayName': 'Movie Name',
            'index': 0,
            'editor': 'Picker',
            'valuesProvider': movies.map((value: Movie) => value.name),
            'converter': new MovieConverter(movies),
          },
          {
            'name': 'date',
            'displayName': 'Date',
            'index': 1,
            'editor': 'DatePicker',
          },
          {
            'name': 'time',
            'displayName': 'Time',
            'index': 2,
            'editor': 'TimePicker',
          },
          {
            'name': 'type',
            'displayName': 'Type',
            'index': 3,
            'editor': 'SegmentedEditor',
            'valuesProvider': ['2D', '3D'],
          },
          {
            'name': 'price',
            'displayName': 'Price',
            'index': 4,
            'editor': 'Decimal',
            'readOnly': true,
          },
          {
            'name': 'numberOfTickets',
            'displayName': 'Number Of Tickets',
            'index': 5,
            'editor': 'Stepper',
            'editorParams': {
              'minimum': 0,
              'maximum': 20,
              'step': 2,
            }
          },
          {
            'name': 'contactName',
            'displayName': 'Contact Name',
            'index': 6,
            'editor': 'Text',
          },
          {
            'name': 'contactPhone',
            'displayName': 'Contact Phone',
            'index': 7,
            'editor': 'Phone',
          },
          {
            'name': 'contactEmail',
            'displayName': 'Contact Email',
            'index': 8,
            'editor': 'Email',
          },
          {
            'name': 'agreeTerms',
            'displayName': 'I Agree with Terms',
            'index': 9,
            'editor': 'Switch',
          },
        ]
      }
    };
  },
  methods: {
    onNavigationButtonTap() {
      Frame.topmost().goBack();
    },
  }
};

Editors List

You can find the list with all available editors here.

References

Related articles you might find useful: