0

I've been trying to create a custom widget for Netlify CMS to allow for key-value pairs to be inserted. However there are a few things going wrong, I'm thinking they might be related so I'm making a single question about them.

This is my first custom widget, and I’m mostly basing this on the official tutorial: https://www.netlifycms.org/docs/custom-widgets/

I’m using a Map as the value, but when I add a new element to the map, and then call the onChange(value) callback, nothing seems to happen. However, if I change it to onChange(new Map(value)) it does update. It seems that the onChange callback requires a new object?

Secondly, the value doesn’t seem to be actually saved. When I fill in other widgets and refresh the page, it then asks to restore the previous values. However it doesn’t restore the map, while restores the other values just fine.

And lastly, I get uncaught exception: Object like a second after I change anything to the map. My guess is that Netlify CMS is trying to save the map (debouncing it for a second so it doesn’t save every letter I type), but fails and throws that exception. That would explain the previous problem (the non-saving one).

My complete code for the custom widget currently is:

var IngredientsControl = createClass({
    getDefaultProps: function () {
        return {
            value: new Map()
        };
    },

    addElement: function (e) {
        var value = this.props.value;
        value.set("id", "Description");

        //is.props.onChange(value);
        this.props.onChange(new Map(value));
    },

    handleIdChange: function (oldId, newId) {
        console.log(oldId, newId);
        var value = this.props.value;
        var description = value.get(oldId);
        value.delete(oldId);
        value.set(newId, description);

        //this.props.onChange(value);
        this.props.onChange(new Map(value));
    },

    handleDescriptionChange: function (id, description) {
        console.log(id, description);
        var value = this.props.value;
        value.set(id.toLowerCase(), description);

        //this.props.onChange(value);
        this.props.onChange(new Map(value));
    },

    render: function () {
        var value = this.props.value;

        var handleIdChange = this.handleIdChange;
        var handleDescriptionChange = this.handleDescriptionChange;

        var items = [];
        for (var [id, description] of value) {
            var li = h('li', {},
                h('input', { type: 'text', value: id, onChange: function (e) { handleIdChange(id, e.target.value); } }),
                h('input', { type: 'text', value: description, onChange: function (e) { handleDescriptionChange(id, e.target.value); } })
            );
            items.push(li);
        }

        return h('div', { className: this.props.classNameWrapper },
            h('input', {
                type: 'button',
                value: "Add element",
                onClick: this.addElement
            }),
            h('ul', {}, items)
        )
    }
});

var IngredientsPreview = createClass({
    render: function () {
        var value = this.props.value;
        var items = [];
        for (var [id, description] of value) {
            var li = h('li', {},
                h('span', {}, id),
                h('span', {}, ": "),
                h('span', {}, description)
            );
            items.push(li);
        }

        return h('ul', {}, items);
    }
});

CMS.registerWidget('ingredients', IngredientsControl, IngredientsPreview);

What am I doing wrong?

Thanks!

The Oddler
  • 6,314
  • 7
  • 51
  • 94

1 Answers1

0

I solved this by using immutable-js's map: https://github.com/immutable-js/immutable-js

The Oddler
  • 6,314
  • 7
  • 51
  • 94