GithubHelp home page GithubHelp logo

anmcgrath / blazordatasheet Goto Github PK

View Code? Open in Web Editor NEW
139.0 11.0 33.0 111.38 MB

Simple excel-like datasheet Blazor component

License: MIT License

HTML 12.87% C# 83.17% CSS 1.68% JavaScript 2.29%
blazor blazor-component blazor-server blazor-webassembly datasheet editor spreadsheet excel csharp

blazordatasheet's Introduction

BlazorDatasheet

A simple datasheet component for editing tabular data.

DatasheetScreenshot

Features

  • Data editing
    • Built in editors including text, date, select, boolean, text area, enum
    • Add custom editors for any data type
  • Conditional formatting
  • Data validation
  • Formula
  • Keyboard navigation
  • Copy and paste from tabulated data
  • Virtualization - handles many cells at once in both rows & cols.

Demo: https://anmcgrath.github.io/BlazorDatasheet/

Getting Started

Install the NuGet package

dotnet add package BlazorDatasheet

Configure Program.cs

In Program.cs, add the required services:

builder.Services.AddBlazorDatasheet();

Import JS/CSS

In _Layout.cshtml or index.html add

<link href="_content/BlazorDatasheet/sheet-styles.css" rel="stylesheet"/>

and

<script src="_content/BlazorDatasheet/blazor-datasheet.js" type="text/javascript"></script>

Blazor Datasheet provides a Datasheet Blazor component that accepts a Sheet.

A Sheet holds the data and configuration for a Datasheet. The data is set per Cell, or can be built using the ObjectEditorBuilder, which creates a datasheet based on a list of objects.

The following code displays an empty 3 x 3 data grid.

<Datasheet
    Sheet="sheet"/>

@code{

    private Sheet sheet;

    protected override void OnInitialized()
    {
        sheet = new Sheet(3, 3);
    }

}

The default editor is the text editor, but can be changed by defining the Type property of each cell.

Setting & getting cell values

Cell values can be set in a few ways:

sheet.Cells[0, 0].Value = "Test"
sheet.Range("A1").Value = "Test";
sheet.Cells.SetValue(0, 0, "Test");
sheet.Commands.ExecuteCommand(new SetCellValueCommand(0, 0, "Test"));

In this example, the first two methods set the value but cannot be undone. The last two methods can be undone.

Formula

Formula can be applied to cells. When the cells or ranges that the formula cells reference change, the cell value is re-calculated.

Currently, the whole sheet is calculated if any referenced cell or range changes.

sheet.Cells[0, 0].Formula = "=10+A2"

Formatting

Cell formats can be set in the following ways:

sheet.Range("A1:A2").Format = new CellFormat() { BackgroundColor = "red" };
sheet.Commands.ExecuteCommand(
    new SetFormatCommand(new RowRegion(10, 12), new CellFormat() { ForegroundColor = "blue" }));
sheet.SetFormat(sheet.Range(new ColumnRegion(5)), new CellFormat() { FontWeight = "bold" });
sheet.Cells[0, 0].Format = new CellFormat() { TextAlign = "center" };

When a cell format is set, it will be merged into any existing cell formats in the region that it is applied to. Any non-null format paremeters will be merged:

sheet.Range("A1").Format = new CellFormat() { BackgroundColor = "red" };
sheet.Range("A1:A2").Format = new CellFormat() { ForegroundColor = "blue" };
var format = sheet.Cells[0, 0].Format; // backroundColor = "red", foreground = "blue"
var format2 = sheet.Cells[1, 0].Format; // foreground = "blue"

Cell types

The cell type specifies which renderer and editor are used for the cell.

sheet.Range("A1:B5").Type = "boolean"; // renders a checkbox

Custom editors and renderers can be defined. See the examples for more information.

Validation

Data validation can be set on cells/ranges. There are two modes of validation: strict and non-strict. When a validator is strict, the cell value will not be set by the editor if it fails validation.

If validation is not strict, the value can be set during editing but will show a validation error when rendered.

Although a strict validation may be set on a cell, the value can be changed programmatically, but it will display as a validation error.

sheet.Validators.Add(new ColumnRegion(0), new NumberValidator(isStrict: true));

Regions and ranges

A region is a geometric construct, for example:

var region = new Region(0, 5, 0, 5); // r0 to r5, c0 to c5
var cellRegion = new Region(0, 0); // cell A1
var colRegion = new ColumnRegion(0, 4); // col region spanning A to D
var rowRegion = new RowRegion(0, 3); // row region spanning 1 to 4

A range is a of region that also knows about the sheet. Ranges can be used to set certain parts of the sheet.

var range = sheet.Range("A1:C5);
var range = sheet.Range(new ColumnRegion(0));
var range = sheet.Range(0, 0, 4, 5);

blazordatasheet's People

Contributors

anmcgrath avatar for7raid avatar jasonswearingen avatar naratteu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blazordatasheet's Issues

How can the template feature be implemented?

How can the template feature be implemented? For example, designing the table header, column headers, and placeholders for each column in advance, as well as the field types for each column, and then filling in the data according to the template definition each time data is loaded. Can this be achieved? Are there any good approaches?

How to use it in my project ?

dude i could not find it on nuget , is it not production ready or what ? i am interested to use it in my project as demo looks grt but could not figure out where is the library :(

Bug: Insert/Remove Cols/Rows not working

When implementing the Inserting/Removing Cols/Rows button, I noticed that it wasn't working properly, it was adding blank spaces and it actually required the user to select a field to work, I think it could just add a new one to the end.

I tried it out on your deployed version and got the same result:

image

I also noticed that when you scroll to the start of the page and then scroll back, the insert/remove action that you did will appear, instead of the blank spaces. Maybe this help you to debug and find the solution quicker. It's just pretty unconsistent.

Help - Code example of ObjectEditor, how can I add a new or delete an old item?

@page "/ObjectEditor"
@using BlazorDatasheet.Render
@using BlazorDatasheet.SharedPages.Data
@using BlazorDatasheet.Core.Formats
@using BlazorDatasheet.Core.ObjectEditor
@using BlazorDatasheet.Core.Validation

<PageTitle>Object editor</PageTitle>

<h1>Object Editor</h1>

<p>This example shows one method of using metadata and cell change events to create an object property editor for a set of objects.</p>

<p>In this example we have a datasource of 100 people and set up a page size of 10. When the page is changed, the Sheet data is overidden from the new data.</p>

<Datasheet
    @ref="dataSheet1"
    CustomCellTypeDefinitions="CustomTypes"
    Sheet="editor.Sheet">
</Datasheet>

<p>Page @(editor.CurrentPage + 1) of @editor.NumPages</p>

<button @onclick="() => editor.SetPage(editor.CurrentPage - 1)">Previous Page</button>
<button @onclick="() => editor.SetPage(editor.CurrentPage + 1)">Next Page</button>
<button @onclick="() => addNewPeople()">Add New One</button>

@code {

    private List<Person> People;
    private ObjectEditor<Person> editor;
    private Datasheet dataSheet1;
    private Dictionary<string, CellTypeDefinition> CustomTypes { get; } = new();

    protected override void OnInitialized()
    {
        People = new List<Person>();
        var r = new Random();
        for (int i = 0; i < 20; i++)
        {
            People.Add(new Person() { Id = i + 1, FirstName = "Person " + i, LastName = "LastName " + i, Age = (r.Next(90) + 10).ToString() });
        }

        var builder = new ObjectEditorBuilder<Person>(new EnumerableQuery<Person>(People))
     .WithRowHeadingSelector(x => x.Id.ToString())
     .WithPageSize(10)
     .WithProperty(x => x.FirstName)
     .WithProperty(x => x.LastName)
     .WithProperty(x => x.Age,
         x =>
             x.WithDataValidator(new NumberValidator(true))
     ).WithProperty(x => x.IsFriendly,
         x =>
             x.WithType("boolean"));
        editor = builder.Build();

        base.OnInitialized();
    }

    private void addNewPeople()
    {
        People.Add(new Person{
            Id = People.Count + 1, FirstName = "New Person " + People.Count, LastName = "LastName " + People.Count, Age = "20" });
        // TODO:  Rebuild the editor
        // How?

    }


}

Deploy on a new VS2022 Blazer Project

Hi anmcgrath.. I´ve tried the demo, and a great component...
I´ve also downloaded your BlazorDatasheet component package from this git repository into Visual Studio 2022 (with NET8.0), built only the server project (blazordatasheet.server), and also worked fine.. The same main page of the Demo was available.
But now i´d like to create a entire new Blazer Project (NET8.0 and server rendering), to test the BlazorDatasheet component, but i got some issues:
The same main demo page should be shown.. but only the external border with scroll bars was showed.. the functional part of the datasheet, no.. (the datasheet grid layout, headers, cells, lines, etc.. nothing.. totally blanked.. ).
Please, could you give some help to fix this issue? to identify which point or config is necessary to work fine as the built of DataSheet.Server Project... (Could be something about the stylish definitions, and rendering?)

  1. On this new project i´ve included/copied this projects/code from this git repository:
  • BlazorDatasheet
  • BlazorDatasheet.Core
  • BlazorDatasheet.DataStructures
  • BlazorDatasheet.Formula.Core
  • BlazorDatasheet.Formula.Functions
  • BlazorDatasheet.SharedPages
  1. Included on app.razor file (from new Server Blazor Project) this aditional lines:

    <script src="_content/BlazorDatasheet/blazor-datasheet.js" type="text/javascript"></script>
  2. Include on my main Blazer Page file a tag for call/Reuse the main page from demo and server project (Index Page) :
    <BlazorDatasheet.SharedPages.Pages.Index />

In advance, thks for some orientation..

Issue when the NuGet package was updated from 0.2.1 to 0.3.0 (BlazorDatasheet.Menu.SheetMenuTarget)

image

I'm mainly using the Object Editor and it is a very simple example, I just updated the package to the new release and fixed the compiler errors, such as SetWidth -> SetSize, InsertRowAt -> InsertAt and others, then I noticed that all my pages that were using the Datasheet or the Sheet component were not loading, throwing an error on the console related to SheetMenuTarget, it looked like I was forgetting to import some JS or something else, that's just my guess, since I didn't see any changes on the READ.ME.

I also tried the simplest possible example (SimpleExample.razor) and I encountered the same error
When I run the 0.2.1 version everything goes well btw

Question: alternate approaches to binding data?

Hi I am wondering if it's possible to separate the datasheet "presentation" from the underyling data a bit more than shown in the example.

For example, in the index.razor it generates a List<Person> which is then fed into the ObjectEditorBuilder. Instead of passing a list of rows, Is there a way to instead pass a List of columns, that are bound to some backing Data (one Data List per column)? With the underlying Data being updated when the datasheet changes (or vice-versa)?

If this is not currently possible, how would you suggest I attempt to go about adding such a feature?

Thank you for reading this :)

Allow Focusing Datasheet Element

As seen on the demo page, when the user clicks a button outside of the datasheet, they are forced to click again onto the datasheet in order to resume typing. As default functionality this is fine, but it would be nice to expose a way to re-focus the datasheet so that the user can seamlessly resume typing after clicking an external button without needing to click back onto the datasheet where they were.

This is especially useful for button effects that change the users selection, so that they can then instantly start typing.

Fantastic component library by the way, it's incredibly flexible!

Change date format?

Is there any way to set a format for how a date is displayed? We've only been able to get it to use MM/DD/YYYY HH:MM:SS but for the data we're working with the timestamp isn't necessary.

Values changes to DateTime in different CultureInfo !

Hi, at first I thank you for this nice component, I appriciate you for sharing it,
When we use a different CultureInfo for example persian ( fa-IR ) , after entring a float value in a cell for example 3.5 , component changes it to 1403/3/5 0:00:00 that's a date in persian calendar, How I can fix it?

My regards

Bug: GetViewPort ('0' cannot be greater than -1.)

In: SimpleExample.razor

Change:

    protected override void OnInitialized()
    {
        sheet = new Sheet(numRows: 100000, numCols: 20000);
    }

To:

    protected override void OnInitialized()
    {
        sheet = new Sheet(numRows: 0, numCols: 20000);
    }

(I am sure you're like "Why??" but in my program I am loading data from a database and the table may be empty. I allow you to add rows so that is why I would want to load an empty table)

When you run it you get:

System.ArgumentException
  HResult=0x80070057
  Message='0' cannot be greater than -1.
  Source=System.Private.CoreLib
  StackTrace:
   at System.Math.ThrowMinMaxException[T](T min, T max)
   at System.Math.Clamp(Int32 value, Int32 min, Int32 max)
   at BlazorDatasheet.Core.Layout.CellLayoutProvider.GetViewPort(Double left, Double top, Double containerWidth, Double containerHeight, Int32 overflowX, Int32 overflowY) in C:\Users\webma\Source\Repos\BlazorDatasheet\src\BlazorDatasheet.Core\Layout\CellLayoutProvider.cs:line 188
   at BlazorDatasheet.Datasheet.HandleScroll(ViewportScrollInfo e) in C:\Users\webma\Source\Repos\BlazorDatasheet\src\BlazorDatasheet\Datasheet.razor.cs:line 333
   at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

image

image

Column Sorting?

I don't see that this component supports sorting.
I am willing to code this and submit a PR.
Before I do so, I wanted to make sure this was not already planned.

My proposed plan:

  • Allow an event to be added to headers (the way validators can be added)
  • When clicked the Header and the reversible sort direction would be sent
  • Custom code can then decide how to handle the sort request (for example reload the sheet with the selected sort)

Note: I am working on pulling data from a database: https://github.com/ADefWebserver/BlazorDatasheet/blob/main/src/BlazorDatasheet.SharedPages/Pages/DataEditor.razor

image

Select cell with multiple options

I found myself in a scenario where I need to have an EnumFlags column.
In order to do that, I'm using a select typed cell, the same type that I'm using for FK constraints on the sheet. The problem is that EnumFlags requires multiples entries, not only one single value, I'm wondering if someone else have been through a similar scenario or if there is a better approach to this, maybe with a component that I don't know yet.

image

I'm thinking about just opening a modal from this cell and using checkboxes for each enum field and some other work arounds as well, but it would be brilliant if there is something like that native from your repository.

[Question] How to Add a column while running, bound to items? Also question about replacing Sheet

Hi, I'm finally at the point where I can play with this cool sheet library again.

I see in the main demo I can add new columns at runtime, but they are not bound to the existing Items

What is the suggested approach? Like if I had some additional property that I want to add later.

It looks like one way I could do this by making Sheet.SetCell() public then looping through and setting the Cell values manually.

On a related note, it looks like Sheet is designed to support being replaced, is that true? I am imagining rewriting it, simplified down to only support my requirements. (data stored in rows, and all types/formatting defined per column). If you think it's doable I'd love to hear, or what issues you think I might come across.

CSV Support

Hi,

can i get sample how to display csv like data from string please ? Im transfering csv from api, it is a string with comma delimeter..

SAMPLE DATA (column for users is dynamic, can be more or less users..)

Group,john.doe,lubja.kkoorer,peter.junk,
dl_group1,USER,NO,YES,
dl_group2,USER,dl_controler,NO,
dl_group1_microsoft365businessbasic,USER,NO,NO,

Regards

Validation Alerts

Curious if you think it would be a good idea to refactor the Dialog Alert that is part of the validation logic. Would it make more sense to raise an event that the user can handle and they can decide how they want to visualize the validation failure?

Unable to load dynamicly generated bundle.css

Captura de tela 2024-04-05 160243

I've been trying to import your project as dll's to use on my personal project as assemblies and almost everything went well. I noticed that the sheet's style was slightly broken and after ripping off some links in your "_Layout" file to see which one was not being imported to my solution, I found out that the "BlazorDatasheet.Server.styles.css", which also imports from "_content/BlazorDatasheet/BlazorDatasheet.bundle.scp.css", was empty on my project. This was the result:

Captura de tela 2024-04-05 160724

image

The cell's inputs are being duplicated and the sheet, itself, doesn't flow as well as it does on your project.
I also did a massive research about it and asked for help to some other developers, but I really seem to be struggle with that. I really enjoyed the concept of the project and wanted to use it, this is kind of my last hope.

How could I trigger an event when a cell is changed on the ObjectEditor?

First of all I want to thank y'all for this amazing project!
I recently downloaded the 0.2.0 nuget package for the BlazorDatasheet and I was able to pass on data from my DB to the datasheet. Now I'm struggling to save the data back on DB, my first thought was to create a save button that does a bulk save (saving all the data that is present on the sheet in one operation), however, unfortunately, that wouldn't work, since there could be a scenario where, with a huge amount of data, only one row is changed. That's not the most optimized way to do that, so my solution is to trigger an event whenever a cell value is updated, being able to pass on the row id (User.Id) as parameter, then I'd be able to save only that entity/row.
Is there any kind of OnCellChanged()-like event I can call?
Or maybe any other smart alternative approach that I could use?

Here is how I set up my simple example of the ObjectEditor:

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.