Hendrik
Hendrik

Reputation: 463

PrimeFaces Paginator JumpToPageDropdown Bug

I am migrating from PrimeFaces 6.2 to 8.0. In my project I am using multiple Primeface DataTables with a Paginator.

MCVE:

Create a data list with more than 10 elements. Then click through the different page numbers. When any page number bigger than 10 is clicked or selected from the JumpToPageDropdown the console will log the following error:

Error in Chrome console:

jquery.js.xhtml?ln=primefaces&v=8.0:2 Uncaught Error: Syntax error, unrecognized expression: option[value=\31 0]
    at Function.se.error (jquery.js.xhtml?ln=primefaces&v=8.0:2)
    at se.tokenize (jquery.js.xhtml?ln=primefaces&v=8.0:2)
    at se.compile (jquery.js.xhtml?ln=primefaces&v=8.0:2)
    at se.select (jquery.js.xhtml?ln=primefaces&v=8.0:2)
    at se (jquery.js.xhtml?ln=primefaces&v=8.0:2)
    at Function.se.matches (jquery.js.xhtml?ln=primefaces&v=8.0:2)
    at Function.k.filter (jquery.js.xhtml?ln=primefaces&v=8.0:2)
    at k.fn.init.k.fn.<computed> [as children] (jquery.js.xhtml?ln=primefaces&v=8.0:2)
    at c.updateUI (components.js.xhtml?ln=primefaces&v=8.0:58)
    at c.updateTotalRecords (components.js.xhtml?ln=primefaces&v=8.0:58)

Used component:

<p:dataTable id="datatable"value="#{backendController.dataList}"
    var="data" paginator="true" rows="1" paginatorPosition="top"
    pageLinks="20"
    paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {JumpToPageDropdown} {NextPageLink} {LastPageLink}">

    -> Add a few <p:column> tags.        

</p:dataTable>

Temporary fix:

I was able to identify that JumpToPageDropdown is causing the error. When this is removed from the paginatorTemplate the error will not be shown anymore when clicking on pages greater than 10. Unfortunately I want to use this dropdown.

Further research:

PrimeFaces uses these JS files for their components and hence also for the JumpToPageDropdown:

This are the respective calls to update the

Both versions:
this.jtpSelect = this.jq.children(".ui-paginator-jtp-select");

PrimeFaces 8.0:
this.jtpSelect.children("option[value=" + $.escapeSelector(this.cfg.page) + "]").prop("selected", "selected")

PrimeFaces 6.2:
this.jtpSelect.children("option[value=" + (this.cfg.page) + "]").prop("selected", "selected")

The difference is that in version 8.0 the value of this.cfg.page is passed to the function $.escapeSelector().

this.cfg.page uses zero-based numbering. Page 1 is 0, page 10 is 9 and so on. In version 6.2 this.jtpSelect.children() would be called with option[value=10] when the selected page is 11. But in version 8.0 $.escapeSelector() would format the same input to \31 0 and results in option[value=\31 0].

This in consequence leads to the error mentioned above. See this line: Uncaught Error: Syntax error, unrecognized expression: option[value=\31 0]

Recommendation:

If this is a bug $.escapeSelector() should be removed from this function in PrimeFaces 8.0, there is apparently no need for escaping: Numbers do not need to be escaped.

Upvotes: 1

Views: 527

Answers (1)

Hendrik
Hendrik

Reputation: 463

Solution:

After digging deep into the code I found a hack to fix the bug:

window.PrimeFaces.widget.Paginator.prototype.updateUI = function(){
    if (this.cfg.page === 0) {
        this.disableElement(this.firstLink);
        this.disableElement(this.prevLink)
    } else {
        this.enableElement(this.firstLink);
        this.enableElement(this.prevLink)
    }
    if (this.cfg.page === (this.cfg.pageCount - 1)) {
        this.disableElement(this.nextLink);
        this.disableElement(this.endLink)
    } else {
        this.enableElement(this.nextLink);
        this.enableElement(this.endLink)
    }
    var a = (this.cfg.rowCount === 0) ? 0 : (this.cfg.page * this.cfg.rows) + 1
      , c = (this.cfg.page * this.cfg.rows) + this.cfg.rows;
    if (c > this.cfg.rowCount) {
        c = this.cfg.rowCount
    }
    var e = this.cfg.currentPageTemplate.replace("{currentPage}", this.cfg.page + 1).replace("{totalPages}", this.cfg.pageCount).replace("{totalRecords}", this.cfg.rowCount).replace("{startRecord}", a).replace("{endRecord}", c);
    this.currentReport.text(e);
    if (this.cfg.prevRows !== this.cfg.rows) {
        this.rppSelect.filter(":not(.ui-state-focus)").children("option").filter('option[value="' + $.escapeSelector(this.cfg.rows) + '"]').prop("selected", true);
        this.cfg.prevRows = this.cfg.rows
    }
    if (this.jtpSelect.length > 0) {
        if (this.jtpSelect[0].options.length != this.cfg.pageCount) {
            var d = "";
            for (var b = 0; b < this.cfg.pageCount; b++) {
                d += '<option value="' + b + '">' + (b + 1) + "</option>"
            }
            this.jtpSelect.html(d)
        }
        this.jtpSelect.children("option[value=" + (this.cfg.page) + "]").prop("selected", "selected")
    }
    if (this.jtpInput.length > 0) {
        this.jtpInput.val(this.cfg.page + 1)
    }
    this.updatePageLinks()
}

Explanation:

The function updateUI of the Paginator widget causes the error. It can be accessed by window.PrimeFaces.widget.Paginator.prototype.updateUI and then be overwritten with the corrected version.

The changed line in the hack:

this.jtpSelect.children("option[value=" + (this.cfg.page) + "]").prop("selected", "selected")

The original line in PrimeFaces 8.0:

this.jtpSelect.children("option[value=" + $.escapeSelector(this.cfg.page) + "]").prop("selected", "selected").

Upvotes: 1

Related Questions