Inspirare-LLC / Radzen.Blazor.GridExportOptions

Radzen blazor grid export options
MIT License
4 stars 2 forks source link

Paging DG Export only for the Page #6

Open frankleib opened 2 years ago

frankleib commented 2 years ago

If you use Paging in a Datagrid you get only the actual page in Excel, not the complet Datasets

JonasPetraska commented 2 years ago

Hi. This functionality is intended to export only the visible data set, since it exports through DOM, it doesn't query database for more data. I suggest to use page size control to increase and decrease the visible data set. In my solutions I use it to export a full data set. You just have to set a high enough page size on the grid so that all of the elements show up. Then you can export them all just as a smaller data set. A user has control over how much data he wants to export by utilizing the page size control.

frankleib commented 2 years ago

I have a List of Classitemes generated from a csv from a FTP file sharing with different calcs as Source for the DG, no DB and the List is has a 30_000+ Elements, so I can't show it complet in the Browser, I have to worke with pages, in the other way I get error because the page is to complex/big. It s is a very nice tool, but I thing it s better to do it DG sourcebased instad of DOM, in this way it's would by perfect

JonasPetraska commented 2 years ago

That is an interesting suggestion. I will consider adding a different mode of export, "DataSource" mode, where you could provide a method for loading data. This component would in return export all of the data your method would return. Can't promise when exactly this would be implemented, but I hope this month :)

frankleib commented 2 years ago

sounds nice, do you have for support a paypal pool or so on for a little donate?

JonasPetraska commented 2 years ago

Hi. Sorry for the long delay, had a lot of other work in the way. I have implemented the first draft of the server data source mode. It is released as a prerelease nuget 3.3.0.1-servermode. Could you please download and test it on your side and give feedback?

To enable the server data source mode, you have to provide 4 additional parameters.

The working example would look something like this: <Radzen.Blazor.GridExportOptions.RadzenGridExportOptions Grid="@grid" CSVButtonStyle="Radzen.ButtonStyle.Info" NotExportableClass="not-exportable" DataSourceMode="true" LoadDataAllMethod="LoadDataAll" ReferenceValueFieldNames="GetReferenceValueFieldNames" HandleReferenceValue="HandleReferenceValue" />

async Task<IEnumerable<T>> LoadDataAll()
{
... data retrieval ...
}
IEnumerable<string> GetReferenceValueFieldNames()
{
    return new List<string>(){ "Customer_Id" };
}
async Task<string> HandleReferenceValue(string fieldName, string value)
{
   var res = "";

   if (fieldName == "Customer_Id")
       res = _customers.FirstOrDefault(x => x.Id == value).Name;
   //_customers is a list of customer object that has been loaded some time before.
   return res;
}
JonasPetraska commented 2 years ago

In regards to a donation, I don't actively promote it, however if you want to show appreciation in that way, please feel free to go to my profile and donate. Any donations will in some way be used to improve my open source work.

frankleib commented 2 years ago

Hi, I can't see a 3.3.0.1 NuGet package in the manager, sorry, but I don't know a way to test it

JonasPetraska commented 2 years ago

Hi. Please check "Include prerelease" checkbox to see the newest nuget package versions. Screenshot 2022-06-25 212708

frankleib commented 2 years ago

Thanks, the NuGet install works, but I don't understand how I use it, for my example

`using BOEERP.Common.WebHelper; using BOEERP.SuppliersArticleDataImport; using BOEERP.SuppliersArticleDataImport.Models; using Microsoft.AspNetCore.Components; using Radzen; using Radzen.Blazor;

namespace BOEERP.Pages { public partial class ArticleInfoImportSelect { [Parameter] public string? urlparamdata { get; set; } string pagingSummaryFormat = "Seite {0} von {1} (insgesamt {2} Artikel)"; RadzenDataGrid grid; private Dictionary<String, String> urlParameterDic = new(); FTPImportProfil fTPImportProfil = new(); FTPProfilDB fTPProfilDB; bool profilExists = false; IEnumerable pageSizeOptions = new int[] { 20, 100, 1000, 10000 }; IEnumerable? fTPImportElements; IList? fTPImportSelectedElements; bool finishLoadingData = false;

    void Open(string title, Type type, Dictionary<string, object> parameters, DialogOptions options)
    {

    }

    void Close(dynamic result)
    {

    }

    public void Dispose()
    {
        // The DialogService is a singleton so it is advisable to unsubscribe.
        DialogService.OnOpen -= Open;
        DialogService.OnClose -= Close;
    }

    protected override void OnInitialized()
    {
        DialogService.OnOpen += Open;
        DialogService.OnClose += Close;
    }

    void ShowNotification(NotificationMessage message)
    {
        NotificationService.Notify(message);
    }

    protected override void OnParametersSet()
    {
        if (fTPProfilDB is null)
        {
            LoadStartData();
        }

        if (fTPImportElements is not null && fTPImportElements.Count() > 0)
        {
            profilExists = true;
        }
        else
        {
            profilExists = false;
        }
    }

    //UI events
    async Task OnClickStartImport()
    {
        _ = BusyDialog();
        await Task.Run(() => Import());
        DialogService.Close();
    }

    //Function
    void LoadStartData()
    {
        finishLoadingData = false;

        urlParameterDic = new URIParameterDic().GetUriParameterDictionary(urlparamdata, "_br_", "_=_")!;
        fTPProfilDB = new FTPProfilDB(Convert.ToInt32(urlParameterDic["konto"]));
        fTPImportProfil = fTPProfilDB.fTPImportProfil!;
        if(fTPImportProfil is not null && fTPImportProfil.Id > 0)
        {
            fTPImportElements = (new FTPImport(fTPImportProfil.FTPImportParameter)).importElements;
        }

        if(fTPImportElements is not null && fTPImportElements.Count() > 0)
        {
            fTPImportElements = fTPImportElements.OrderByDescending(s => s.Identnr);
        }

        finishLoadingData = true;
    }

    void Import()
    {
        FTPUpdateE025 fTPUpdateE025 = new(fTPImportSelectedElements);
        if(fTPUpdateE025.Error)
        {
            ShowNotification(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "Import erfolgte mit Fehlern", Detail = fTPUpdateE025.ErrorTxt, Duration = 99999999 });
        }
        else
        {
            ShowNotification(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "Import erfolgreich: ", Detail = "Der Import war erfolgreich", Duration = 99999999 });
        }
    }

    //Grid Export
    async Task<IEnumerable<FTPImportElement>> LoadDataAll()
    {

    }

    IEnumerable<string> GetReferenceValueFieldNames()
    {
        return new List<string>() { "Customer_Id" };
    }

    async Task<string> HandleReferenceValue(string fieldName, string value)
    {
        var res = "";

        if (fieldName == "Customer_Id")
            res = fTPImportElements.FirstOrDefault(x => x.Id == value).Name;
        //_customers is a list of customer object that has been loaded some time before.
        return res;
    }

}

}

@page "/ftpimportselection/{urlparamdata?}" @using BOEERP.SuppliersArticleDataImport.Models @using Radzen @using BOEERP.Common.WebHelper @using Radzen.Blazor.GridExportOptions @using System.Threading;

@inject FTPFilesInDirService filesInDirService @inject NotificationService NotificationService @inject DialogService DialogService @inject TooltipService tooltipService @inject ContextMenuService ContextMenuService

@implements IDisposable

@if(profilExists) {

Auswahl Import Preise und Verfügbarkeiten von @urlParameterDic["konto"] @urlParameterDic["kontobez"]

<div>
    <RadzenButton Click=@(args => OnClickStartImport()) Text="Importieren" Icon="check_circle" ButtonStyle="ButtonStyle.Success"/>
    <RadzenGridExportOptions Grid="@grid" NotExportableClass="not-exportable" DataSourceMode="true" LoadDataAllMethod="LoadDataAll" ReferenceValueFieldNames="GetReferenceValueFieldNames" HandleReferenceValue="HandleReferenceValue" CsvExport="false" DateTimeFormat="dd.MM.yyyy" ExcelTitle="Excel Export" />
</div>
<hr>
<div>
    <RadzenDataGrid AllowFiltering="true" AllowMultiColumnSorting="true" AllowPaging="true" PageSize="20" AllowColumnReorder="false"
            PageSizeOptions="@pageSizeOptions" ShowPagingSummary="true" PagingSummaryFormat="@pagingSummaryFormat" PageSizeText="Artikel pro Seite"
            OrOperatorText="oder" AndOperatorText="und" ContainsText="enthält" StartsWithText="beginnt mit" EndsWithText="endet mit" DoesNotContainText="enthält nicht" IsNullText="is leer" IsNotNullText="ist nicht leer" ApplyFilterText="anwenden" ClearFilterText="leeren" 
            EqualsText="gleich" NotEqualsText="ungleich" LessThanText="kleiner als" LessThanOrEqualsText="kleiner gleich" GreaterThanText="größer als" GreaterThanOrEqualsText="größer gleich"
            AllowSorting="true" Data="@fTPImportElements" TItem="FTPImportElement" ColumnWidth="200px"
            SelectionMode="DataGridSelectionMode.Multiple" @bind-Value=@fTPImportSelectedElements>
        <Columns>
            <RadzenDataGridColumn TItem="FTPImportElement" Width="20px" Sortable="false" Filterable="false" CssClass="exclude-from-radzen-export" HeaderCssClass="exclude-from-radzen-export">
                <HeaderTemplate>
                    <RadzenCheckBox TriState="false" TValue="bool" Value="@(fTPImportElements.Any(i => fTPImportSelectedElements != null && fTPImportSelectedElements.Contains(i)))"
                                Change="@(args => fTPImportSelectedElements = args ? fTPImportElements.ToList() : null)" />
                </HeaderTemplate>
                <Template Context="data">
                    <RadzenCheckBox TriState="false" Value="@(fTPImportSelectedElements != null && fTPImportSelectedElements.Contains(data))" />
                </Template>
            </RadzenDataGridColumn>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="Lieferant" Title="Lieferant" Width="0px" CssClass="radzen-blazor-gridexportoptions-column-number"/>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="Identnr" Title="Artikelnummer" Width="70px" CssClass="radzen-blazor-gridexportoptions-column-number" />
            <RadzenDataGridColumn TItem="FTPImportElement" Property="Bezeichnung" Title="Bezeichnung" Width="300px" CssClass="radzen-blazor-gridexportoptions-column-number"/>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="Menge_ab" Title="Ab-Menge" Width="60px" TextAlign="TextAlign.Right"/>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="Ekpreis" Title="EK-Preis"  Width="60px" TextAlign="TextAlign.Right"/>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="Menge_verf" Title="verf.Menge"  Width="60px" TextAlign="TextAlign.Right"/>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="Liefterm" Title="Liefertermin" FormatString="{0:d}"  Width="70px" TextAlign="TextAlign.Right"/>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="anp_ve_lief" Title="VE"  Width="60px" TextAlign="TextAlign.Right"/>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="anp_palmenge" Title="PAL"  Width="60px" TextAlign="TextAlign.Right"/>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="EAN" Title="EAN" Width="100px" CssClass="radzen-blazor-gridexportoptions-column-number"/>
            <RadzenDataGridColumn TItem="FTPImportElement" Property="Kdidentnr" Title="Artikel-Lieferant" CssClass="radzen-blazor-gridexportoptions-column-number"/>
        </Columns>
    </RadzenDataGrid>
</div>

} else { @if(finishLoadingData == false && fTPImportElements is null) {

Daten werden abgerufen
}
else
{
    <br/>
    <br/>
    <br/>
    <br/>
    <br/>
    <br/>
    <h2 style="text-align:center; color:red">keine Daten gefunden</h2>
}

}

@code { async Task BusyDialog() { await DialogService.OpenAsync("", ds => @

Import läuft, bitte warten oder in b7 in anderer Maske weiterarbeiten...
    </div>, new DialogOptions() { ShowTitle = false, Style = "min-height:auto;min-width:auto;width:auto", CloseDialogOnEsc = false });
}

} `

frankleib commented 2 years ago

with IEnumerable<string> GetReferenceValueFieldNames() { return new List<string>() { "Lieferant", "Identnr", "Bezeichnung", "Menge_ab", "Ekpreis", "Menge_verf", "Liefterm", "anp_ve_lief", "anp_palmenge", "EAN", "Kdidentnr" }; }

and <Radzen.Blazor.GridExportOptions.RadzenGridExportOptions Grid="@grid" CSVButtonStyle="Radzen.ButtonStyle.Info" NotExportableClass="not-exportable" DataSourceMode="true" LoadDataAllMethod="LoadDataAll" ReferenceValueFieldNames="GetReferenceValueFieldNames" HandleReferenceValue="HandleReferenceValue" />

I get a "Severity Code Description Project File Line Suppression State Error (active) CS1503 Argument 14: cannot convert from 'method group' to 'IEnumerable' BOEERP c:\Users\frank\OneDrive\Arbeit\Böttcher\BOEERP\BOEERP\BOEERP\Pages\ArticleInfoImportSelect.razor 22
"

JonasPetraska commented 2 years ago

Hi,

I see the problem now. I have made a mistake in my sample. "ReferenceValueFieldNames " has to be an IEnumerable, not a function. You can try replacing yours with: ReferenceValueFieldNames="@(() => GetReferenceValueFieldNames())".

My apologies for the mistake.

frankleib commented 2 years ago

=>Severity Code Description Project File Line Suppression State Error (active) CS1660 Cannot convert lambda expression to type 'IEnumerable' because it is not a delegate type BOEERP c:\Users\frank\OneDrive\Arbeit\Böttcher\BOEERP\BOEERP\BOEERP\Pages\ArticleInfoImportSelect.razor 24
:-)

JonasPetraska commented 2 years ago

Okay, lets try again. use "@GetReferenceValueFieldNames()" instead of "@(() => GetReferenceValueFieldNames())".

frankleib commented 2 years ago

this is working, thank you!

but it will freeze yet.

public class FTPImportElement { public int Id { get; set; } public int Lieferant { get; set; } public string? Kdidentnr { get; set; } public string? EAN { get; set; } public string? Identnr { get; set; } public string? Bezeichnung { get; set; } public decimal Menge_ab { get; set; } = 0; public decimal Ekpreis { get; set; } public decimal? Menge_verf { get; set; } public DateTime? Liefterm { get; set; } public decimal? anp_ve_lief { get; set; } public decimal? anp_palmenge { get; set; }

    private string _errorContent = "";

    public string ErrorContent
    {
        get { return _errorContent; }
        set { _errorContent += value; }
    }

    public bool selected { get; set; }
    public bool Error { get; set; } = false;

    public bool setIdentnr()
    {
        try
        {
            using (SqlConnection connection = new SqlConnection(B7DB.b7MSQLConnetionString))
            {
                connection.Open();

                int count = 0;
                SqlCommand cmd = new SqlCommand("select identnr from g040 where ean=" + EAN, connection);
                SqlDataReader sdr = cmd.ExecuteReader();

                if (sdr.HasRows)
                {
                    while (sdr.Read())
                    {
                        if (count > 0)
                        {
                            throw new Exception("Mehr als ein Ergebnis bei der identnr-Suche für g030.ean=" + EAN);
                        }

                        Identnr = sdr.GetString(0);

                        count++;
                    }
                }
                else
                {
                    Identnr = "";
                }
            }
        }
        catch (Exception e)
        {
            Error = true;
            ErrorContent = " // FTPProfilDB getFTPImportProfil(int _Lieferant) select: " + e.ToString();
        }

        return true;
    }
}

IEnumerable? fTPImportElements;

void LoadStartData() { finishLoadingData = false;

        urlParameterDic = new URIParameterDic().GetUriParameterDictionary(urlparamdata, "_br_", "_=_")!;
        fTPProfilDB = new FTPProfilDB(Convert.ToInt32(urlParameterDic["konto"]));
        fTPImportProfil = fTPProfilDB.fTPImportProfil!;
        if(fTPImportProfil is not null && fTPImportProfil.Id > 0)
        {
            fTPImportElements = (new FTPImport(fTPImportProfil.FTPImportParameter)).importElements;
        }

        if(fTPImportElements is not null && fTPImportElements.Count() > 0)
        {
            fTPImportElements = fTPImportElements.OrderByDescending(s => s.Identnr);
        }

        finishLoadingData = true;
    }

async Task<IEnumerable> LoadDataAll() { return fTPImportElements; }

    IEnumerable<string> GetReferenceValueFieldNames()
    {
        return new List<string>() { "Lieferant", "Identnr", "Bezeichnung", "Menge_ab", "Ekpreis", "Menge_verf", "Liefterm", "anp_ve_lief", "anp_palmenge", "EAN", "Kdidentnr" };
    }

    async Task<string> HandleReferenceValue(string fieldName, string value)
    {
        var res = "";

        if (fieldName == "Lieferant")
        {
            res = fTPImportElements.FirstOrDefault(x => x.Lieferant.ToString() == value).ToString();
        }

        return res;
    }
JonasPetraska commented 2 years ago

Are there a lot of rows? Can you specify when and how it freezes?

frankleib commented 2 years ago

30_000 rows

frankleib commented 2 years ago

I have a breakpoint in all 3 methods and it freeze after async Task<IEnumerable> LoadDataAll() { return fTPImportElements; } after the click

frankleib commented 2 years ago

can you please upload a complete example for use, because it's possible, that it is my mistake

frankleib commented 2 years ago

[2022-07-09T21:59:26.664Z] Error: System.NullReferenceException: Object reference not set to an instance of an object. at Radzen.Blazor.GridExportOptions.RadzenGridExportOptions1.GetVisibleColumns() at Radzen.Blazor.GridExportOptions.RadzenGridExportOptions1.ExportToExcel() at System.Threading.Tasks.Task.<>c.b__128_0(Object state) at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteSynchronously(TaskCompletionSource`1 completion, SendOrPostCallback d, Object state) at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.<>c.<.cctor>b__23_0(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteBackground(WorkItem item)

JonasPetraska commented 2 years ago

Hi. My deepest apologies for a late answer. I have been looking into this and I think currently exporting large data is not possible, because there is a serialization limit while passing data to JS function via JS interop. In regards to the last error "Null reference" it is hard to debug what can be "null" there since I don't see a complete example. Can you provide one? Or you can import this project manually (not nuget package) and debug yourself. That would be much appreciated.