Skip to content

Use AttributesView Control

AttributesView control is the most versatile component of NodeActa's built-in user interface. You can use AttributesView to display a single value or as many values as you want. AttributesView serves as universal edit box. It will display TextBox, NumberBox, DateTyme Picker, CheckBox, Image, RichTextBox, Label, HyperLink, etc by detecting the type of underlying value. You can also force the editor type.
The true power of AttributesView comes into play when you need to display more than one value. It shines especially when you need to display hundreds or thousands of values ​​at once. Building a page layout with too many controls will make it extremely slow. On the other hand, displaying thousands of values ​​within a single AttributesView doesn't make much of a difference in performance compared to displaying a dozen or so. A good example is a built-in app for Localization. There we use a single AttributesView to display thousands TextBoxes at once quite efficiently. Also, you can see how to use AttributesView in Samples->UI Controls Sample app.

Initialize AttributesView

To initialize a AttributesView you have to set AttributesView.source property. Value can be a record, attributes, or simple values.

Initialize With Attributes

Using one or more Attributes is the most flexibile way you can use AttributesView. You can build very complex layouts using Attribute, AttributeButton, AttributeHorizontalSplit, AttributeImage, AttributePanel, AttributeSheet, AttributeSpace and AttributeText.

Display a single attribute
this.currencyEditor = new AttributesView(myPage);
this.currencyEditor.width = '200';   // 100 pixels width
this.currencyEditor.height = '1ch';  // 1 character height as we are displaying a single value
this.currencyEditor.source = new Attribute( {  
    type: AttributeValueType.Currency, 
    formatDisplay: '$ ,0.00',
    value: 55.90
} );
// to read attribute value do
let val = this.currencyEditor.source.value;
// to change attribute value do
this.currencyEditor.source.value = 33.49;
var myName = 'NODEACTA';
var myLabel = 'NodeActa';
var myType = 'W';
var myReplication = false;
...
this.attributesView.source = [
    new AttributePanel( { caption: 'Name & Label' }, [
        new Attribute( { 
            label: L`Name`, 
            value: (atr)=> myName, 
            setValue: (atr, val)=> myName = val } ),
        new Attribute( { 
            label: L`Label`, 
            value: (atr)=> myLabel, 
            setValue: (atr, val)=> myLabel = val } ),
        new Attribute( { 
            label: L`Type`, 
            value: (atr)=> myType, 
            setValue: (atr, val)=> myType = val,
            values: [
                new AttributeValue('W', 'Working'), 
                new AttributeValue('A', 'Archive'), 
                new AttributeValue('B', 'Backup') 
            ] } )
    ]),
    new AttributeSpace(),
    new AttributePanel( { caption : L`Options` }, [
        new AttributeText( {   
            label: L`Grantees Replication allows records in the storage to have security.`, 
            font: { size: 8, style: { italic: true } } } ),
        new Attribute( { 
            label: L`Grantees Replication`, 
            type: AttributeValueType.Boolean, 
            value: (atr)=> myReplication, 
            setValue: (atr, val)=> myReplication = val } ) 
    ])
];

attributesview-sample1

Initialize With Record

In NodeActa you will usually have your data in the form of a certain document class record. If you initialize the source property with a record, AttributesView will try the following:

  1. Check if you initialized AttributesView.fields property. Control will display only listed fields from the record.
  2. Check if you initialized AttributesView.layout property. Control will use this property to construct control's layout and find matching record field values to display in that layout. Your Attribute.name property must match record's field or field name.
  3. Check if record's data class has a defined Layout. If layout exists, the control will use it.
  4. If layout and fields properties are not set and data class does not have layout defined, AttributesView will display all record's fields with Attribute flag in its Visibility property (see Default Visibility option in Class Designer).

If you want to display a single value for example, before setting source property, you must initialize layout or fields property like this:

Display customer name in AttributesView
let purchases = await Purchase.where(...some condition...).selectAsync();
let purchase = purchases[9];
...
this.attributesView.fields = [Purchase.customer];
this.attributesView.source = purchase;
Display calculated value in AttributesView
...
const nameAndPlace = {
  type: AttributeValueType.String,
  value: (p) => {
    return p.name + ' ' + p.place;
  }
};

this.attributesView.fields = [nameAndPlace];
this.attributesView.source = purchase;

Hint

See Attribute for all possible properties nameAndPlace can have.

You can construct very complex layouts and still use a record as source. You must only ensure that your Attribute.name property matches record's field or field name.

Record and Layout
this.attributesView.layout = [
        new AttributePanel( { caption: 'Name & Address' }, [
            new Attribute( { name: Purchase.customer } ),
            new Attribute( { name: Purchase.customerAddress } )
        ] ),
        new AttributePanel( { header: false }, [
            new AttributeText( { 
                label: L`Some static text you want to display.`, 
                font: { size: 8, style: { italic: true } } } ),
            new Attribute( { name: Purchase.purchaseDate } ),
            new Attribute( { name: Purchase.amount })
        ] )
    ];

this.attributesView.source = purchase;

Hint

If you initialize Attribute.name property with a field object like Purchase.customer, it will automatically populate the type, label, defaultValue, values (for lookup fields), formatDisplay, formatEdit, as well as default width and height (if specified) based on the field definition. You can still provide these properties, which will override the default values.

Initialize With Simple Values

Only setting the source property to a certain value can be enough to initialize AttributesView. The control will detect the type of the value and display required editor. Problem starts when your value is undefined or null, because control will not be able to decide which editor to display.

...
this.attributeView.source = 'some text';

// reading changed value is only possible like
var newVal = this.attributeView.focused?.value;

Warning

We highly recommend NOT to use this method, unless you just want to display some values.

Default Data Class Layout

As mentined above, if you just initialize AttributeView.source property only with a record and you don't set fields and layout, AttributeView will use record's data class layout (if defined). Default layout for a data class can be designed using class designer like in the picture below. You can write layout code directly in code editor, or use the designer.

dataclassdesigner-layout

Hint

Please do not confuse this designer with the page layout designer. Both designers have similar available controls, but they are not the same.