Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Paginator] Does not emit event when changed programatically #8417

Open
thw0rted opened this issue Nov 13, 2017 · 23 comments
Open

[Paginator] Does not emit event when changed programatically #8417

thw0rted opened this issue Nov 13, 2017 · 23 comments
Labels
area: material/paginator P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent
Projects

Comments

@thw0rted
Copy link

Bug, feature request, or proposal:

Bug

What is the expected behavior?

Changing the page index programmatically should emit a page event.

What is the current behavior?

Assigning to .pageIndex does not emit a page event. There is no method to jump to a specified page and ensure that an event is emitted.

What are the steps to reproduce?

Open this plunker. Enter a (different) page number in the input at the top of the page and click "Go To". The displayed paginator offset ("11-20") changes but the table results do not.

What is the use-case or motivation for changing an existing behavior?

The current behavior is wrong. The documentation for the page Output says "Event emitted when the paginator changes the page size or page index"; the page index has changed but the event was not emitted.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Still happening as of Beta 12, at least.

Is there anything else we should know?

I checked paginator.ts and the event is emitted in various methods that change the page index (next / previous) but not in the setting for pageIndex itself. I don't know why this design decision was made so I hesitate to suggest that it be changed, but we need some way to tell the paginator to go to a page as though the user had clicked to get to that page.

In the short term, I noticed that the private method _changePageSize is exposed in the typings for this component, and does not check if the size being set is the current size. So I can call

this.paginator._changePageSize(this.paginator.pageSize);

to force the paginator to emit a page event. Of course it's a pretty awful hack, but it gets the intended behavior. It'd be nice to avoid this in a future release.

@andrewseguin andrewseguin self-assigned this Nov 13, 2017
@jelbourn jelbourn added the P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent label Nov 14, 2017
@thw0rted
Copy link
Author

I meant to leave a trackback to #6220 in the original issue -- not exactly the same thing, but related.

@andrewseguin andrewseguin changed the title Paginator does not emit page event when assigning to pageIndex [Paginator] Does not emit event when changed programatically Nov 20, 2017
@andrewseguin andrewseguin added this to Discussion in Table Nov 20, 2017
@andrewseguin andrewseguin removed this from Discussion in Table Jan 23, 2018
@andrewseguin andrewseguin added this to Features in Paginator Jan 23, 2018
@andrewseguin andrewseguin moved this from Features to Bugs in Paginator Jan 23, 2018
@alexpearce92
Copy link

Came here with the same problem. I needed a way to keep paginator on the same page after a data update for a mattable. The pageSize hack from @thw0rted is still the best option.

For others using paginator with mattable, I had to set the pageIndex inside a timeout in order for paginator to detect that the pageIndex was changed:

@ViewChild(MatPaginator) paginator: MatPaginator;
public dataSource: MatTableDataSource<{ [id: string]: any }>;
...
refreshPaginator() {
  if (!this.dataSource.paginator) {
    this.dataSource.paginator = this.paginator;
  }

  let pageIndex = 0;
  ... // some math

  setTimeout((idx) => {
    this.paginator._pageIndex = idx;
    this.paginator._changePageSize(this.paginator.pageSize);
  }, 0, pageIndex);
}

@CraigComeOnThisNameCantBeTaken

I had to add this.paginator._changePageSize(this.paginator.pageSize); to get mine working also

@SurajSokasaneCB
Copy link

It says : "Property '_pageIndex' is private and only accessible within class 'MatPaginator'"

@thw0rted
Copy link
Author

Quite some time ago, I believe they added a public accessor for pageIndex so you don't have to use the underscore-prefixed field anymore. You still have to use the prefix for _changePageSize though.

@thw0rted
Copy link
Author

thw0rted commented Jun 28, 2019

I haven't looked at this in ages. @andrewseguin is there any debate about this? I'm pretty sure it's unambiguously a bug, and can be fixed by inserting a call to _emitPageEvent in the setter for pageIndex. Do you know why this has sat open for a year and a half? Would you accept a PR?

ETA: while we're at it, can we talk about why there are two different ways to change the page size (pageSize and _changePageSize()), one of which emits a page event and one of which doesn't?

@thw0rted
Copy link
Author

Hello again as we near the 2-year anniversary of this bug! #6220 just got auto-closed so I figured I should stop by here to provide some activity and avoid the same fate. Ping! 😁

@benelliott
Copy link
Contributor

@thw0rted Just FYI - that bot only locks already closed issues, it doesn't close them. So open issues like this should be OK without a bump.

@jimmykane
Copy link

Hi all any workaround on this ?

@AshotAleqs
Copy link

AshotAleqs commented Oct 31, 2019

Hello Everyone. Here is My working example.
first you need to change paginator.pageIndex
and emit event .page for a change page

this.paginator.pageIndex = this.currentPage;
this.dataSource.paginator.page.emit({
  length: this.paginator.getNumberOfPages(),
pageIndex: this.currentPage,
pageSize: 10,
previousPageIndex: this.previousPage 
})

@b-mi
Copy link

b-mi commented Dec 11, 2019

AshotAleqs solution works very good - without flickering (as with setTimeout). Little improvement:

      this.paginator.pageIndex = pageIndex;
      this.dataSource.paginator.page.emit({
        length: this.paginator.getNumberOfPages(),
        pageIndex: pageIndex,
        pageSize: this.paginator.pageSize
      })

@AshotAleqs
Copy link

AshotAleqs commented Dec 11, 2019

@b-mi ah I see, Thank you. I forgot to change my properties

@einarjohnson
Copy link

will this ever be fixed? :)

@alexpearce92
Copy link

What version is used where emitting the page event or using the public pageIndex works? In 7.2, the only working solution is still the one I posted above with _pageIndex and _changePageSize (use // @ts-ignore to ignore the private variable error)

@AshotAleqs
Copy link

Hello, @alexpearce92 I have used a 7.2 version of angular. And the solution works correctly. without any errors

@lorenzocovarrubiasjr
Copy link

What version is used where emitting the page event or using the public pageIndex works? In 7.2, the only working solution is still the one I posted above with _pageIndex and _changePageSize (use // @ts-ignore to ignore the private variable error)

Only works on my end with the setTimeout

@domin-sweet
Copy link

domin-sweet commented Nov 4, 2021

Using paginator.pageIndex setter does not emit PageEvent:

Ran into this again. Taking a look at the source, fairly confident that the problem is the fact that no PageEvent is emitted when you set the pageIndex via the setter.

Pretty sure where it is currently:

/** The zero-based page index of the displayed list of items. Defaulted to 0. */
  @Input()
  get pageIndex(): number {
    return this._pageIndex;
  }
  set pageIndex(value: number) {
    this._pageIndex = Math.max(coerceNumberProperty(value), 0);
    this._changeDetectorRef.markForCheck();
  }
  private _pageIndex = 0;

It needs to be more like this:

/** The zero-based page index of the displayed list of items. Defaulted to 0. */
  @Input()
  get pageIndex(): number {
    return this._pageIndex;
  }
  set pageIndex(value: number) {
    const previousPageIndex = this._pageIndex;
    this._pageIndex = Math.max(coerceNumberProperty(value), 0);
    this._emitPageEvent(previousPageIndex);
    this._changeDetectorRef.markForCheck();
  }
  private _pageIndex = 0;

I haven't seen any reason mentioned as to why we would explicitly NOT want to emit the PageEvent from the setter;
Maybe you could shed light on such a reason, if there is one? @andrewseguin

I did see: #6220 and #5822

The latter of which seemed to fix a problem with the change detection, however, this issue is distinctly different from the change detection. When you set the pageIndex you see the changes in the Paginator element, but the visible rows don't update unless you call one of the paging functions (which would negate the setting you did) or manually call paginator.emit() and specify the PageEvent values.

For quick fix:
Also, I did make a work around for the time being, for those of you who want a quick fix:

In my Component I get a reference to the paginator like so: @ViewChild(MatPaginator) paginator!: Paginator;

Then in my ngAfterViewInit() funciton I overwrite the getter and setter methods like so:

ngAfterViewInit() {
    /* ... */

    /** The zero-based page index of the displayed list of items. Defaulted to 0. */
    Object.defineProperty(this.paginator, 'pageIndex', {

      // same getter as source
      get: function (): number {
        return this._pageIndex;
      },

      // setter emits the PageEvent now
      set: function (value: number) {
        const previousPageIndex = this._pageIndex;
        this._pageIndex = Math.max(coerceNumberProperty(value), 0);
        this._emitPageEvent(previousPageIndex);
        this._changeDetectorRef.markForCheck();
      }
    });

    /* ... */
}

Then you can use the assignment operator as expected, like so:

someFunction () {
    /* ... */

    this.paginator.pageIndex = desiredPageIndex;
    
    /* ... */
}

@hjopel
Copy link

hjopel commented Feb 2, 2022

Update 2022: Tried both @alexpearce92 and @AshotAleqs workaround, however only @alexpearce92 's worked for me.

@celalettin-turgut
Copy link

celalettin-turgut commented Jan 17, 2023

Update 2023: I am still having the same issue. I can set pageSize dynamically without problem. But pageIndex does not emit. So I get the current page size from store and then assign them to my paginator with no success.

`

      this.dataSource.paginator = this.paginator;
      this.paginator.pageSize = paginator.pageSize;
      this.paginator.pageIndex = paginator.pageIndex;

      this.dataSource.paginator.page.emit({
        length: this.paginator.getNumberOfPages(),
        pageIndex: paginator.pageIndex,
        pageSize: paginator.pageSize
      } as PageEvent);

`

Only workaround that works me is setTimeout or delay pipe

With above code changes only pageSize

@andrewseguin andrewseguin removed their assignment Jun 3, 2023
@Thore1954
Copy link

@celalettin-turgut This behavior is seemingly intentional and a "fix" would break existing workflows. If you want to navigate programmatically, you should use the firstPage(), lastPage(), nextPage(), and previousPage() methods which all emit page event.

@thw0rted
Copy link
Author

thw0rted commented Aug 9, 2023

The original issue is about going directly to a page, not first/last or increment/decrement. Is there a method for jumping to a specific page?

@jpcmf
Copy link

jpcmf commented Aug 21, 2023

The original issue is about going directly to a page, not first/last or increment/decrement. Is there a method for jumping to a specific page?

@thw0rted Perhaps this link can help you: https://stackoverflow.com/a/51552039

@isoulaimane
Copy link

Hello All,
I have the same issue MatPaginator can't jump to a specific page changed programatically (v14.2)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: material/paginator P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent
Projects
No open projects
Paginator
  
Bugs
Development

No branches or pull requests