0
votes

I have a model with a hex color field. The user can edit it as rgb via 3 separate numberfields. I'm trying to bind the field to these components but I'm not sure how to do it. I tried putting them in a container and binding the container to the field. However my setValue isn't called when a numberfield is changed.

I guess I could add listeners to the numberfields but I was hoping there was a better way to go about it.

https://fiddle.sencha.com/#view/editor&fiddle/23t2

2

2 Answers

0
votes

setValue is only called on a form field. Form fields are denoted by the config isFormField: true. Note however that setValue is not the only function expected on a form field; there are dozens others (e.g. getValue, getModelValue, isValid, ...).

Because of this, I always use a hiddenfield to aggregate other form fields, not a container, and then I use change listeners to keep hiddenfield and other fields synchronized (bind should work as well, but our app is still MVC). I also annotate the other fields with

excludeForm: true,
submitValue: false,

to make sure that the values are not submitted and do not affect the "dirty" state of the form.

0
votes

I have made some changes. It will work for both scenario,

  1. if user change from color name(textfield) then RGB will change.
  2. If user will change from number field than color name(textfield) will be changed.

Try this code in your sencha fiddle

Ext.create({
    xtype: 'viewport',
    renderTo: Ext.getBody(),

    viewModel: {
        data: {
            theColor: {
                name: 'Blue',
                hex: '3366CC'
            }
        },
        formulas: {
            containerValue: {
                bind: '{theColor.hex}',
                get: function (value) {
                    return {
                        hex: value
                    };
                },
                set: function (value) {
                    this.set('theColor.hex', value.hex);
                }
            }
        }
    },

    items: [{
        region: 'center',
        xtype: 'form',
        bodyPadding: 10,
        height: 300,

        fieldDefaults: {
            labelWidth: 90,
        },

        items: [{
            xtype: 'component',
            width: 30,
            height: 30,
            bind: {
                style: {
                    background: '#{theColor.hex}'
                }
            }
        }, {
            xtype: 'textfield',
            fieldLabel: 'Name',
            bind: '{theColor.name}',
            listeners:{
                blur:function(textfield,e,eOpts){
                    var viewModel = textfield.up('viewport').getViewModel();
                        colorName = textfield.getValue(),
                        hex = colorToHex(colorName);
                    viewModel.set('theColor',{
                     name: colorName,
                     hex: hex
                    });
                    function colorToRGBA(color) {
                        // Returns the color as an array of [r, g, b, a] -- all range from 0 - 255
                        // color must be a valid canvas fillStyle. This will cover most anything
                        // you'd want to use.
                        // Examples:
                        // colorToRGBA('red')  # [255, 0, 0, 255]
                        // colorToRGBA('#f00') # [255, 0, 0, 255]
                        var cvs, ctx;
                        cvs = document.createElement('canvas');
                        cvs.height = 1;
                        cvs.width = 1;
                        ctx = cvs.getContext('2d');
                        ctx.fillStyle = color;
                        ctx.fillRect(0, 0, 1, 1);
                        return ctx.getImageData(0, 0, 1, 1).data;
                    }

                    function byteToHex(num) {
                        // Turns a number (0-255) into a 2-character hex number (00-ff)
                        return ('0'+num.toString(16)).slice(-2);
                    }

                    function colorToHex(color) {
                        // Convert any CSS color to a hex representation
                        // Examples:
                        // colorToHex('red')            # '#ff0000'
                        // colorToHex('rgb(255, 0, 0)') # '#ff0000'
                        var rgba, hex;
                        rgba = colorToRGBA(color);
                        hex = [0,1,2].map(
                            function(idx) { return byteToHex(rgba[idx]); }
                            ).join('');
                        return hex;
                    }
                }
            }
        }, {
            xtype: 'container',

            setValue: function (value) {
                const hex = value.hex || '000000';

                const red = parseInt(hex.substr(0, 2), 16);
                const green = parseInt(hex.substr(2, 2), 16);
                const blue = parseInt(hex.substr(4, 2), 16);

                const items = this.query('');

                items[0].setValue(red);
                items[1].setValue(green);
                items[2].setValue(blue);
            },

            bind: {
                value: '{containerValue}',
            },

            defaults: {
                xtype: 'numberfield',
                maxValue: 255,
                minValue: 0,
                allowBlank: false,
                width: 175,
                listeners:{
                    change:function(numberfield){
                        if(numberfield.hasFocus){
                            var viewModel = numberfield.up('viewport').getViewModel(),
                                items = this.up().query(''),
                                red =  items[0].getValue() || 0,
                                green = items[1].getValue() || 0,
                                blue = items[2].getValue() || 0,
                                hex = rgbToHex(red,green,blue);
                            viewModel.set('theColor',{
                             name: hex,//For hex to color name you have to search for that, here I am giving hax color.
                             hex: hex
                            });
                            function componentToHex(c) {
                                var hex = c.toString(16);
                                return hex.length == 1 ? "0" + hex : hex;
                            }

                            function rgbToHex(r, g, b) {
                                return componentToHex(r) + componentToHex(g) + componentToHex(b);
                            }
                        }
                    }
                }
            },

            items: [{
                fieldLabel: 'R',
            }, {
                fieldLabel: 'G',
            }, {
                fieldLabel: 'B',
            }]
        }]
    }]
});