-
Notifications
You must be signed in to change notification settings - Fork 803
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
[Tutorial] Custom grid & grid pager without counting total records #4458
Comments
Thanks @minhhungit, this is really useful! I'm also interested to see how/where you are tracking user actions? |
@edwardch it's not complex, just put your "insert log" code into your methods, it will insert new record into a "action log" table, the rest, serenity will generate form for you |
Hi everyone, here is new code, at this version we implement it as a "mixin" btw, I am waiting this pull request #4474, if that PR is approved then we can use CustomData and we don't need to create MyBaseListRequest.cs public interface IPagingRequest
{
bool EnableOnlyNextPreviousMode { get; set; }
}
public class MyBaseListRequest : ListRequest, IPagingRequest
{
public bool EnableOnlyNextPreviousMode { get; set; }
} CustomPagerWithOnlyNextPreviousMixin.ts namespace [YOUR_NAME_SPACE].Common {
export class CustomPagerWithOnlyNextPreviousMixin<TItem> {
private options: CustomPagerWithOnlyNextPreviousMixinOptions<TItem>;
private dataGrid: Serenity.DataGrid<TItem, any>;
private _customPagerCurrentPage: number = 1;
private _customPager: JQuery = $("<span class='next-previous-pager'><button class='custompager-pre'><strong>«</strong> Previous</button><span style='padding: 0 2px;'></span><button class='custompager-next'>Next <strong>»</strong></button><span style='padding: 0 2px;'></span><b>Page</b> <span class='custompager-curpage'>1</span></span>");
private _originalPager = $(".s-SlickPager");
private _pagingMode: ('full' | 'next-previous-only');
private _btnSwitch: JQuery;
constructor(options: CustomPagerWithOnlyNextPreviousMixinOptions<TItem>) {
var self = this;
this.options = options;
var dg = this.dataGrid = options.grid;
this._pagingMode = options.pagingMode = options.pagingMode || 'next-previous-only';
$(".slick-pg-in").hide();
this._originalPager.find(".slick-pg-in").append(this._customPager);
var btnSwitch = this._btnSwitch = $('<input type="checkbox" title="Full Pager" class="paging-mode-switch pull-right" style="margin-right: 5px" ' + (options.pagingMode == "full" ? ' checked' : '') + '/>')
.appendTo(dg.element.find(".slick-pg-in"));
btnSwitch.change((evt) => {
var isFullMode: boolean = $(evt.target).is(":checked");
// update current page number
if (!isFullMode) {
this._customPagerCurrentPage = parseInt($(".slick-pg-current").val());
this._originalPager.find(".custompager-curpage").text($(".slick-pg-current").val());
}
this.switchView(isFullMode ? 'full' : 'next-previous-only');
});
this._originalPager.find(".custompager-pre").click(e => {
if (this._customPagerCurrentPage > 1) {
this._customPagerCurrentPage--;
this.dataGrid.view.seekToPage = this._customPagerCurrentPage;
this.dataGrid.refresh();
this._originalPager.find(".custompager-curpage").text(this._customPagerCurrentPage);
}
return;
});
this._originalPager.find(".custompager-next").click(e => {
this._customPagerCurrentPage++;
this.dataGrid.view.seekToPage = this._customPagerCurrentPage;
this.dataGrid.refresh();
this._originalPager.find(".custompager-curpage").text(this._customPagerCurrentPage);
return;
});
dg.view.onDataChanged.subscribe(() => {
this.updatePageControls(!$(this._btnSwitch).is(":checked"));
});
// save setting
var oldCurrentSettings = (dg as any).getCurrentSettings;
(dg as any).getCurrentSettings = function (flag) {
var settings = oldCurrentSettings.apply(dg, [flag]);
settings['customPagerMode'] = $(btnSwitch).is(":checked") ? 'full' : 'next-previous-only';
return settings;
};
var oldRestoreSettings = (dg as any).restoreSettings;
(dg as any).restoreSettings = function (settings, flags) {
oldRestoreSettings.apply(dg, [settings, flags]);
if (settings == null) {
var storage = this.getPersistanceStorage();
if (storage == null) {
self.switchView(self._pagingMode);
return;
}
var json = Q.trimToNull(storage.getItem(this.getPersistanceKey()));
if (!json) {
self.switchView(self._pagingMode);
return;
}
settings = JSON.parse(json);
}
var viewPagerMode = settings.customPagerMode || self._pagingMode;
var currentViewPagerMode = $(btnSwitch).is(":checked") ? 'full' : 'next-previous-only';
if (viewPagerMode != currentViewPagerMode) {
$(btnSwitch).click();
}
};
}
public updateNextButton(nbrOfRecords: number, nbrOfRowsPerPage: number): void {
if (this.options.pagingMode === 'full') {
return;
}
if (nbrOfRecords == 0 || nbrOfRecords < nbrOfRowsPerPage) {
this._originalPager.find(".custompager-next").prop("disabled", true);
this._originalPager.find(".custompager-next").css("opacity", 0.5);
}
else {
this._originalPager.find(".custompager-next").prop("disabled", false);
this._originalPager.find(".custompager-next").css("opacity", 1);
}
}
private switchView(pMode: ('full' | 'next-previous-only')): void {
this.updatePageControls(pMode == "next-previous-only");
this.dataGrid.refresh();
(this.dataGrid as any).persistSettings();
}
private updatePageControls(isNextPreviousOnlyMode: boolean) {
if (isNextPreviousOnlyMode) {
this._originalPager.find(".next-previous-pager").show();
this._originalPager.find(".slick-pg-grp").hide();
this._originalPager.find(".slick-pg-sep").hide();
this._originalPager.find(".slick-pg-grp:first").show();
}
else {
this._originalPager.find(".next-previous-pager").hide();
this._originalPager.find(".slick-pg-grp").show();
this._originalPager.find(".slick-pg-sep").show();
}
$(".slick-pg-in").show();
}
public getCurrentPagerMode(): ('full' | 'next-previous-only') {
return $(this._btnSwitch).is(":checked") ? 'full' : 'next-previous-only';
}
}
export class CustomPagerWithOnlyNextPreviousMixinOptions<TItem> {
grid: Serenity.DataGrid<TItem, any>;
rowPerPage: number;
pagingMode?: ('full' | 'next-previous-only');
}
} Endpoint.cs public ListResponse<MyRow> List(IDbConnection connection, MyBaseListRequest request)
{
return new MyRepository().List(connection, request);
} Repository.cs public ListResponse<MyRow> List(IDbConnection connection, MyBaseListRequest request)
{
return new MyListHandler().Process(connection, request);
}
public class CustomListRequestHandle<TRow> : ListRequestHandler<TRow> where TRow : Row, new()
{
protected override void ApplyFilters(SqlQuery query)
{
base.ApplyFilters(query);
if (Request is MyBaseListRequest customRequest)
{
if (customRequest.EnableOnlyNextPreviousMode)
{
query.ApplySkipTakeAndCount(this.Request.Skip, this.Request.Take, this.Request.ExcludeTotalCount || DistinctFields != null);
// Setting CountRecords to false stops the count(*) query from running
query.CountRecords = false;
}
}
}
} Grid.ts /// <reference path="../../common/mixin/custompagerwithonlynextpreviousmixin.ts" />
private _pagerMixin: Common.CustomPagerWithOnlyNextPreviousMixin<Your_Row>;
protected onViewProcessData(response: Serenity.ListResponse<Your_Row>): Serenity.ListResponse<Your_Row> {
var lr = super.onViewProcessData(response);
this._pagerMixin.updateNextButton(lr.Entities.length, response.Take);
return lr;
}
protected getViewOptions() {
var opt = super.getViewOptions();
opt.rowsPerPage = 20;
return opt;
}
protected createToolbarExtensions(): void {
super.createToolbarExtensions();
var self = this;
this._pagerMixin = new Rydell.Web.Common.CustomPagerWithOnlyNextPreviousMixin({
grid: this,
rowPerPage: this.getPagerOptions().rowsPerPage
});
}
protected onViewSubmit() {
if (!super.onViewSubmit()) {
return false;
}
var request = this.view.params as MyBaseListRequest;
request.EnableOnlyNextPreviousMode = this._pagerMixin.getCurrentPagerMode() == 'next-previous-only';
return true;
}
protected getPersistanceStorage(): Serenity.SettingStorage {
return new Common.UserPreferenceStorage();
} Feel free to ask any question 💖 |
I have allowed myself to change the title of your wiki entry to: Grid: .... (categorized it under Grid for being better findable) Maybe you want to update your link in this post to: https://github.com/volkanceylan/Serenity/wiki/Grid:-Custom-grid-&-grid-pager-without-counting-total-records And if you don't mind: Put also your mixin code into your wiki - as you say there that it is beter to do a mixin. :-) With kind regards, John |
@JohnRanger I will update wiki soon, thank you ! |
I updated wiki, here is link: Grid Mixin Custom grid pager without counting total records |
@minhhungit - thanks very much :-) John |
@kilroyFR I can not reproduce it, I tried some times on some my projects with I don't your problem. |
Issue occurs when you have others GRIDS in tabs (looks like the grids in the tabs inherit from the main grid) |
@kilroyFR I can reproduce the issue now, will try to fix |
@kilroyFR I fixed and updated wiki, pls check it |
sorry I was quite busy so I couldn't reply you sooner |
Wow Much Awesome, looks like it works like a charm. Many thanks ! |
Relate to some issues at here #4250 , #4399
I created a post to demo how to create a custom grid which just has only next/previous buttons, it will not count total records so in some cases (ex, table with many records) we won't worry about timeout issue
Here it is: Grid Mixin Custom grid pager without counting total records
Screenshot
The text was updated successfully, but these errors were encountered: