insin / newforms-examples

Examples repository for newforms / React
32 stars 7 forks source link

Custom widget examples? #2

Open kevzettler opened 9 years ago

kevzettler commented 9 years ago

I can't seem to find any code demonstrating custom widget setup

marr commented 9 years ago

Bump. Also from #1, @insin can you provide how to do this with http://newforms.readthedocs.org/en/latest/forms_api.html#DeclarativeFieldsMeta

insin commented 9 years ago

The default Widget implementations are currently the only reference for writing widgets. The Widget docs only contain a custom MultiWidget example because the base object is useless on its own.

The base Widget object documents what the various methods are for - the best thing to do at the moment is check out how widgets which are most similar to what you need are implemented.

Note that widgets are currently still effectively direct ports from django.forms so are fairly dumb and static - still trying to figure out a good way to implement them as React components, which should make it much easier to implement your own.

React 0.13 may be the time to start implementing this, as it adds support for regular JavaScript constructors as components, which allows for extension and tweaking of a base Widget component.

I haven't tried it yet, but a good patten in the meantime might be to extend Widget and render a custom React component inside the widget's render(name, value, kwargs) method. kwargs.attrs includes the event handler callbacks newforms uses to track changes (there's always a kwargs.attrs.onChange, plus any other for events you've configure to fire), so you need to either pass those to a rendered React input or handle calling them yourself with an appropriate value.

kevzettler commented 9 years ago

I haven't tried it yet, but a good patten in the meantime might be to extend Widget and render a custom React component inside the widget's render(name, value, kwargs) method. kwargs.attrs includes the event handler callbacks newforms uses to track changes (there's always a kwargs.attrs.onChange, plus any other for events you've configure to fire), so you need to either pass those to a rendered React input or handle calling them yourself with an appropriate value.

This is what we've been doing so far on our setup. We have this meta thing that converts all our 'Form' components in to newforms friendly components. @insin let me know if you have any ideas to improve this

var Form = {
    CheckBox:         require('./form/CheckBox'),
    CardInput:         require('./form/CardInput'),
    QuantitySelector: require('./QuantitySelector')
};

Object.keys(Form).forEach(function(key){
    Form["NF"+key] = newforms.Widget.extend({
        constructor: function (kwargs) {
            if (!(this instanceof Form["NF"+key])) { return new Form["NF"+key](kwargs) }
            newforms.Widget.call(this, kwargs);
            this.props = kwargs;
        },

        render: function(name, value, kwargs){
            var finalAttrs = this.buildAttrs(Object.assign(kwargs.attrs, this.props), {
                    type: this.inputType,
                    name:name
            });
            var valueAttr = (kwargs.controlled || this.isHidden ? 'value' : 'defaultValue')
            finalAttrs[valueAttr] = this.props[valueAttr];

            return React.createElement(Form[key], finalAttrs);
        }
    });
});
marr commented 9 years ago

Would be cool to see an example of how RenderForm would be used with a custom renderer as well.

insin commented 9 years ago

@marr a custom renderer for RenderForm can just be any React component which takes a form prop with the form instance to be rendered. BootstrapForm and GridForm are a couple of examples.

(After React contexts change from being owner-based to parent-based, it won't even have to take a prop, just pick the form off the context, e.g: this is what GridForm should look like then)

marr commented 9 years ago

Thanks, I hadn't seen that syntax before. Specifically passing children to the RenderForm. Is that something supported in 0.12? I am running into an issue where I'd like to format a fields input using a vendor lib. https://www.npmjs.com/package/payment#paymentformatcardnumber will let me format CC entry a little nicer, but I'm not sure how to hook it into a newforms field. My form looks like: https://github.com/bitwise/status/blob/master/src/scripts/forms/NewCreditCard.js