GithubHelp home page GithubHelp logo

andrewhathaway / winterfell Goto Github PK

View Code? Open in Web Editor NEW
787.0 29.0 120.0 1.37 MB

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

Home Page: http://winterfell.andrewhathaway.net

License: MIT License

JavaScript 100.00%
reactjs react forms json complex winterfell customisable validation validated

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

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]
            ]
        }
    ]
}

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.

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

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!

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

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.

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

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.

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

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.

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

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!

`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?

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

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!

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.

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.

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).

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.

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!

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!

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

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'
    },

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?

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.

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;

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.

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.

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?

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!

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.

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.

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!

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.

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!

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" ] }

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.