Working with forms in Griffin.Yo – A Spa library in TypeScript

I’ve pushed a new release that includes a form reader. With a few lines of code you can get a complete JSON object, including hierarchy from a HTML form.

When building a spa you typically do not want forms to be submitted as a regular http request, as it would defeat the purpose of a spa. As you already work with ajax and JSON, why not use it for form submissions too? It’s now possible in Griffin.Yo.

Start by declaring a simple form:

<form id="MyForm">
    <div>
        <label>First name:</label>
        <input name="FirstName" value="Jonas">
    </div>
    <div>
        <label>Last name:</label>
        <input name="LastName" value="Gauffin">
    </div>
</form>

Reading it is done with the FormReader class:

var form = new FormReader("MyForm");
var dto = form.read();

// .. or in your view model:
var dto = ctx.readForm("MyForm");

The returned result is a json document:

{
    "FirstName": "Jonas",
    "LastName": "Gauffin"
}

Radio buttons

Radio buttons are only appended to the JSON document if they are checked, i.e. all other options are ignored:

<form id="MyForm">
    <label>Mood</label>
    <input type="radio" name="Mood" value="Rocking"> Rocking
    <input type="radio" name="Mood" value="Tired" checked> Tired
    <input type="radio" name="Mood" value="Excited"> Excited
</form>

.. results in ..

{
    "Mood": "Tired"
}

Check boxes

The same applies for check boxes:

<form id="MyForm">
    <label>Moods</label>
    <input type="checkbox" name="Moods" value="Rocking"> Rocking
    <input type="checkbox" name="Moods" value="Tired" checked> Tired
    <input type="checkbox" name="Moods" value="Excited" checked> Excited
</form>

.. results in ..

{
    "Moods": ["Tired", "Excited"]
}

.. which is great since we get an array back.

Collections

Collections are typically difficult to handle in HTML forms, as there is nothing in the HTML specification that states how they should be handled. In this implementation they are represented by the “data-collection” attribute.

If you are working with collections that have a single value you use the special input name “[]” to indicate that. Example follows:

<form id="MyForm">
    <div data-collection="Brands">
        <label>Your favorite brands</label>
        <p>In reality you and new inputs using javascript and a button. Just imagine that it's been done here.</p>
        <input name="[]" value="Headlight" />
        <input name="[]" value="OneTrueError" />
        <input name="[]" value="Griffin.Framework" />
    </div>
</form>

Which results in:

{
    "Brands":["Headlight","OneTrueError","Griffin.Framework"]
}

But if your collection contains complex objects you simply specify the name of the items:

<div data-collection="Addresses">
    <label>Enter your addresses</label>
    <input name="Street" value="Here1" />
    <input name="City" value="Falun" />
    <input name="Street" value="Here2" />
    <input name="City" value="Stockholm" />
</div>

Each new item is automatically created when the same input name is repeated. Thus as long as you have all inputs in the same order it works pretty excellent.

Result:

{
    "Addresses": [{
        "Street": "Here",
        "City": "Falun"
    }, {
        "Street": "Here2",
        "City": "Stockholm"
    }]
}

Complex objects

Same thing goes for complex objects. There is nothing in the HTML spec. With this library you have two options.

The first option is to include a <div data-name="SubObjectName"> to wrap the sub object:

<form id="MyForm">
    <div>
        <label>First name:</label>
        <input name="FirstName" value="Jonas">
    </div>
    <div>
        <label>Last name:</label>
        <input name="LastName" value="Gauffin">
    </div>
    <div data-name="Address">
        <h2>Address</h2>
        <label>Street:</label>
        <input name="Street" value="Awesome street"><br>
        <label>Postal code:</label>
        <input name="PostalCode" value="12345"><br>
        <label>City:</label>
        <input name="City" value="Falun"><br>
    </div>
</form>

.. which would generate the following JSON:

{
    "FirstName": "Jonas",
    "LastName": "Gauffin",
    "Address": {
        "Street": "Awesome street",
        "PostalCode": 12345,
        "City": "Falun"
    }
}

The second options is to use dot notation in the input names:

 <div>
    <h2>Address</h2>
    <label>Street:</label>
    <input name="Address2.Street" value="Awesome street"><br>
    <label>Postal code:</label>
    <input name="Address2.PostalCode" value="12345"><br>
    <label>City:</label>
    <input name="Address2.City" value="Falun"><br>
</div>    

.. which will give you the same result.

Value handling

All values are parsed. For instance the string values “true” and “false” are converted to a JSON bool. Strings containing numbers are converted to JSON numbers. Everything else is treated as a strings.

Summary

The code is available at github.

Questions? Missing a feature? Write a comment.

  • vicky kumar

    Is it helpful if we are using angularjs
    What if we have some optional field in our html and we want to create dynamic json where json should have entry only for those fields which is filled by user.
    For example if user has not filled mobile number then there should not be any object related to mobile rather then having mobile:””

    • Fields which are empty will not be included in the generated JSON.

      If it´s helpful in Angular is up to you to decide.