[FIXED] [#894] [3.3] GridPanel/RowExpander not working as expected

  1. #1

    [FIXED] [#894] [3.3] GridPanel/RowExpander not working as expected

    Hi

    I have an application which is making extenisve use of GridPanels and RowExpanders. I'm experiencing problems with getting the functionality to behave as I want it to. The full set up is relatively complicated so I have broken it down into stages. The following code is the first stage

    The View code is:

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
        @{
        Layout = "~/Views/Shared/_Layout.cshtml";
        }
        @section scripts
        {
            <script>
                var counter = 1;
                var changeText = function (button) {
                    var grid = button.up('grid');
                    var selectedRecords = grid.getSelectionModel().getSelection();
                    if (selectedRecords.length > 0) {
                        selectedRecords[0].set("Test", "Testing " + counter);
                        counter++;
                    }
                }
            </script>
        }
    </head>
    <body>
    @section mainBody
    {
        @(Html.X().GridPanel().Width(352)
            .Title("Users").ID("GridPanel").Border(true)
            .Store(Html.X().Store()
                .ID("Store")
                .Model(Html.X().Model().IDProperty("ID")
                    .Fields(
                        new ModelField("ID", ModelFieldType.Int),
                        new ModelField("Name"),
                        new ModelField("Test")
                        )
                    )
                .Proxy(Html.X().AjaxProxy().Url(Url.Action("Read")).Reader(Html.X().JsonReader().RootProperty("data"))))
            .ColumnModel(
                Html.X().Column().Text("User").DataIndex("Name").Width(100),
                Html.X().Column().Text("Test").DataIndex("Test").Flex(50)
            )
            .SelectionModel(Html.X().RowSelectionModel().ID("rowSelectionModel").Mode(SelectionMode.Single))
            .TopBar(Html.X().Toolbar().Items(
                Html.X().Button().Text("Test").Listeners(lst => { lst.Click.Handler = "changeText(this)"; })
                )
            )
            .Plugins(
            Html.X().RowExpander().SingleExpand(true).ID("RowExpand")
            .Component(
                Html.X().GridPanel().Border(true).Height(250).ID("AccessgridPanel")
                    .Store(Html.X().Store().ID("RowExpanderStore")
                        .Model(Html.X().Model()
                            .Fields(
                                new ModelField("ID", ModelFieldType.Int),
                                new ModelField("Option"),
                                new ModelField("IsReadOnly", ModelFieldType.Boolean)
                                )
                            )
                        .Proxy(Html.X().AjaxProxy().Url(Url.Action("RowExpander")).Reader(Html.X().JsonReader().RootProperty("data")))
                        .AutoLoadParams(new { id = JRawValue.From("this.record.data.ID") }))
                    .ColumnModel(
                        Html.X().Column().Text("Option").DataIndex("Option").Flex(1),
                        Html.X().CheckColumn().Text("Read Only?").DataIndex("IsReadOnly").Width(100).Editable(true)
                    )
                )
                                                    
            )
        )
    }
    </body>
    </html>
    The Controller code is:

    using Ext.Net;
    using Ext.Net.MVC;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    
    namespace ExtSandpit.Controllers
    {
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                return View();
            }
            public ActionResult Read()
            {
                List<User> lstUsers = new List<User>();
                lstUsers.Add(new User(1000,"Jeff"));
                lstUsers.Add(new User(1001,"James"));
                return this.Store(lstUsers);
            }
            public ActionResult RowExpander(string id)
            {
                int userID = Int32.Parse(id);
                List<AccessOptionDetail> lstAccessOptionDetail = new List<AccessOptionDetail>();
                if (userID == 1001)
                {
                    lstAccessOptionDetail.Add(new AccessOptionDetail(1, "Goods In", true));
                }
                else if (userID == 1000)
                {
                    lstAccessOptionDetail.Add(new AccessOptionDetail(2, "Production", false));
                }
                return this.Store(lstAccessOptionDetail);
            }
        }
    
        public class User
        {
            public User()
            {
            }
            public User(int id, string name)
            {
                ID = id;
                Name = name;
            }
            public int ID { get; set; }
            public string Name { get; set; }
            public string Test { get; set; }
        }
        public class AccessOptionDetail
        {
            public AccessOptionDetail()
            {
            }
            public AccessOptionDetail(int id, string option, bool isreadonly)
            {
                ID = id;
                Option = option;
                IsReadOnly = isreadonly;
            }
            public int ID { get; set; }
            public string Option { get; set; }
            public bool? IsReadOnly { get; set; }
        }
    }
    When I select a row in the main GridPanel and press the Test button a JavaScript function updates the value of the Test field. This works OK when the RowExpander is closed but when the RowExpander is open the effect of the function is to close the RowExpander but leave the +/- box as -. Clicking on this change it to a +. It is then possible to open the RowExpander again.

    I want the RowExpander to remain open. Am I missing something or is this a bug?

    As a minor aside why is the column containing the +/- sign not wide enough?

    Thanks for your help
    Last edited by Daniil; Sep 11, 2015 at 1:20 PM. Reason: [FIXED] [#894] [3.3]
  2. #2
    Hi @Argenta,

    Well, it is either a bug or not a supported feature. I am not sure how to treat it. There is a specific technical reason of this behavior. A record's .set() call triggers re-rendering of the entire row and it removes a row's body content which is not recreated automatically.

    1. A solution could be collapsing and expanding before updating.

    var counter = 1;
    
    var changeText = function (button) {
        var grid = button.up('grid'),
            selectedRecords = grid.getSelectionModel().getSelection(),
            selectedRecord,
            rowIndex,
            rowExpander,
            expand;
    
        if (selectedRecords.length > 0) {
            selectedRecord = selectedRecords[0];
            rowIndex = grid.getStore().indexOf(selectedRecord),
            rowExpander = grid.getRowExpander();
    
            if (rowExpander.isExpanded(rowIndex)) {
                rowExpander.collapseRow(rowIndex);
                expand = true;
            }
    
            selectedRecord.set("Test", "Testing " + counter);
    
            if (expand) {
                rowExpander.expandRow(rowIndex);
            }
    
            counter++;
        }
    };
    2. Alternative solution could be getting rid of record.set() call at all and replace it with a silent manual update.

    var counter = 1;
    
    var changeText = function (button) {
        var grid = button.up('grid'),
            selectedRecords = grid.getSelectionModel().getSelection();
    
        if (selectedRecords.length > 0) {
            updateCell(grid, selectedRecords[0], "Test", "Testing " + counter);
            counter++;
        }
    };
    
    var updateCell = function (grid, record, dataIndex, value) {
        var column = grid.headerCt.child("gridcolumn[dataIndex=" + dataIndex + "]"),
            view = grid.getView(),
            cell = view.getCell(record, column),
            inner = cell.first();
    
        record.data[dataIndex] = value;
        record.dirty = true;
        cell.addCls(view.dirtyCls);
    
        if (Ext.isFunction(column.renderer)) {
            value = column.renderer(value, null, record); // The second parameter is "metadata" which is not supported with such an update. 
                                                            // Also you might need to pass all other parameters if it is used in your custom Renderers
        }
    
        inner.setHtml(value);
    };
    3. I finally realized that it is nothing except a bug. Most likely, it has been introduced while working on these issues.
    https://github.com/extnet/Ext.NET/issues/832
    https://github.com/extnet/Ext.NET/issues/836

    I am saying "most likely", because I cannot check it right away to ensure - it looks like the SVN server is down currently and I cannot look at the SVN revisions.

    Created an Issue.
    https://github.com/extnet/Ext.NET/issues/894

    Please try this override as a fix. I left commented out things for myself not to forget what I changed.
    Ext.net.RowExpander.override({
        bindView: function (view) {
            view.stopEventFn = this.stopEventFn;
    
            view.on("beforerefresh", function () {
                this.preventsExpanding = {};
            }, this);
    
            if (this.expandOnEnter) {
                view.on('itemkeydown', this.onKeyDown, this);
            }
    
            if (this.expandOnDblClick) {
                view.on('itemdblclick', this.onDblClick, this);
            }
    
            view.on('itemmousedown', function (view, record, item, index, e) {
                return !e.getTarget('div.x-grid-rowbody', view.el);
            }, this);
    
            if (this.swallowBodyEvents) {
                view.on("itemupdate", this.swallowRow, this);
                view.on("refresh", this.swallowRow, this);
            }
    
            if ((this.componentCfg /*&& this.singleExpand === false*/) || this.loader) {
                view.on("beforerefresh", this.mayRemoveComponents, this);
                view.on("beforeitemupdate", this.mayRemoveComponent, this);
                view.on("beforeitemremove", this.removeComponent, this);
                view.on("refresh", this.restoreComponents, this);
                view.on("itemupdate", this.restoreSingleComponent, this);
            }
    
            //if (this.component) {
            //    view.on("beforerefresh", this.moveComponent, this);
            //    view.on("beforeitemupdate", this.moveComponent, this);
            //    view.on("beforeitemremove", this.moveComponent, this);
            //    view.on("refresh", this.restoreComponent, this);
            //    view.on("itemupdate", this.restoreComponent, this);
            //}
        },
    
        restoreComponent: Ext.emptyFn
    });
    As a minor aside why is the column containing the +/- sign not wide enough?
    Please start a new forum thread.
  3. #3
    Thanks very much Daniil

    That override certainly solves the issue for now.

    Thanks again

    Jeff
  4. #4
    Thank you for confirming. I have committed the fix in the revision #6561 (trunk). It goes to the 3.3 release.

Similar Threads

  1. [CLOSED] ClicksToEdit not working as expected
    By Argenta in forum 3.x Premium Help
    Replies: 1
    Last Post: May 28, 2015, 4:01 PM
  2. [CLOSED] Checkbox selection model is not working as expected.
    By arjunrvasisht in forum 2.x Premium Help
    Replies: 2
    Last Post: Apr 30, 2015, 10:32 AM
  3. Replies: 0
    Last Post: Feb 06, 2012, 7:29 PM
  4. [CLOSED] SelectionModel.SelectAll() Not Working As Expected
    By garrisrd in forum 1.x Premium Help
    Replies: 1
    Last Post: Aug 09, 2011, 8:30 AM
  5. Replies: 11
    Last Post: Aug 20, 2010, 3:06 PM

Tags for this Thread

Posting Permissions