kth-node-formlib

3.0.10 • Public • Published

kth-node-formlib

Render Bootstrap 3 style forms for Express.js using isomorphic-schema definitions.

install

npm install kth-node-formlib

i18n

If you don't implement i18n support forms will be renderedª with english labels. To use your app specific translations you need to create and register a ITranslationUtil with a single method message(i18nlabel, lang). Add the following code:

const registry = require('component-registry').globalRegistry
const createUtility = require('component-registry').createUtility
const { ITranslationUtil } = require('kth-node-formlib').interfaces
// You can choose a different i18n package
const i18n = require('kth-node-i18n')

createUtility({
  implements: ITranslationUtil,
  // If your i18n package has a different implementation you might need to write
  // some glue code to call it properly. The message method is called with the params
  // message(i18nlabel, lang)
  message: i18n.message.bind(i18n)
}).registerWith(registry)

Browser Javascript

In order for HTML-editor and list fields to work properly you need to add two javascript files to your browser code. If you want to create custom behaviour or use other libraries, just take a look at the included files and implement your own solution.

List Field

Initialise to fire up the add and remove button handlers, and add drag'n'drop support using dragula.

NOTE: You need to include dragula.js separately for this to work.

var $ = require('jquery')
var listField = require('kth-node-formlib/lib/browser/ListField')

$(function () {
  listField.init()
})

To clean up event handlers etc. Call listField.cleanup()

HTML Area Field with CK Editor

Initialise the ckeditor by implementing this code. The code will detect if there are HTML Area Field widgets on the page and 1) load ck editor on demand; 2) initialise ck editor on these <textarea>-fields. This code also adds a dirty check using the exposed list of ck editor instances.

var $ = require('jquery')

var ckeditorSetup = require('kth-node-formlib/lib/browser/ckeditor')

// Add the path to your ck editor root
var ckeditorBasepath = '/static/js/ckeditor/'

$(function () {
  ckeditorSetup.init({
    ckeditorBasepath: ckeditorBasepath,
    ckeditorOptions: {
      // Add your ck editor options
    }
  })

  var doCheckDirty = function (event) {
    // Check each instance to see if it is dirty
    var isDirty = ckeditorSetup.ckeditorInstances.reduce(function (prev, editor) {
      return prev || editor.checkDirty()
    }, false)
    if (isDirty) {
      // try set custom message if browser supports it
      var msg = 'Are you sure you want to discard your edits?'
      event.returnValue = event.originalEvent.returnValue = msg
      return msg
    }
  }
  var doDisableDirtyCheck = function () {
    // disable beforeunload if submitting form
    $(window).off('beforeunload')
  }

  // Check if editor is dirty
  $(window).on('beforeunload', doCheckDirty)

  // Remove dirty check on submit
  $(document).on('submit', 'form', doDisableDirtyCheck)
})

Basic form rendering

Rendering a form without handlebar helpers:

formpage.handlebars

<html>
    <body>
        <form method="post" action="{{cancelUrl}}">
            {{{formFieldsHTML}}}
            <div class="pull-right">
                <a class="cancel" href="{{cancelUrl}}">Cancel</a>
                <button type="submit">Save</button>
            </div>
        </form>
    </body>
</html>

formCtrl.js

const Schema = require('isomorphic-schema').Schema
const formSchema = new Schema({...})
const formlib = require('kth-node-formlib')

function formPage (req, res, next) {
    const didSubmit = req.method === 'POST'

    // bodyParser converts nested forms to object hierarchy but we need to
    // convert to proper datatypes prior to validation, the last bool param
    // tells transform to keep readOnly props which are needed if we want
    // to display the form with errors without readOnly fields being left empty
    const formData = formSchema.transform(req.body, undefined, true)
    
    // Validate the input
    const errors = formSchema.validate(formData)

    // Transform input to proper data structure
    const data = formSchema.transform(formData)

    // On successful submit, store the data
    if (didSubmit && !errors) {
        yourDataUpdateMethod(data)
        return res.redirect(200, '/success/url')
    }

    // Render the form fields
    const formFieldsHTML = formlib.renderFields({
        data: data,
        errors: errors,
        lang: 'en',
        submitted: didSubmitt
    })

    // Render the form page
    res.render('formpage', {
        lang: 'en',
        actionUrl: '', // Post to self
        cancelUrl: '/some/path',
        formFieldsHTML: formlib.renderFields
    })

Rendering using Handlebars view helper

Add the following code to your project to register Handlebars helpers:

const Handlebars = require('handlebars')
const registerFormlibHandlebarHelpers = require('kth-node-formlib').registerHandlebarHelpers
registerFormlibHandlebarHelpers(Handlebars)

Now you will get the formlib Handlebars view helpers (described further down) allowing you to write:

formpage.handlebars

<html>
    <body>
        <form method="post" action="{{cancelUrl}}">
            {{formfields formOptions lang}}

            {{formsave cancelUrl lang}}
        </form>
    </body>
</html>

formCtrl.js

const Schema = require('isomorphic-schema').Schema
const formSchema = new Schema({...})
const formlib = require('kth-node-formlib')

function formPage (req, res, next) {
    const didSubmit = req.method === 'POST'

    // bodyParser converts nested forms to object hierarchy but we need to
    // convert to proper datatypes prior to validation, the last bool param
    // tells transform to keep readOnly props which are needed if we want
    // to display the form with errors without readOnly fields being left empty
    const formData = formSchema.transform(req.body, undefined, true)
    
    // Validate the input
    const errors = formSchema.validate(formData)

    // Transform input to proper data structure
    const data = formSchema.transform(formData)

    // On successful submit, store the data
    if (didSubmit && !errors) {
        yourDataUpdateMethod(data)
        return res.redirect(200, '/success/url')
    }

    // Render the form page
    res.render('formpage', {
        lang: 'en',
        actionUrl: '', // Post to self
        cancelUrl: '/some/path',
        formOptions: {
            submitted: req.method === 'POST',
            formSchema: formSchema,
            data: data,
            errors: errors
        }
    })

formfields

{{formfields formOptions lang}}

formOptions = {
    submitted: req.method === 'POST', // Used to only show errors on submitt (normally a POST)
    formSchema: formSchema,
    data: pageData,
    errors: errors // The result from formSchema.validate(pageData), undefined if no errors
}
lang = 'en' // Passed to fields and used for error message rendering

formsave

Form save uses action url in form for post and cancelUrl when clicking cancel.

{{formsave cancelUrl lang}}

cancelUrl = '/path/to/cancel'
lang = 'en'

TODO: Add test for async form fields generation TODO: Add async form docs to README DONE: Register i18n utility with component registry TODO: Get browser include to work with dev-package (currently fails on babel, work around is to copy files in .../browser to project) https://github.com/babel/babel-loader/blob/master/README.md#the-node-api-for-babel-has-been-moved-to-babel-core

Readme

Keywords

none

Package Sidebar

Install

npm i kth-node-formlib

Weekly Downloads

10

Version

3.0.10

License

MIT

Unpacked Size

149 kB

Total Files

52

Last publish

Collaborators

  • kth-stratus
  • mictsi
  • n_sandstrom
  • kthwebmaster
  • exacs
  • ssundkvist
  • kth-ci
  • emilstenberg