Toolkit

TK.Form

Form builder

Automatically create a form based on an object

{
    _: TK.Form,
    Model: {
        Name: "Duck",
        Active: true,
        Age: 5
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

Field settings

{
    _: TK.Form,
    SaveButtonText: "Woop",
    Model: {
        Name: "",
        Active: true,
        Age: 5,
        From: "2018-04-27",
        Id: 99
    },
    Fields: {    
        // Setting a type or display name
        From: { Type: "date", DisplayName: "Active From" },

        // Marking a field as required
        Name: { Required: true, PlaceHolder: "Name here" },

        // Hide the ID field (Original result will still be available in the saved model)
        Id: { Type: "ignore"},

        // Using a custom template
        Age: {
            Template: {
                _: "span",
                Init: function() {
                    this.Elements.NumberInput.value = this.Data;
                },
                GetValue: function () {
                    return parseFloat(this.Elements.NumberInput.value);
                },
                Elements: {
                    NumberInput: {},
                    AddButton: {
                        innerHTML: "+",
                        type: "button",
                        onclick: function() {
                            this.Near("NumberInput").value =
                                parseInt(this.Near("NumberInput").value) + 1;
                        }
                    }
                }
            }
        }
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

Sub forms

Single sub form

{
    _: TK.Form,
    Model: {
        Name: "Duck",
        Food: {
            Name: "Donuts",
            Amount: 20
        }
    },
    Fields: {
        Food: {
            Type: "form",
            Fields: {
                Name: { 
                    Required: true, DisplayName: "Name of the food"
                }
            }
        }
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

Array

{
    _: TK.Form,
    Model: {
        Name: "Duck",
        Active: true,
        Age: 5,
        Food: [
            { Name: "Grass", Amount: 5 },
            { Name: "Donuts", Amount: 2 }
        ]
    },
    Fields: {
        Food: {
            Type: "forms",
            NewItem: { Name: "", Amount: 0 },
            AddButtonText: "ADD!", // Default: Add
            RemoveButtonText: "REMOVE!", // Default: Remove
            Fields: {
                Name: { Required: true, DisplayName: "Name of the food" }
            }            
        }
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

Auto Save

This executes the save callback when there is any potential change.

{
    Elements: {
        Form: {
            _: TK.Form,
            AutoSave: true,
            SaveButtonText: null, // Hide the normal save button
            Model: {
                Name: "Duck",
                Active: true,
                Age: 5
            },
            Save: function(newModel) {                
                this.Near("Status").innerHTML = "Name is now: " + newModel.Name;
            }
        },
        Status: {}
    }
}

Javascript Events and ajax combo box

The selectable options can be retrieved using ajax. This will be done once during exection and cached for any other form elements using this Url. It is also possible to add onchange / onblur / onfocus events to most fields.

{
    Elements: {
        Form: {
            _: TK.Form,
            Model: {
                Name: "Pink Banana",
                Active: true,
                Age: 5
            },
            Fields: {
                Name: {
                    Type: "ajaxselect",
                    Url: "ExampleData.txt",
                    GetName: function(a) { return a.Description; }, // Default: a.Name
                    GetValue: function(a) { return a.Description; }, // Default: a.Id
                    ValueIsText: true,
                    onchange: function() {
                        alert(this.value);
                    }                    
                },
                Age: {
                    onfocus: function() {
                        this.value = 123;
                    },
                    onblur: function() {
                        this.value = 456;
                    }
                }
            }
        }
    }
}

Styling options

When using the SortByFields setting, the fields will be added in the order of the Fields setting. This also enables the use of sections which will create html fieldsets and allows adding other (non-field) elements in between.

{
    _: TK.Form,
    SortByFields: true,
    Model: {
        FirstName: "",
        LastName: "",
        Street: "",
        Postcode: "",
        City: "",
        Country: ""
    },
    Fields: {    
        FirstSection: { Type: "section", DisplayName: "Name"},        
        FirstName: { Required: true,DisplayName: "First Name", Inline: 1 },
        LastName: { Required: true, DisplayName: "Last Name", Inline: 1 },

        SecondSection: { Type: "section", DisplayName: "Address"},
        Desc: { _: "p", innerHTML: "Please fill in your address below"},
        Street: { Required: true, DisplayName: "Street", Width: "300px" },
        Postcode: { Required: true, DisplayName: "Postcode", Inline: 1, Width: "100px" },
        City: { Required: true, DisplayName: "City", Inline: 1 },
        Country: {  Required: true,  Type: "select", ValueIsText: true, Options: [
            { Text: "- Please select -", Value: "" },
            { Text: "Netherlands", Value: "NL" },
            { Text: "United Kingdom", Value: "UK" },
        ]}

    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

It is also possible to use the property .LabelWidth (both on field as form) to place the labels on the left side of fields.

{
    _: TK.Form,
    LabelWidth: 200,
    Model: {
        FirstName: "",
        LastName: "",
        AllowContact: false
    },
    Fields: {    
        FirstName: { Required: true,DisplayName: "First Name" },
        LastName: { Required: true, DisplayName: "Last Name" },
        AllowContact: { DisplayName: "Allow contact", Type: "switch", TextBefore: "No", TextAfter: "Yes" }
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

Dynamic sub form

A field can be linked to another field. When the other field changes, the linking field will be cleared and Init in the template will be called again. The property LinkedData is filled with the value of the linked field.

{
    _: TK.Form,
    Model: {
        Country: "",
        Custom: ""
    },    
    Fields: {
        Country: { 
            Required: true, Type: "select", ValueIsText: true, 
            Options: [
                { Text: "- Please select -", Value: "" },
                { Text: "Netherlands", Value: "NL" },
                { Text: "United Kingdom", Value: "UK" },
            ]
        },
        Custom: {            
            LinkField: "Country",
            Template: {       
                _: "input",         
                
                Init: function() {
                    if (!this.LinkedData) {
                        this.value = "Nothing selected";
                    } else {
                        this.value = "You selected " + this.LinkedData + "!";
                    }
                },
                GetValue: function() {
                    return this.value;
                }
            }        
        }
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

IsVisible function to control if a field should be visible or not

The IsVisible method is called at Init and whenever the 'onchange' is called by any of the fields.

{
    _: TK.Form,
    Model: {
        Name: "Duck",
        ShowAge: false,
        Age: 5
    },
    Fields: {
        ShowAge: {
            DisplayName: "Show age field"
        },
        Age: {
            IsVisible: function(model) {
                // Return true if this field should be visible
                // Return false to hide it
                return model.ShowAge;
            }
        }
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

By using the form field type and the LinkSettings property, it is possible to dynamically change the form based on the value of the linked field.

{
    _: TK.Form,
    Model: {
        ContactType: "Personal",
        ContactDetails: null
    },    
    Fields: {
        ContactType: { 
            Required: true, Type: "select", ValueIsText: true, 
            DisplayName: "Contact Type",
            Options: [
                { Text: "Personal", Value: "Personal" },
                { Text: "Business", Value: "Business" },
            ]
        },
        ContactDetails: {            
            Type: "form",
            DisplayName: "Contact Details",
            LinkField: "ContactType",
            LinkSettings: {
                Personal: {
                    DefaultModel: { Name: "", Address: "", City: "" }
                },
                Business: {
                    DefaultModel: { ContactPerson: "", Name: "", Address: "", City: "" },
                    Fields: {
                        ContactPerson: {
                            DisplayName: "Contact person"
                        },
                        Address: {
                            DisplayName: "Address main office"
                        }
                    }
                }
            }       
        }
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

Custom validation

Assign a custom validation function to do extra validations. The result needs to be passed by calling the given callBack function. This allows for ajax requests.

{
    _: TK.Form,
    Model: {
        Name: "Duck",
        Active: true,
        Age: 5
    },
    CustomValidation: function(newModel, callBackResult) {
        if (newModel.Age < 10)
            callBackResult(["At least 10 years or older!"]);
        else
            callBackResult(); // OK
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}

Custom error display

{
    _: TK.Form,
    Model: {
        Name: "",
        Active: true,
        Age: 5
    },
    Fields: {
        Name: {
            Required: true
        }
    },
    RenderErrors: function(errors, textBefore) {
        TK.Toast.Create("Could not save form", textBefore + ": " + errors.join(", "));
    },
    Save: function(newModel) {
        alert(JSON.stringify(newModel));
    }
}