Extjs classic: Textarea with resizable=true cannot be resized

209 views Asked by At

I created this fiddle: https://fiddle.sencha.com/#view/editor&fiddle/3mh2. If you run it, you'll see you cannot resize the textarea even though it has the property resizable: true.

Ext.application({
    name: 'Fiddle',

    launch: function () {

        var shows = Ext.create('Ext.data.Store', {
            fields: ['id', 'show'],
            data: [{
                id: 0,
                show: 'Battlestar Galactica'
            }, {
                id: 1,
                show: 'Doctor Who'
            }, {
                id: 2,
                show: 'Farscape'
            }, {
                id: 3,
                show: 'Firefly'
            }, {
                id: 4,
                show: 'Star Trek'
            }, {
                id: 5,
                show: 'Star Wars: Christmas Special'
            }]
        });

        Ext.create('Ext.form.Panel', {
            renderTo: Ext.getBody(),
            title: 'Sci-Fi Television',
            width: 400,
            frame: true,
            resizable: true,
            items: [{
                xtype: 'tagfield',
                fieldLabel: 'Select a Show',
                store: shows,
                displayField: 'show',
                valueField: 'id',
                queryMode: 'local',
                filterPickList: true
            },
                {
                    xtype: 'textareafield',
                    resizable: true,
                    fieldLabel: 'Some label',
                    anchor: '100%',
                    //resizeHandles: 's',
                    //grow: true
                }]
        });
    }
});

What am I missing?

To make things more interesting, I took a look at the docs: https://docs.sencha.com/extjs/7.6.0/classic/Ext.form.field.TextArea.html.

I modified the sample to:

Ext.create('Ext.form.FormPanel', {
    title      : 'Sample TextArea',
    width      : 400,
    bodyPadding: 10,
    renderTo   : Ext.getBody(),
    items: [{
        xtype     : 'textareafield',
        grow      : true,
        name      : 'message',
        fieldLabel: 'Message',
        anchor    : '100%',
        resizable: true,
    }]
});

(I added the resizable: true, line) If I click the Run button and I hover the mouse over I get the gray bars.

enter image description here

On the other form, no matter where I hover the mouse the gray bars don't show up.

But... if I include grow: true I am getting some weird mix up in the UI - the gray bars show up eventually, but the position is incorrect.

enter image description here

How can I get this form to look correct, and still be able to resize the textarea. Resizing the textarea just vertically would suffice.

2

There are 2 answers

2
Peter Koltai On

You can get this working in a few steps:

  1. Specify a vbox layout for the form panel (align: 'stretch' is needed to stretch the form fields horizontally when you resize the panel).
  2. Wrap the textareafield into a container with fit layout and set resizable on the container and not on the textarea.
  3. You can set further parameters within resizer if instead of true you use an object which defines an Ext.resizer.Resizer, check documentation for all config options (pinned might be a good idea to show the resize handler always).

As for step 2, I can't tell you for sure why it is not working without the container, but according to the documentation linked abocve, textarea resizer is somewhat different, this could be the reason but I can only guess:

Textarea and img elements will be wrapped with an additional div because these elements do not support child nodes.

One drawback of this solution is that the resize handle appears not only below the textarea but the entire container, but this is as far as I could get. I tried labelAlign: 'top' on the textarea but it adds some space below the label when resizing.

Ext.application({
    name: 'Fiddle',
    launch: function () {

        var shows = Ext.create('Ext.data.Store', {
            fields: ['id', 'show'],
            data: [{
                id: 0,
                show: 'Battlestar Galactica'
            }, {
                id: 1,
                show: 'Doctor Who'
            }, {
                id: 2,
                show: 'Farscape'
            }, {
                id: 3,
                show: 'Firefly'
            }, {
                id: 4,
                show: 'Star Trek'
            }, {
                id: 5,
                show: 'Star Wars: Christmas Special'
            }]
        });

        Ext.create('Ext.form.Panel', {
            renderTo: Ext.getBody(),
            title: 'Sci-Fi Television',
            width: 400,
            padding: 8,
            frame: true,
            resizable: true,
            layout: {
                type: 'vbox',
                align: 'stretch',
            },
            items: [{
                xtype: 'tagfield',
                fieldLabel: 'Select a Show',
                store: shows,
                displayField: 'show',
                valueField: 'id',
                queryMode: 'local',
                filterPickList: true
            }, {
                xtype: 'container',
                layout: {
                    type: 'fit',
                },
                resizable: {
                    pinned: true,
                    handles: 's',
                },
                items: [{
                    xtype: 'textareafield',
                    //labelAlign: 'top',
                    grow: true,
                    fieldLabel: 'Some label',
                }]
            }]
        });
    }
});
0
boggy On

Found another way (fiddle here):

Ext.application({
    name: 'Fiddle',
    launch: function () {

        var shows = Ext.create('Ext.data.Store', {
            fields: ['id', 'show'],
            data: [{
                id: 0,
                show: 'Battlestar Galactica'
            }, {
                id: 1,
                show: 'Doctor Who'
            }, {
                id: 2,
                show: 'Farscape'
            }, {
                id: 3,
                show: 'Firefly'
            }, {
                id: 4,
                show: 'Star Trek'
            }, {
                id: 5,
                show: 'Star Wars: Christmas Special'
            }]
        });

        Ext.create('Ext.panel.Panel', {
            renderTo: Ext.getBody(),
            title: 'Sci-Fi Television',
            //width: 400,
            //height: 800,
            layout: 'fit',
            padding: 8,
            frame: true,
            //resizable: true,

            // layout: {
            //     type: 'vbox',
            //     align: 'stretch',
            // },

            items: [{
                xtype: 'form',
                items: [{
                    xtype: 'tagfield',
                    fieldLabel: 'Select a Show',
                    store: shows,
                    displayField: 'show',
                    valueField: 'id',
                    queryMode: 'local',
                    filterPickList: true
                }, {

                    xtype: 'textareafield',
                    //labelAlign: 'top',
                    //grow: true,
                    fieldLabel: 'Some label',
                    anchor: '100%',
                    style: 'margin-bottom: 10px;',
                    fieldStyle: 'resize: vertical;',
                    listeners: {
                        afterrender: function (resizable) {
                            console.log('afterrender');
                            var formPanel = resizable.up('form');
                            // formPanel.setHeight(formPanel.body.getHeight() + formPanel.getFrameHeight());
                            console.log(formPanel.findParentByType('panel'));
                            function outputsize() {
                                //console.log(resizable.getHeight());
                                formPanel.findParentByType('panel').updateLayout();
                            }

                            console.log(resizable);
                            new ResizeObserver(outputsize).observe(resizable.getEl().dom);
                        }
                    }
                }, {
                    xtype: 'tagfield',
                    fieldLabel: 'Select a Show',
                    store: shows,
                    displayField: 'show',
                    valueField: 'id',
                    queryMode: 'local',
                    filterPickList: true
                }]
            }],

        });
    }
});

Some points:

  • I made the textarea resizable vertically using the resizable: vertical; style
  • I placed the form in another panel that has the layout: 'fit', because I wanted this panel to expand to fit the content of the form panel
  • I added a resize listener for the textarea using the info found here: https://stackoverflow.com/a/39312642/832783. The listener simply updates the layout of the parent panel which in turn resizes it to embrace the entire content of the form panel.