SearchBuilder improperly displaying indented criteria on loaded state?

SearchBuilder improperly displaying indented criteria on loaded state?

DakotaTDakotaT Posts: 2Questions: 1Answers: 0

Links

Test case: https://jsfiddle.net/a1vczxft/1/
(Basically identical to this example, except the one above uses the modal rather than the embedded version)
https://datatables.net/extensions/staterestore/examples/integration/searchBuilder.html

Example

Steps to reproduce:
1. Open searchBuilder, add 2 criteria, and indent both of them.
2. Create a state once applied, then reload that state (doesn't even need a table reload)

When loading you can see the indented buttons on the left, it seems the CSS just isn't set correctly:

This doesn't seem to be a savedState issue in the sense of the data not storing correctly, because the localStorage holds the data as expected.

Also if you add a criteria at the bottom (while within the broken state) and remove it, it rebuilds it correctly.

Answers

  • DakotaTDakotaT Posts: 2Questions: 1Answers: 0

    Alright I believe I've diagnosed the issue, may not be the best solution but it's a solution.

    Below are the modified methods:

    SearchBuilder main method

    //... The beginning of the method
       this.s = {
        dt: table,
        opts: opts,
        search: undefined,
        serverData: undefined,
        topGroup: undefined,
        isStateJustLoaded: false // new flag for loading a new state
    };
    //... Rest of the method is also unchanged
    

    State Load Params handler

    this.s.dt.on('stateLoadParams.dtsb', function (e, settings, data) {
        _this.rebuild(data.searchBuilder);
        _this.s.isStateJustLoaded = true; // flag trigger
    });
    

    SearchBuilder button extension action

    action: function (e, dt, node, config) {
        this.popover(config._searchBuilder.getNode(), {
            align: 'container',
            span: 'container'
        });
        // --- Start of modified logic ---
        var sbInstance = config._searchBuilder;
        var topGroup = sbInstance.s.topGroup;
        // Need to redraw the contents to calculate the correct positions for the elements
        if (void 0 !== topGroup) {
            if (sbInstance.s.isStateJustLoaded) {
                topGroup.dom.container.trigger('dtsb-redrawContents');
                sbInstance.s.isStateJustLoaded = false;
            } else {
                topGroup.dom.container.trigger('dtsb-redrawContents-noDraw');
            }
        }
        // --- End of modified logic ---
        if (topGroup.s.criteria.length === 0) {
            $('.' + $.fn.dataTable.Group.classes.add.replace(/ /g, '.')).click();
        }
    }
    

    Explanation

    The issue is when the searchBuilder is shown as a popover and loadState is leveraged. Specifically the following portion within the setupLogic:

    var height = this.dom.container.outerHeight() - 1;
    this.dom.logicContainer.width(height);
    this._setLogicListener();
    // Set criteria left margin
    this.dom.container.css('margin-left', this.dom.logicContainer.outerHeight(true));
    var logicOffset = this.dom.logicContainer.offset();
    // Set horizontal alignment
    var currentLeft = logicOffset.left;
    var groupLeft = this.dom.container.offset().left;
    var shuffleLeft = currentLeft - groupLeft;
    var newPos = currentLeft - shuffleLeft - this.dom.logicContainer.outerHeight(true);
    this.dom.logicContainer.offset({ left: newPos });
    // Set vertical alignment
    var firstCrit = this.dom.logicContainer.next();
    var currentTop = logicOffset.top;
    var firstTop = $$2(firstCrit).offset().top;
    var shuffleTop = currentTop - firstTop;
    var newTop = currentTop - shuffleTop;
    this.dom.logicContainer.offset({ top: newTop });
    this.dom.clear.outerHeight(this.dom.logicContainer.height());
    this._setClearListener();
    
    Since the container is not visible, the browser has not rendered or calculated the dimensions.
    • The height variable becomes -1 because this.dom.container.outerHeight() is 0 (not calculated).
    • The logicContainer.width becomes -1, which is clamped to 0px (invisible)
    Because of this 0px representation for the pre-rotated width (once rotated would represent the height) of the logic button, all indentations are incorrect. As well as the buttons not being rendered since they have no width.

    Solution

    When the popover is truly rendered in the dom for the first time, redraw all the content, at this point the dom will be calculated correctly. This is only necessary for the first time, since any modification to the searchBuilder while the popover is visible will rebuild as expected. The flag prevents unnecessary rebuilds for better performance.

  • allanallan Posts: 64,599Questions: 1Answers: 10,683 Site admin

    Hi,

    Many thanks for posting back on this, and sorry I wasn't able to reply before. Thank you for digging into the issue - I'll look into when I'm next rooting around in the SearchBuilder code :)

    Allan

Sign In or Register to comment.