Git Product home page Git Product logo

winterfell's Introduction

Winterfell

Generate complex, validated and extendable JSON-based forms in React

Winterfell allows you to build up complex, multi-page forms with conditional questions, validation and conditional-page switching via a JSON schema, rendered by React.

Winterfell was initially made for a project in a sector that required a large, complex form with questions that would result in more questions or different pages when you clicked next. With an easy to write schema and a high level of customisation, comes a great power.

View Demo - Follow me on Twitter

Usage

First install Winterfell via npm

$ npm install winterfell --save

Winterfell uses a JSON schema to render your form. We will go through that later.

var Winterfell = require('winterfell');
var schema     = require('./schema');

React.render(
  <Winterfell schema={schema} />,
  document.getElementById('form')
);

Features

  • Easy, quick and extendable
  • JSON schema
  • Design agnostic and customisable
  • Multi-page forms
  • Infinitely-recursive conditional questions
  • Conditional page switching
  • Conditional form submitting
  • Disable regular submissions
  • Instant form validation
  • Decide when to validate per field
  • Validation against other fields values
  • Predefined validation types
  • Predefined error messages
  • Custom validation types
  • Custom error messages
  • Custom error rendering
  • Custom required asterisk rendering
  • Custom classes
  • Custom InputTypes
  • Question pre and post text
  • Question panel header and text
  • Question set header and text
  • Ability to disable buttons
  • Default values
  • Events

Schema

The schema is built up of three main parts, formPanels, questionPanels and questionSets.

Form Panels

The initial formPanels entry is used as a page of questions, or questionPanels in Winterfell's case.

{
  "formPanels": [
    {
      "index": 1,
      "panelId": "intro-panel"
    },
    {
      "index": 2,
      "panelId": "register-panel"
    },
    {
      "index": 3,
      "panelId": "final-panel"
    }
  ]
}

Question Panels

Question Panels are the fleshed-out details about a page of questions. We defined the questionSets that exist on this page, any conditions for submitting the panel and button information. You should have one of these for every panel defined in formPanels above.

Each questionPanel has the ability to have a header and some text along with it that is displayed above the questions. You can define these via the panelHeader and panelText fields.

Supported actions are GOTO and SUBMIT. When using GOTO, the target can be any questionPanelId. SUBMIT places the target in to the action field of the form element.

{
  "questionPanels": [
    {
      "panelId": "intro-panel",
      "panelHeader": "A quick survey?",
      "panelText": "Please could you take a few minutes to fill out our survey?",
      "action": {
        "conditions": [
          {
            "questionId": "existing-user",
            "value": "no",
            "action": "GOTO",
            "target": "register-panel"
          }
        ],
        "default": {
          "action": "GOTO",
          "target": "final-panel"
        }
      },
      "button": {
        "text": "Next",
        "disabled": false
      },
      "": {
        "text": "Back",
        "disable": false
      },
      "questionSets": [
        {
          "index": 1,
          "questionSetId": "intro-set"
        }
      ]
    }
  ]
}

Question Sets

Questions Sets are groups of questions. Here is where you define questions with their validations, types, conditions etc. conditionalQuestions are recursive and will work as expected.

The questionSet below has an initial radio button with yes and no options. When you select yes, a question asking for the users email address will render.

Each question has the ability to have some text associated with it which gets rendered below the questions-label and some postText which will be rendered below the questions input.

{
  "questionSets": [
    {
      "questionSetId": "intro-set",
      "questionSetHeader": "I am a question set header",
      "questionSetText": "I am a question set text",
      "questions": [
        {
          "questionId": "existing-user",
          "question": "Are you an existing user?",
          "text": "We'd just like to know so we can get you in the right place.",
          "input": {
            "type": "radioOptionsInput",
            "default": "yes",
            "options": [
              {
                "text": "Yes",
                "value": "yes",
                "conditionalQuestions": [
                  {
                    "questionId": "register-user-email",
                    "question": "Please enter the email address your account is registered with",
                    "postText": "We will not spam your email address.",
                    "input": {
                      "type": "emailInput",
                      "placeholder": "Email Address"
                    },
                    "validateOn": "blur",
                    "validations": [
                      {
                        "type": "isLength",
                        "params": [
                          1
                        ]
                      }
                    ]
                  }
                ],
                "validations": [
                  {
                    "type": "isLength",
                    "params": [
                      1
                    ]
                  }
                ]
              },
              {
                "text": "No",
                "value": "no",
                "conditionalQuestions": []
              }
            ]
          }
        }
      ]
    }
  ]
}

The validateOn property is used to dictate when to validate the field. The default for this is blur, which results in the field being validated when the user unfocusses from the field. You can also set this field to change which will validate the field as the user types, or changes their answer. Setting validateOn to submit will result in the field being validated when the next or submit button being pressed and only then.

Validations are handled via the Validator package on npm. In the validations key item, you can set your types of validation for the field. The type must be a method on the Validator package, or a custom defined method.

A validation-items params key must be an array of parameters for the validation method. The value will be unshifted to the start of the array and called up on the validation method in order. For example:

Validation item where the value must be a minimum length of 1.

{
  "type": "isLength",
  "params": [
    1
  ]
}

Validation item where the value must be a minimum length of 1 and a maximum of 20.

{
  "type": "isLength",
  "params": [
    1,
    20
  ]
}

You can also add a custom error message for the questions validaton item by using the message property.

{
  "type": "isLength",
  "params": [
    1
  ],
  "message": "Please select an option"
}

To validate a questions answer against another questions answer, you can wrap curly-braces around a parameter in the params property and it will be turned in to a questions answer. For example:

{
  "type": "equals",
  "params": [
    "{password}"
  ],
  "message": "Confirm Password must match the Password field"
}

HTML Classes

Winterfell allows you to define classes for the rendered form in multiple different areas. To use them, place them in the root of the form-schema like so:

{
  "formPanels": [],
  "classes": {
    "form": "form-wrapping-class",
    "label": "question-label"
  }
}

The table below describes the current set of classes.

Class Name Description
form The form element itself
questionPanels The div that wraps around the active questionPanel
questionPanel The div that wraps around the active questionSets and the button bar
questionPanelHeaderContainer The div that wraps around the questionPanels header text and text
questionPanelHeaderText The h3 tag that holds the questionPanel header text
questionPanelText The p tag that holds the questionPanel text
questionSetHeader The h4 tag that holds the questionSet header
questionSetText The p tag that holds the questionSet text
questionSetHeaderContainer The div that wraps around the header and text of a questionSet
questionSets The div that wraps around the questionSets inside of a questionPanel
questionSet The div that wraps around the questions inside a questionSet
question The div that wraps around the question
questionText The p tag that holds the question text
questionPostText The p tag that holds the question post-text
label Label inside of a question
backButton Panel-back button, shown when on a second panel
controlButton Typically the Next or Submit button, depending on panel
buttonBar The div wrapped around the buttons described above
errorMessage Error Message div class - Not used if custom renderError method used
input Assigned to the inputs for types textInput, textareaInput, emailInput and passwordInput
select Assigned to the selectInput select-element
file Assigned to the fileInput file-element
checkboxInput The div that wraps around the checkboxInput
checkbox Assigned to the checkboxOptionsInput and checkboxInput checkbox-input
checkboxList Assigned the to UL wrapped around the checkbox items in checkboxOptionsInput
checkboxListItem Assigned to the LI inside of the checkboxList mentioned above
checkboxLabel Assigned to the label inside of a checkbox option
radioList Assigned to the UL wrapped around the radio items in radioOptionsInput
radioListItem Assigned to the LI inside of the radioList mentioned above
radioLabel Assigned to the label inside of a radio button option
radio Assigned to the radio button inside of a radioOptionsInput

Default & Custom Input Types

The default set of input types that ships with Winterfell are the following:

  • textInput
  • textareaInput
  • emailInput
  • hiddenInput
  • fileInput
  • passwordInput
  • selectInput
  • checkboxInput
  • checkboxOptionsInput
  • radioOptionsInput

You can also define custom input types like so:

var Winterfell         = require('winterfell');
var MyAwesomeInputType = require('./awesomeInputType');

Winterfell
  .addInputType('myAwesomeInputType', MyAwesomeInputType);

// OR

Winterfell
  .addInputTypes({
    myAwesomeInputType : MyAwesomeInputType
  });

Custom Error Messages

Error messages can be set strings, or methods that are called to generate an error message. They can be set like so:

var Winterfell = require('winterfell');

Winterfell
  .addErrorMessage('isLength', 'Please enter some text!');

Winterfell
  .addErrorMessages({
  	isLength : (validationItem) => {
  	  /*
  	   * validationItem = {
  	   *   type   : 'isLength',
  	   *   params : [] //Starts with answer
  	   * }
  	   */

  	  return 'Please enter a value';
  	}
  });

Custom Validation Methods

Validation methods can be defined and will be chosen over methods defined in the Validator package.

var Winterfell = require('winterfell');

Winterfell
  .addValidationMethod('isLength', value => {
  	/*
  	 * arguments == validation parameters
  	 */

    return true; // Valid
  });

Winterfell
  .addValidationMethods({
  	isLength : value => {
  	  /*
  	   * arguments == validation parameters
  	   */

      return true; // valid
    }
  });

Props & Config

The following table shows the props Winterfell accepts, their types and descriptions. The only prop that is required is schema.

Prop Name Type Description
panelId string Initial panelId to render
schema object schema for the form to render
ref string ref field for form element
encType string encType field for the form element
method string method field for the form element
action string Default action field for the form element
disableSubmit boolean Prevent the form from submitting naturally
questionAnswers object Existing questionAnswers. questionId => answer
renderError function Custom validation error render method. Return a React Component Or React Element.
renderRequiredAsterisk function Custom require asterisk rendering method. Return a React Component or React Element.

Events

The following events can be registered as props of Winterfell.

Event Prop Description Arguments
onRender Fired when Winterfell has initially rendered N/A
onUpdate Fired when a questions answer has been changed questionAnswers
onSwitchPanel Fired when a panel is switched or changed panel
onSubmit Fired when the form is submitted successfully questionAnswers, action

Final Notes

Pull requests are completely welcome. If you'd like to get in touch, Tweet me. Initial schema design by Jordan Appleson.

License

MIT License (MIT)

Copyright (c) 2015 Andrew Hathaway, https://github.com/andrewhathaway/Winterfell

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

winterfell's People

Contributors

aethant avatar algm avatar andrewhathaway avatar bsdavidson avatar camerow avatar coreyonprem avatar gjk0090 avatar hcuppens avatar igor-yamshchykov avatar jbthummar avatar joshgeller avatar kascote avatar marcelometal avatar satishgadhave avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

winterfell's Issues

State leaks into prototype

When displaying two forms, I would expect both to be separated. Instead it seems that the state is shared.

How to reproduce
Insert two forms with the same schema into your page. Fill out the first and submit the second without any inputs. The second form will submit the inputs of the first form.

Possible solutions
I suspect that this is due to the way how default values are taken into the state. The constructor of the Winterfell class does this:

this.state = {
      schema          : schema,
      currentPanel    : currentPanel,
      action          : this.props.action,
      questionAnswers : this.props.questionAnswers
};

When initializing the form, the Winterfell.defaultProps are passed into the constructor. After the code above this.state.questionAnswers is the same object as Winterfell.defaultProps.questionAnswers. Every change to this state also causes the prototype to change. Every form, even if displayed one after another, shares the same questionAnswers.
Generating the default properties within the constructor instead of holding them statically on the class could help.

Possible workaround
Passing the questionAnswers as a property while holding them in the state of the surrounding component. And listening to any updates.

Multi-field validation

When validating a form, it would be convenient if there were a way to validate against multiple different fields. An example might be a date-range input with a start date and an end date. The form would be invalid if the end date came before the start date, even though both fields might be valid independently.

Enter key currently submits form

When focussed on an input, the enter key will submit the form (expected behaviour). However, if you have disabled submissions this should not be the case. It also submits the form on a panel that does not have a submission action, it should attempt to follow the action (IE: Next/Submit button click).

Reset form on submit

Is there a way to reset the form once it is submitted?

After I submit a form, I'm redirecting to another page. But, once I go to the form again, all the values previously typed in/selected(in case of radio buttons) are already present. I need the values to be cleared from the form.

Edit : I believe what I basically need is to refresh the questionAnswers object.

questionPanelText not getting custom classes

Hi!

I can't seem to get questionPanelText to actually set a className.

given this Schema:

 {
  classes : {
    input : 'Field-value',
    label : 'Field-label blank-u-mgBmd',
    select : 'Field-value',
    question : 'Field blank-u-mgBlg',
    questionPanel : '',
    questionPanelText : 'This one is not working',
    questionPanelHeaderText : 'Nor this one',
    questionText : 'blank-u-mgBlg',
    radioListItem : '',
    radioList : 'Field--paired',
    radioLabel: 'Field--paired-label',
    radio: 'Field-value',
    checkboxInput : 'Field-value',
    checkboxListItem : '',
    checkboxList : 'Field--paired',
    controlButton : 'Button Button--positive',
    backButton : 'Button Button--neutral',
    errorMessage : 'alert alert-danger',
    buttonBar : 'button-bar'
  },
  formPanels : [{
    index : 1,
    panelId : 'intro-panel'
  }],
  questionPanels : [{
    panelId : 'intro-panel',
    panelHeader : 'My Awesome Form',
    panelText : 'Play around, you might find some surprises depending on what you answer!',

the node from panelText or panelHeader doesn't get any className. Am I misunderstaning something? Other elements are correctly getting classes.

Thanks!

Compound Conditionals

Winterfell should support compound conditionals, IE answerOne == this && answerTwo == that, both in the questionPanel objects and the question objects.

I'm not exactly sure what the schema should be like for this, will spend some time thinking about it. Suggestions welcome.

Access form element dom node

Well so far unsuccessful to get how to manipulate the form.
Let's say you'd want to hide/remove your form after a successful submit
I guess that's pretty simple; but my Winterfell.getDOMNode()'s object remains undefined wherever I check it

Issues trying to modify package locally

Hello, I hope this makes some sense, I am a bit new to React and webpack.

I have a local clone of the repo I am trying to modify for my project. With a fresh copy of the repo, everything is okay and Winterfell renders properly.

However, when I modify one of the winterfell/src/*.js files, I start running into problems. After making changes and running npm run build I get these errors in the browser:

Warning: Winterfell(...): React component classes must extend React.Component.

Uncaught Error: Invariant Violation: Winterfell.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.

I am not making any breaking changes to the source files (I have tried very trivial changes), and Winterfell still extends from React.Component, I am not messing with the class definition.

Does anybody have any ideas what's causing this?

I am using react 0.14.0 in my project, would this matter?

Thanks in advance for any input!

`addValidationMethod[s]` not working

Hey!

I'm working on adding some custom validation. Here's my setup:

import React from 'react';
import Winterfell from 'winterfell';
import SignupSchema from '../forms/signup.js';
import 'moment';
import { default as isPhone } from 'is-phone-number';

export default class SignUpForm extends React.Component {
  constructor (props) {
    super(props);
    Winterfell.addValidationMethods({
      isPhoneNumber: value => isPhone(value)
    });
  }

It's throwing:

TypeError: _winterfell2['default'].addValidationMethods is not a function. (In '_winterfell2['default'].addValidationMethods', '_winterfell2['default'].addValidationMethods' is undefined)

and if I console.log(Winterfell)

function Winterfell(props) {
        _classCallCheck(this, Winterfell);

        _get(Object.getPrototypeOf(Winterfell.prototype), 'constructor', this).call(this, props);

        this.panelHistory = [];

        var schema = _.extend({
          classes: {},
          formPanels: [],
          questionPanels: [],
          questionSets: []
        }, this.props.schema);

        schema.formPanels = schema.formPanels.sort(function (a, b) {
          return a.index > b.index;
        });
        var panelId = typeof this.props.panelId !== 'undefined' ? this.props.panelId : schema.formPanels.length > 0 ? schema.formPanels[0].panelId : undefined;

        var currentPanel = typeof schema !== 'undefined' && typeof schema.formPanels !== 'undefined' && typeof panelId !== 'undefined' ? _.find(schema.formPanels, function (panel) {
          return panel.panelId == panelId;
        }) : undefined;

        if (!currentPanel) {
          throw new Error('Winterfell: Could not find initial panel and failed to render.');
        }

        this.state = {
          schema: schema,
          currentPanel: currentPanel,
          action: this.props.action,
          questionAnswers: this.props.questionAnswers
        };
      }

Do i need to import the validation utils from somewhere else?

Multi page forms - async validations and routes

With the built in multi-page forms functionality is there is a way to have async actions occur between steps (like server side validation - proceed to next step) and also any way to tie in routes to the steps? I'd also like to send new data to the next step from the previous async action.

I'm trying to decide whether I should continue to use the built in Multi page form or have separate forms and wire in all the advanced step logic and routes myself. I imagine this sort of logic would need to be tied to the schema so maybe it's just better to use separate forms for each step and not try to tackle this at a schema level.

hiddenInput value not set as expected

hiddenInput sets the default props as follows:

HiddenInput.defaultProps = {
name : undefined,
value : undefined
};

So this would appear to be the way to define a question for the hiddenInput
{
"questionId" : "func",
"question" : "",
"input" : {
"type" : "hiddenInput",
"name" : "hiddenname",
"value" : "hiddenvalue"
}
}

However the value prop does not make it into the rendered as this implies. Looking at the render method of question.js it appears as though moving the value property to the question might do what we want

var value = typeof this.props.value !== 'undefined'
              ? this.props.value
              : typeof this.props.input.default !== 'undefined'
                  ? this.props.input.default
                  : undefined;

This definition did not work either since the value prop of the questions comes from the questionAnswers prop on the set and that seems like a pretty convoluted way to set a simple hidden input.
{
"questionId" : "func",
"question" : "",
"input" : {
"type" : "hiddenInput",
"name" : "hiddenname",
}
"value" : "hiddenvalue"
}

There is a simple but not obvious workaround by setting the default prop on the input:

{
"questionId" : "func",
"question" : "",
"input" : {
"type" : "hiddenInput",
"name" : "hiddenname",
"default" : "hiddenvalue"
}
}

I am not sure if this should be seen as a documentation or a code issue. Perhaps an additional level in the Question Render command might be the easiest solution:

var value = typeof this.props.value !== 'undefined'
              ? this.props.value
              : typeof this.props.input.value!== 'undefined'
                  ? this.props.input.value
                  :  typeof this.props.input.default !== 'undefined'
                  ? this.props.input.default
                  : undefined;

Password confirmation not working

Hi, we are trying to add the password confirmation to the schema, but it doesn't seem like the two password fields talk to each other. We currently have it like following:

"validations" : [{
"type" : "isEmail"
}]
},{
"questionId" : "password",
"question" : "Password",
"input" : {
"type" : "passwordInput",
"placeholder" : "8 characters minimum",
"required" : true
},
// Make sure password is entered
"validations" : [{
"type" : "isLength",
"params" : [1]
}]
},{
"questionId" : "passwordConfirm",
"question" : "Password Confirm",
"input" : {
"type" : "passwordInput",
"placeholder" : "confirm password"
},
"validations" :[{
"type" : "equals",
"params" : ["12345678"]
//"matches" : "({passwordConfirm}, {password} )"
//"message" : "Confirm password must match password field"
}]
Thanks!

CheckboxInputOptions stores values from all checkbox questions

I am having an issue that when I have numerous questions that use the input type checkboxOptionsInput the checked answers are added the state including one from previous questions, thereby causing the answer to include all checked boxes from all of the different questions that use an checkboxOptionsInput.
I think it might be due to the fact that the constructor set the state to the props.value and when the state is updated it also resets the props.value.

Submit button does not submit on all versions of IE

I created a tool based on the form and when I do a submit in IE, I see that it is not submitting. Clicking enter works. It does not log any error to console.

It would be great if you can help in root causing the issue.

Specify transform in package.json for browserify support

If you use the "browserify.transform" feature, it will make it easier for those who also use browserify at the app level to use your npm package. The two changes required to your package.json are: add a dependency on reactify (you currently only have a dev dependency), add at the below line.

"browserify": { "transform": [ ["reactify",{"es6":true}] ] }

You may also wish to consider using babelify instead. It is based on the babel project which is replacing the react-tools project that reactify is based on. If you do, you can use this line instead (as well as a dependency on babelify):

"browserify": { "transform": [ "babelify" ] }

A Way to get all choices?

Being based on React, there could be a way to retrieve the choices as a single parsible object. I don't know if this would require using one of the data store libraries, or just creating an object with nested data.

It would be incredibly useful to have something, either way.

Way to display a conditional question on another panel

Hi, I read the documentation but I didn't find a way to display a conditional question on a different panel.
Example: I answer on panel 1 and 2 and I want a new question on panel 3 according to the previous answers.
Is there a way to do that?
Thanks :-)

Additional simpler demo

First off - this looks real good and I am quite interested in using it in my personal projects.

Now - in addition to the existing demo, I think another with a smaller schema associated with it might help people get started up faster. The current demo is very useful but might work better as the second example.

Just my opinion. Good luck!

a more simple syntax definition

Hi andrew, It's not a criticism but I've found a bit complex understand how define my schemas, basically I feel than there are some incidental complexity in the way how build this (again it's not a criticism and I wish know your point of vie)

  1. after read the doc I understand than you choose use a kind of pointers avoiding nesting compositions, so instead of a form panel with multiples question panels and more nested questionSets you chose separe this in 3 main schema properties and that every components refers with a pointer id to this components, this is pretty nice but I think than this
"formPanels" : [{
        "index" : 1,
        "panelId" : "intro-panel"
    }, {
        "index" : 2,
        "panelId" : "register-panel"
    }, {
        "index" : 3,
        "panelId" : "final-panel"
    }]

can be reduced to

"formPanels" : [ "intro-panel", "register-panel","final-panel"]

I feel than it's not only more readable but than also give the feels about I'm indicating which panels has my component instead of defining panels, in the original way I feel like if I've define my panels in two different places

"action" : {
            "conditions" : [{
                "questionId" : "existing-user",
                "value" : "no",
                "action" : "GOTO",
                "target" : "register-panel"
            }],
            "default" : {
                "action" : "GOTO",
                "target" : "final-panel"
            }
        },
        "button" : {
            "text" : "Next"
        },

for me it's not clear the relationship between default and button, my understand after read the doc is than button call the default action, but in the def seems like if they're not related

maybe something like this could be better

"action" : {
            "conditions" : [{
                "questionId" : "existing-user",
                "value" : "no",
                "action" : "GOTO",
                "target" : "register-panel"
            }],
            "default" : {
                "button" : "Next",
                "action" : "GOTO",
                "target" : "final-panel"
            }
        },



Hope you feel than this can be an improve, I really like many ideas behind this lib and I found I nice way of build forms, thanks

Adding a title to a question set

I hope this dirty schema explains the idea :

capture

As there is a title to the panel, there'd be one on the set.
Or I missed the option in the docs

React.findDOMNode is not a function on Submit

Using the example schema provided, a la:

 "action" : {
      "default" : {
        "action" : "SUBMIT",
        "target": "www.google.com",
      },
    },
    "button" : {
      "text" : "Add",
    },

I'm getting the following error when I hit the Submit button:

Uncaught TypeError: React.findDOMNode is not a function(anonymous function) 
@ index.js:116notifyAll 
@ CallbackQueue.js:67close 
@ ReactUpdates.js:60closeAll 
@ Transaction.js:204perform 
@ Transaction.js:151perform 
@ ReactUpdates.js:90flushBatchedUpdates 
@ ReactUpdates.js:173closeAll 
@ Transaction.js:204perform 
@ Transaction.js:151batchedUpdates 
@ ReactDefaultBatchingStrategy.js:63batchedUpdates 
@ ReactUpdates.js:98dispatchEvent 
@ ReactEventListener.js:150

Does this have to do with the switch from React to ReactDOM? I couldn't find an open issue with this here on GH.

Using "react": "^15.2.1", "react-dom": "^15.2.1", on the project in question.

Submit button

Hi, I got rid of all submit button related things in this schema, but there is still a submit link on the page, does Winterfell internally generate the submit for all schemas?

http://pastebin.com/20gFktDS

Thanks!

Include a non-minified version of Winterfell.

Maybe I am missing something, but there doesn't seem to be an unminified copy of winterfell. I'm not sure if you mean for us to build it if we want it, but many libraries include both versions of code.

Answers for Q's on a different conditional panel stay in answers object

For example, in the Winterfell demo, if you choose No on the first question and press next, enter your email address and go back and select yes, the email address previously entered in the No panel will still be there.

I guess the idea would be to delete any answers from that panel, but if the user wanted to go back to that panel, they'd have lost their input. Is that expected functionality or?

Custom input type props and event handling

Hi great plugin, currently evaluating it to use in a project. If it works for our basic needs I'm more than happy to help with the project.

I would like to use the google places react autosuggest component in a form. Including it as a custom input in the schema renders the component fine but I need to capture the onSuggestSelect event provided by google autosuggest and map it to the onChange event that Winterfell is expecting for the input and pass in a placeholder prop like:

<Geosuggest placeholder="" onSuggestSelect={(suggest) => address.onChange(suggest)} {...address} />

What's the best approach to passing props and handling the mapping of events to custom input types with Winterfell?

Default option on select

Might have missed it maybe; how do I implement a blank default option ?
That works with adding an empty object for sure; I was thinking about the rails select helper that has this specific option which makes it clear and separated from the real selectable ones

Repeating Question Sets

The ability to add more items of a questionSet for example needs to be built in with an "add another" button etc with a remove button.

Examples not working

Hi @andrewhathaway, I've been struggling to get the examples up and running via all sorts of methods. I've tried npm run, npm build, gulping, grunting and the custom npm commands you put together and for whatever reason, can't seem to compile the app.js to the same build state as the running examples here: http://winterfell.andrewhathaway.net/.

The reason I'd like to have the examples running is because I'm only able to wire into the onSwitchPanel event. Something is off in my attempts to build locally. I really want to move ahead with Winterfell, but I'm currently blocked under a time constraint. Thanks again for the awesome OSS contribution that is Winterfell!

Add/remove fields dynamicaly

Is there a way to create fields that can be added or removed dynamically?
Example: A group field to enter an invoice line (product and price) and a '+' button to add a new invoice line. A '-' button to remove the new added line.
Thank you Andrew for the great work with Winterfell!

custom Classes per question

I'd love to be able to use custom classes on a single question. is this possible? This is how I would expect it to work:

  }, {
    panelId : 'register-panel',
    panelHeader : 'My Awesome Form',
    panelText : 'We don\'t have a survey for you yet, how about we get you subscribed?',
    classes: {
      radioList : 'Field--paired Grid Grid--alignMiddle Grid--withGutters',
      radioListItem : 'Grid-cell u-size1of4'
    },

String vs. number mismatch

I noticed problems when using the checkboxOptionsInput (and maybe with others, too) and defining your options using numbers (not numbers in strings). When checking a checkbox, the value that is registered is the number as string. This seems to lead to multiple problems:

  1. The checkbox is not rendered checked.
  2. The questionsAnswers holds duplicate values if the checkbox was clicked multiple times.
  3. The isAllIn validation does not validate if given as numbers as well.

Workaround
Not using numbers or convert numbers to strings in the schema.

Why I think this is a bug
This library aims to provide "JSON-based forms in React". The JSON format allows numbers, so the expected behaviour would be that numbers work as options.

Possible solutions
The source of this problem could be that there is no distinction between numbers and strings in HTML and that the options are used as value of the checkbox. Simply converting numbers to strings would fix most of the issues. But it would not allow that for example 42 and "42" could both be values. So another solution would be to use proxy-options as values for the checkboxes and then map the proxy-options to the real options.

Example broken question

{
    "questionId": "example-broken-question",
    "question": "Please select any number of elements",
    "input": {
        "type": "checkboxOptionsInput",
        "required": false,
        "options": [
            {
                "text": "Option one",
                "value": 1
            },
            {
                "text": "Option two",
                "value": 2
            },
            {
                "text": "Option three",
                "value": 3
            }
        ]
    },
    "validations": [
        {
            "type": "isAllIn",
            "params": [
                [1, 2, 3]
            ]
        }
    ]
}

Support for front-end UI frameworks

Any thought about add a custom theming feature so one could slip in UI frameworks like Material-UI or even (god forbid) Bootstrap.

I would mark this as a question, not issue, but I don't know how to do so

Email input box jumps around whilst typing

Hey up it's Barn, lib looks really good btw!

Just a minor UX thing I noticed when trying the demo, email box jumps up and down as my input goes from empty -> invalid -> valid.

I guess you may want to either display validation below, add a delay which resets on input, or add a validateOn option which would let me validate email on blur.

How can I make a checkbox to be checked by default?

After some tests, I am unable to set a checkbox as checked by default. I am reading the code and I don't see any way the checkboxInput component can accomplish that.

Am I missing anything? Should I try to do it and send a PR?

Thanks!

Unable to build examples

Hi

I've tried for several time to get your example working.

I can see that there is a "gulp build-example"...

All though when I run this, I get the following:

[14:41:50] Starting 'build-examples'...
events.js:85
      throw er; // Unhandled 'error' event
            ^
Error: Cannot find module 'react' from 'c:\Users\User\Downloads\Winterfell-master\Winterfell-master\examples'

Other than that, I have tried just to find a precompiled version of "Winterfell", to use with my app, but it seems I really have to build it....

Can you supply a production ready precompiled version of your plugin, ready to use?

Regards

Ordering is inconsistently determined

The order of formPanels, questionSets, and questions seems to be inconsistent. Questions are ordered by their array order. QuestionSets, seem to be controlled by their array order in the questionPanels.questionSets array as well, rather than by the index property shown in the examples. As for formPanels, looking at the code, I find that they do get sorted by their index property (index.js line 21).

This is inconsistent, but may be intentional for some reason. If so, the index property of the questionSet should be omitted from documentation as it is misleading and never used. Personally, I'd rather see the ordering of everything be based on the actual array order rather then an index property. However, it could also be configurable, or index could be used if present with fallback to array order. Most importantly, this should be implemented consistently.

While submitting

While trying to submit the form we are unable to do that. We got the following issue.

Uncaught Error: Winterfell: Attempted to validate for undefined method "undefined"

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.