├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── other.md
├── renovate.json
└── workflows
│ ├── cicd.yml
│ ├── pr.yml
│ └── release.yml
├── .gitignore
├── .releaserc
├── BlazorTable.gif
├── BlazorTable.sln
├── LICENSE
├── README.md
├── global.json
└── src
├── BlazorTable.Sample.Server
├── BlazorTable.Sample.Server.csproj
├── Pages
│ └── _Host.cshtml
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Startup.cs
├── _Imports.razor
├── appsettings.Development.json
├── appsettings.json
└── wwwroot
│ ├── css
│ ├── bootstrap
│ │ ├── bootstrap.min.css
│ │ └── bootstrap.min.css.map
│ ├── open-iconic
│ │ ├── FONT-LICENSE
│ │ ├── ICON-LICENSE
│ │ ├── README.md
│ │ └── font
│ │ │ ├── css
│ │ │ └── open-iconic-bootstrap.min.css
│ │ │ └── fonts
│ │ │ ├── open-iconic.eot
│ │ │ ├── open-iconic.otf
│ │ │ ├── open-iconic.svg
│ │ │ ├── open-iconic.ttf
│ │ │ └── open-iconic.woff
│ └── site.css
│ ├── favicon.ico
│ └── sample-data
│ ├── MOCK_DATA.json
│ └── MOCK_DATA_BAD.json
├── BlazorTable.Sample.Shared
├── App.razor
├── BlazorTable.Sample.Shared.csproj
├── Bugs
│ ├── 104.razor
│ ├── 114.razor
│ ├── 135.razor
│ ├── 146.razor
│ ├── 152.razor
│ └── 157.razor
├── MainLayout.razor
├── NavMenu.razor
├── Pages
│ ├── AddColumn.razor
│ ├── CustomSelectExample.razor
│ ├── Detail.razor
│ ├── DynamicColumn.razor
│ ├── EditMode.razor
│ ├── EmptyData.razor
│ ├── Error.razor
│ ├── GlobalSearch.razor
│ ├── Index.razor
│ ├── JObjectpg.razor
│ ├── LoadingData.razor
│ ├── Row.razor
│ ├── RowTemplate.razor
│ ├── ServerSideData.razor
│ ├── TableFooter.razor
│ └── ToggleColumnVisibility.razor
└── _Imports.razor
├── BlazorTable.Sample.Wasm
├── BlazorTable.Sample.Wasm.csproj
├── Program.cs
├── Properties
│ └── launchSettings.json
├── _Imports.razor
└── wwwroot
│ ├── _redirects
│ ├── css
│ ├── bootstrap
│ │ ├── bootstrap.min.css
│ │ └── bootstrap.min.css.map
│ ├── open-iconic
│ │ ├── FONT-LICENSE
│ │ ├── ICON-LICENSE
│ │ ├── README.md
│ │ └── font
│ │ │ ├── css
│ │ │ └── open-iconic-bootstrap.min.css
│ │ │ └── fonts
│ │ │ ├── open-iconic.eot
│ │ │ ├── open-iconic.otf
│ │ │ ├── open-iconic.svg
│ │ │ ├── open-iconic.ttf
│ │ │ └── open-iconic.woff
│ └── site.css
│ ├── favicon.ico
│ ├── index.html
│ └── sample-data
│ ├── MOCK_DATA.json
│ └── MOCK_DATA_BAD.json
├── BlazorTable.Tests
├── AddNullChecks.cs
├── BlazorTable.Tests.csproj
├── BrowserTests.cs
└── BrowserTestsAddress.config
└── BlazorTable
├── BlazorTable.csproj
├── Components
├── AggregateType.cs
├── Align.cs
├── Column.razor
├── Column.razor.cs
├── CustomRow.razor
├── CustomRow.razor.cs
├── CustomSelectOption.razor
├── CustomSelectOption.razor.cs
├── DetailTemplate.razor
├── DetailTemplate.razor.cs
├── DynamicColumns.razor
├── DynamicColumns.razor.cs
├── EmptyDataTemplate.razor
├── EmptyDataTemplate.razor.cs
├── FilterManager.razor
├── FilterManager.razor.cs
├── LoadingDataTemplate.razor
├── LoadingDataTemplate.razor.cs
├── Pager.razor
├── Pager.razor.cs
├── Popover.razor
├── Popover.razor.cs
├── SelectionType.cs
├── ServerSide
│ ├── FilterData.cs
│ └── PaginationResult.cs
├── Table.razor
└── Table.razor.cs
├── Filters
├── BooleanFilter.razor
├── BooleanFilter.razor.cs
├── CustomSelect.razor
├── CustomSelect.razor.cs
├── DateFilter.razor
├── DateFilter.razor.cs
├── EnumFilter.razor
├── EnumFilter.razor.cs
├── NumberFilter.razor
├── NumberFilter.razor.cs
├── StringFilter.razor
└── StringFilter.razor.cs
├── GlobalSuppressions.cs
├── IServiceCollectionExtensions.cs
├── Interfaces
├── IColumn.cs
├── ICustomSelect.cs
├── IDataLoader.cs
├── IFilter.cs
├── ITable.cs
└── ITableGen.cs
├── LinkerConfig.xml
├── Localization
├── Localization.Designer.cs
├── Localization.da.resx
├── Localization.de.resx
├── Localization.es.resx
├── Localization.fr.resx
├── Localization.pt-BR.resx
├── Localization.resx
└── Localization.zh-CN.resx
├── LocalizedDescriptionAttribute.cs
├── Utillities.cs
├── _Imports.razor
├── icon.png
└── wwwroot
├── BlazorTable.min.js
└── images
├── filter.png
├── minus.png
├── plus.png
├── sort-asc.png
└── sort-desc.png
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[Bug]"
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Please create a standalone Page which reproduces the issue and paste the code here in a code block.
15 | [More Examples](https://github.com/IvanJosipovic/BlazorTable/tree/master/src/BlazorTable.Sample.Shared/Bugs)
16 |
17 | ```
18 | @page "/Bug152"
19 |
20 |
21 |
22 |
23 | @context.ShortId
24 |
25 |
26 |
27 | @code
28 | {
29 | private PersonData[] data;
30 |
31 | protected override void OnInitialized()
32 | {
33 | data = new PersonData[]
34 | {
35 | new PersonData()
36 | {
37 | ShortId = 5
38 | }
39 | };
40 | }
41 |
42 | public class PersonData
43 | {
44 | public int ShortId { get; set; }
45 | }
46 | }
47 | ```
48 |
49 |
50 | **Expected behavior**
51 | A clear and concise description of what you expected to happen.
52 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[Feat]"
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/other.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Other
3 | about: Any other reason
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "enabled": true,
3 | "timezone": "America/Vancouver",
4 | "dependencyDashboard": true,
5 | "dependencyDashboardTitle": "Renovate Dashboard",
6 | "commitMessageSuffix": "",
7 | "commitBody": "",
8 | "semanticCommits": true,
9 | "suppressNotifications": ["prIgnoreNotification"],
10 | "rebaseWhen": "conflicted",
11 | "extends": [
12 | "config:base"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/.github/workflows/cicd.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - '*'
5 | - '!master'
6 | - '!alpha'
7 | - '!beta'
8 |
9 | name: CI/CD
10 | jobs:
11 | build:
12 | name: CI/CD
13 | runs-on: ubuntu-latest
14 | timeout-minutes: 10
15 | steps:
16 |
17 | - name: Checkout code
18 | uses: actions/checkout@v2
19 |
20 | - name: Setup .NET Core
21 | uses: actions/setup-dotnet@v1
22 | with:
23 | dotnet-version: 3.1.x
24 |
25 | - name: Dotnet Build
26 | run: dotnet build -c Release
27 |
28 | - name: Dotnet Publish
29 | working-directory: src/BlazorTable.Sample.Wasm
30 | run: dotnet publish -c Release
31 |
32 | - name: Deploy to Test
33 | id: netlify
34 | uses: netlify/actions/cli@master
35 | with:
36 | args: deploy --json -d src/BlazorTable.Sample.Wasm/bin/Release/netstandard2.1/publish/wwwroot
37 | env:
38 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
39 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
40 |
41 | - name: Get Test Address
42 | run: |
43 | Set-Content -Path "src/BlazorTable.Tests/BrowserTestsAddress.config" -Value "${{ steps.netlify.outputs.NETLIFY_URL }}";
44 | shell: pwsh
45 |
46 | - name: Dotnet Test
47 | run: dotnet test -c Release
--------------------------------------------------------------------------------
/.github/workflows/pr.yml:
--------------------------------------------------------------------------------
1 | on:
2 | pull_request:
3 | branches:
4 | - '*'
5 |
6 | name: Build
7 | jobs:
8 | build:
9 | name: Build
10 | runs-on: ubuntu-latest
11 | timeout-minutes: 10
12 | steps:
13 |
14 | - name: Checkout code
15 | uses: actions/checkout@v2
16 |
17 | - name: Setup .NET Core
18 | uses: actions/setup-dotnet@v1
19 | with:
20 | dotnet-version: 3.1.x
21 |
22 | - name: Dotnet Build
23 | run: dotnet build -c Release
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - master
5 | - alpha
6 | - beta
7 |
8 | name: Create Release
9 | jobs:
10 | build:
11 | name: Create Release
12 | runs-on: ubuntu-latest
13 | timeout-minutes: 10
14 | steps:
15 | - name: Checkout code
16 | uses: actions/checkout@v2
17 |
18 | - name: Setup .NET Core
19 | uses: actions/setup-dotnet@v1
20 | with:
21 | dotnet-version: 3.1.x
22 |
23 | - name: Dotnet Publish
24 | working-directory: src/BlazorTable.Sample.Wasm
25 | run: dotnet publish -c Release
26 |
27 | - name: Deploy to Production
28 | if: github.ref == 'refs/heads/master'
29 | id: netlify
30 | uses: netlify/actions/cli@master
31 | with:
32 | args: deploy --prod --json -d src/BlazorTable.Sample.Wasm/bin/Release/netstandard2.1/publish/wwwroot
33 | env:
34 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
35 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
36 |
37 | - name: Set Test Address
38 | if: github.ref == 'refs/heads/master'
39 | run: |
40 | Set-Content -Path "src/BlazorTable.Tests/BrowserTestsAddress.config" -Value "${{ steps.netlify.outputs.NETLIFY_URL }}";
41 | shell: pwsh
42 |
43 | - name: Deploy to Staging
44 | if: github.ref != 'refs/heads/master'
45 | id: netlify2
46 | uses: netlify/actions/cli@master
47 | with:
48 | args: deploy --json -d src/BlazorTable.Sample.Wasm/bin/Release/netstandard2.1/publish/wwwroot
49 | env:
50 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
51 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
52 |
53 | - name: Set Test Address
54 | if: github.ref != 'refs/heads/master'
55 | run: |
56 | Set-Content -Path "src/BlazorTable.Tests/BrowserTestsAddress.config" -Value "${{ steps.netlify2.outputs.NETLIFY_URL }}";
57 | shell: pwsh
58 |
59 | - name: Dotnet Test
60 | run: dotnet test --configuration Release
61 |
62 | - name: Semantic Release
63 | uses: cycjimmy/semantic-release-action@v2
64 | id: semantic
65 | with:
66 | semantic_version: 17.4
67 | env:
68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69 |
70 | - name: Dotnet Pack
71 | if: steps.semantic.outputs.new_release_published == 'true'
72 | working-directory: src/BlazorTable
73 | run: dotnet pack -c Release -p:Version=${{ steps.semantic.outputs.new_release_version }}
74 |
75 | - name: Dotnet Nuget Push
76 | if: steps.semantic.outputs.new_release_published == 'true'
77 | working-directory: src/BlazorTable/bin/Release
78 | run: dotnet nuget push BlazorTable.*.nupkg -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_API_KEY }}
79 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
--------------------------------------------------------------------------------
/.releaserc:
--------------------------------------------------------------------------------
1 | {
2 | "branches": ["master", {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}],
3 | "plugins": [
4 | "@semantic-release/commit-analyzer",
5 | "@semantic-release/release-notes-generator",
6 | "@semantic-release/github"
7 | ]
8 | }
--------------------------------------------------------------------------------
/BlazorTable.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/BlazorTable.gif
--------------------------------------------------------------------------------
/BlazorTable.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29411.138
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorTable", "src\BlazorTable\BlazorTable.csproj", "{2F9538AF-9B01-4759-A46C-40C21F45F2FA}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorTable.Sample.Wasm", "src\BlazorTable.Sample.Wasm\BlazorTable.Sample.Wasm.csproj", "{AC356BF1-0B40-4138-AC10-8585B5082FD2}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3CBA7388-6E6D-4D90-8C11-FE6970C465A3}"
11 | ProjectSection(SolutionItems) = preProject
12 | .github\workflows\build.yml = .github\workflows\build.yml
13 | .github\workflows\cicd.yml = .github\workflows\cicd.yml
14 | .dependabot\dependabot.yaml = .dependabot\dependabot.yaml
15 | README.md = README.md
16 | .github\workflows\release.yml = .github\workflows\release.yml
17 | EndProjectSection
18 | EndProject
19 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorTable.Sample.Server", "src\BlazorTable.Sample.Server\BlazorTable.Sample.Server.csproj", "{537D6905-461A-4180-B2F6-D64ADBBE9941}"
20 | EndProject
21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorTable.Sample.Shared", "src\BlazorTable.Sample.Shared\BlazorTable.Sample.Shared.csproj", "{25E8AB75-2F08-463E-8499-0C5BBB20BC50}"
22 | EndProject
23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorTable.Tests", "src\BlazorTable.Tests\BlazorTable.Tests.csproj", "{64B71D26-A307-4541-9B17-BD6709211F21}"
24 | EndProject
25 | Global
26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
27 | Debug|Any CPU = Debug|Any CPU
28 | Release|Any CPU = Release|Any CPU
29 | EndGlobalSection
30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
31 | {2F9538AF-9B01-4759-A46C-40C21F45F2FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {2F9538AF-9B01-4759-A46C-40C21F45F2FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {2F9538AF-9B01-4759-A46C-40C21F45F2FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {2F9538AF-9B01-4759-A46C-40C21F45F2FA}.Release|Any CPU.Build.0 = Release|Any CPU
35 | {AC356BF1-0B40-4138-AC10-8585B5082FD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {AC356BF1-0B40-4138-AC10-8585B5082FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {AC356BF1-0B40-4138-AC10-8585B5082FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {AC356BF1-0B40-4138-AC10-8585B5082FD2}.Release|Any CPU.Build.0 = Release|Any CPU
39 | {537D6905-461A-4180-B2F6-D64ADBBE9941}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40 | {537D6905-461A-4180-B2F6-D64ADBBE9941}.Debug|Any CPU.Build.0 = Debug|Any CPU
41 | {537D6905-461A-4180-B2F6-D64ADBBE9941}.Release|Any CPU.ActiveCfg = Release|Any CPU
42 | {537D6905-461A-4180-B2F6-D64ADBBE9941}.Release|Any CPU.Build.0 = Release|Any CPU
43 | {25E8AB75-2F08-463E-8499-0C5BBB20BC50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {25E8AB75-2F08-463E-8499-0C5BBB20BC50}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {25E8AB75-2F08-463E-8499-0C5BBB20BC50}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 | {25E8AB75-2F08-463E-8499-0C5BBB20BC50}.Release|Any CPU.Build.0 = Release|Any CPU
47 | {64B71D26-A307-4541-9B17-BD6709211F21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48 | {64B71D26-A307-4541-9B17-BD6709211F21}.Debug|Any CPU.Build.0 = Debug|Any CPU
49 | {64B71D26-A307-4541-9B17-BD6709211F21}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 | {64B71D26-A307-4541-9B17-BD6709211F21}.Release|Any CPU.Build.0 = Release|Any CPU
51 | EndGlobalSection
52 | GlobalSection(SolutionProperties) = preSolution
53 | HideSolutionNode = FALSE
54 | EndGlobalSection
55 | GlobalSection(ExtensibilityGlobals) = postSolution
56 | SolutionGuid = {FE5E5FAF-B880-4435-892E-12E9BBAAE487}
57 | EndGlobalSection
58 | EndGlobal
59 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Ivan Josipovic
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BlazorTable
2 | [](https://BlazorTable.netlify.com/)
3 | [](https://www.nuget.org/packages/BlazorTable)
4 | [](https://www.nuget.org/packages/BlazorTable)
5 | 
6 |
7 | Blazor Table Component with Sorting, Paging and Filtering
8 |
9 | [](/BlazorTable.gif)
10 |
11 | ## Install
12 |
13 | - Add [BlazorTable Nuget](https://www.nuget.org/packages/BlazorTable)
14 | - dotnet add package BlazorTable
15 | - Add to the index.html or _Hosts.cshtml
16 | - ``
17 | - Add call to Program.cs or Startup.cs
18 | - Services.AddBlazorTable();
19 |
20 | Note: If installing `BlazorTable` in a hosted Blazor WASM application, these steps should be performed in the [WASM Client](https://docs.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-5.0#blazor-webassembly-1) project.
21 |
22 | ## Features
23 | - Column Reordering
24 | - Edit Mode ([Template Switching](https://github.com/IvanJosipovic/BlazorTable/blob/master/src/BlazorTable.Sample.Shared/Pages/EditMode.razor))
25 | - Client Side
26 | - Paging
27 | - Sorting
28 | - Filtering
29 | - Strings
30 | - Numbers
31 | - Dates
32 | - Enums
33 | - Custom Component
34 | ## Dependencies
35 | - Bootstrap 4 CSS
36 |
37 | ## Sample
38 | [Example Page](https://github.com/IvanJosipovic/BlazorTable/blob/master/src/BlazorTable.Sample.Shared/Pages/Index.razor)
39 |
40 | ```csharp
41 |
42 |
43 |
44 |
45 |
46 |
47 | @context.email
48 |
49 |
50 |
51 |
52 |
53 |
54 | @context.created_date.ToShortDateString()
55 |
56 |
57 |
58 |
59 | ```
60 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "3.1.404",
4 | "rollForward": "latestFeature"
5 | }
6 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/BlazorTable.Sample.Server.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/Pages/_Host.cshtml:
--------------------------------------------------------------------------------
1 | @page "/"
2 | @namespace BlazorTable.SampleServer.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 | @{
5 | Layout = null;
6 | }
7 |
8 |
9 |
10 |
11 |
12 |
13 | BlazorTable.SampleServer
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | An error has occurred. This application may no longer respond until reloaded.
26 |
27 |
28 | An unhandled exception has occurred. See browser dev tools for details.
29 |
30 |
Reload
31 |
🗙
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Hosting;
10 | using Microsoft.Extensions.Logging;
11 |
12 | namespace BlazorTable.Sample.Server
13 | {
14 | public class Program
15 | {
16 | public static void Main(string[] args)
17 | {
18 | CreateHostBuilder(args).Build().Run();
19 | }
20 |
21 | public static IHostBuilder CreateHostBuilder(string[] args) =>
22 | Host.CreateDefaultBuilder(args)
23 | .ConfigureWebHostDefaults(webBuilder =>
24 | {
25 | webBuilder.UseStartup();
26 | });
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:49484",
7 | "sslPort": 44312
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "BlazorTable.Sample.Server": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "environmentVariables": {
22 | "ASPNETCORE_ENVIRONMENT": "Development"
23 | },
24 | "applicationUrl": "http://localhost:51075/"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Components;
8 | using Microsoft.AspNetCore.Hosting;
9 | using Microsoft.AspNetCore.HttpsPolicy;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Hosting;
13 |
14 | namespace BlazorTable.Sample.Server
15 | {
16 | public class Startup
17 | {
18 | public Startup(IConfiguration configuration)
19 | {
20 | Configuration = configuration;
21 | }
22 |
23 | public IConfiguration Configuration { get; }
24 |
25 | // This method gets called by the runtime. Use this method to add services to the container.
26 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
27 | public void ConfigureServices(IServiceCollection services)
28 | {
29 | services.AddRazorPages();
30 | services.AddServerSideBlazor();
31 | // Server Side Blazor doesn't register HttpClient by default
32 | if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
33 | {
34 | // Setup HttpClient for server side in a client side compatible fashion
35 | services.AddScoped(s =>
36 | {
37 | // Creating the URI helper needs to wait until the JS Runtime is initialized, so defer it.
38 | var uriHelper = s.GetRequiredService();
39 | return new HttpClient
40 | {
41 | BaseAddress = new Uri(uriHelper.BaseUri)
42 | };
43 | });
44 | }
45 | services.AddBlazorTable();
46 | }
47 |
48 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
49 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
50 | {
51 | if (env.IsDevelopment())
52 | {
53 | app.UseDeveloperExceptionPage();
54 | }
55 | else
56 | {
57 | app.UseExceptionHandler("/Error");
58 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
59 | app.UseHsts();
60 | }
61 |
62 | app.UseHttpsRedirection();
63 | app.UseStaticFiles();
64 |
65 | app.UseRouting();
66 |
67 | app.UseEndpoints(endpoints =>
68 | {
69 | endpoints.MapBlazorHub();
70 | endpoints.MapFallbackToPage("/_Host");
71 | });
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using System.Net.Http
2 | @using Microsoft.AspNetCore.Authorization
3 | @using Microsoft.AspNetCore.Components.Authorization
4 | @using Microsoft.AspNetCore.Components.Forms
5 | @using Microsoft.AspNetCore.Components.Routing
6 | @using Microsoft.AspNetCore.Components.Web
7 | @using Microsoft.JSInterop
8 | @using BlazorTable.Sample.Shared
9 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "DetailedErrors": true,
3 | "Logging": {
4 | "LogLevel": {
5 | "Default": "Information",
6 | "Microsoft": "Warning",
7 | "Microsoft.Hosting.Lifetime": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/FONT-LICENSE:
--------------------------------------------------------------------------------
1 | SIL OPEN FONT LICENSE Version 1.1
2 |
3 | Copyright (c) 2014 Waybury
4 |
5 | PREAMBLE
6 | The goals of the Open Font License (OFL) are to stimulate worldwide
7 | development of collaborative font projects, to support the font creation
8 | efforts of academic and linguistic communities, and to provide a free and
9 | open framework in which fonts may be shared and improved in partnership
10 | with others.
11 |
12 | The OFL allows the licensed fonts to be used, studied, modified and
13 | redistributed freely as long as they are not sold by themselves. The
14 | fonts, including any derivative works, can be bundled, embedded,
15 | redistributed and/or sold with any software provided that any reserved
16 | names are not used by derivative works. The fonts and derivatives,
17 | however, cannot be released under any other type of license. The
18 | requirement for fonts to remain under this license does not apply
19 | to any document created using the fonts or their derivatives.
20 |
21 | DEFINITIONS
22 | "Font Software" refers to the set of files released by the Copyright
23 | Holder(s) under this license and clearly marked as such. This may
24 | include source files, build scripts and documentation.
25 |
26 | "Reserved Font Name" refers to any names specified as such after the
27 | copyright statement(s).
28 |
29 | "Original Version" refers to the collection of Font Software components as
30 | distributed by the Copyright Holder(s).
31 |
32 | "Modified Version" refers to any derivative made by adding to, deleting,
33 | or substituting -- in part or in whole -- any of the components of the
34 | Original Version, by changing formats or by porting the Font Software to a
35 | new environment.
36 |
37 | "Author" refers to any designer, engineer, programmer, technical
38 | writer or other person who contributed to the Font Software.
39 |
40 | PERMISSION & CONDITIONS
41 | Permission is hereby granted, free of charge, to any person obtaining
42 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
43 | redistribute, and sell modified and unmodified copies of the Font
44 | Software, subject to the following conditions:
45 |
46 | 1) Neither the Font Software nor any of its individual components,
47 | in Original or Modified Versions, may be sold by itself.
48 |
49 | 2) Original or Modified Versions of the Font Software may be bundled,
50 | redistributed and/or sold with any software, provided that each copy
51 | contains the above copyright notice and this license. These can be
52 | included either as stand-alone text files, human-readable headers or
53 | in the appropriate machine-readable metadata fields within text or
54 | binary files as long as those fields can be easily viewed by the user.
55 |
56 | 3) No Modified Version of the Font Software may use the Reserved Font
57 | Name(s) unless explicit written permission is granted by the corresponding
58 | Copyright Holder. This restriction only applies to the primary font name as
59 | presented to the users.
60 |
61 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
62 | Software shall not be used to promote, endorse or advertise any
63 | Modified Version, except to acknowledge the contribution(s) of the
64 | Copyright Holder(s) and the Author(s) or with their explicit written
65 | permission.
66 |
67 | 5) The Font Software, modified or unmodified, in part or in whole,
68 | must be distributed entirely under this license, and must not be
69 | distributed under any other license. The requirement for fonts to
70 | remain under this license does not apply to any document created
71 | using the Font Software.
72 |
73 | TERMINATION
74 | This license becomes null and void if any of the above conditions are
75 | not met.
76 |
77 | DISCLAIMER
78 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
80 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
81 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
82 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
83 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
84 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
85 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
86 | OTHER DEALINGS IN THE FONT SOFTWARE.
87 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/ICON-LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Waybury
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/README.md:
--------------------------------------------------------------------------------
1 | [Open Iconic v1.1.1](http://useiconic.com/open)
2 | ===========
3 |
4 | ### Open Iconic is the open source sibling of [Iconic](http://useiconic.com). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons)
5 |
6 |
7 |
8 | ## What's in Open Iconic?
9 |
10 | * 223 icons designed to be legible down to 8 pixels
11 | * Super-light SVG files - 61.8 for the entire set
12 | * SVG sprite—the modern replacement for icon fonts
13 | * Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats
14 | * Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats
15 | * PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.
16 |
17 |
18 | ## Getting Started
19 |
20 | #### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](http://useiconic.com/open#icons) and [Reference](http://useiconic.com/open#reference) sections.
21 |
22 | ### General Usage
23 |
24 | #### Using Open Iconic's SVGs
25 |
26 | We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute).
27 |
28 | ```
29 |
30 | ```
31 |
32 | #### Using Open Iconic's SVG Sprite
33 |
34 | Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack.
35 |
36 | Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.*
37 |
38 | ```
39 |
40 |
41 |
42 | ```
43 |
44 | Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions.
45 |
46 | ```
47 | .icon {
48 | width: 16px;
49 | height: 16px;
50 | }
51 | ```
52 |
53 | Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag.
54 |
55 | ```
56 | .icon-account-login {
57 | fill: #f00;
58 | }
59 | ```
60 |
61 | To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/).
62 |
63 | #### Using Open Iconic's Icon Font...
64 |
65 |
66 | ##### …with Bootstrap
67 |
68 | You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}`
69 |
70 |
71 | ```
72 |
73 | ```
74 |
75 |
76 | ```
77 |
78 | ```
79 |
80 | ##### …with Foundation
81 |
82 | You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}`
83 |
84 | ```
85 |
86 | ```
87 |
88 |
89 | ```
90 |
91 | ```
92 |
93 | ##### …on its own
94 |
95 | You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}`
96 |
97 | ```
98 |
99 | ```
100 |
101 | ```
102 |
103 | ```
104 |
105 |
106 | ## License
107 |
108 | ### Icons
109 |
110 | All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT).
111 |
112 | ### Fonts
113 |
114 | All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web).
115 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.eot
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.otf
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.woff
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
2 |
3 | html, body {
4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
5 | }
6 |
7 | a, .btn-link {
8 | color: #0366d6;
9 | }
10 |
11 | .btn-primary {
12 | color: #fff;
13 | background-color: #1b6ec2;
14 | border-color: #1861ac;
15 | }
16 |
17 | app {
18 | position: relative;
19 | display: flex;
20 | flex-direction: column;
21 | }
22 |
23 | .top-row {
24 | height: 3.5rem;
25 | display: flex;
26 | align-items: center;
27 | }
28 |
29 | .main {
30 | flex: 1;
31 | }
32 |
33 | .main .top-row {
34 | background-color: #f7f7f7;
35 | border-bottom: 1px solid #d6d5d5;
36 | justify-content: flex-end;
37 | }
38 |
39 | .main .top-row > a, .main .top-row .btn-link {
40 | white-space: nowrap;
41 | margin-left: 1.5rem;
42 | }
43 |
44 | .main .top-row a:first-child {
45 | overflow: hidden;
46 | text-overflow: ellipsis;
47 | }
48 |
49 | .sidebar {
50 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
51 | overflow: auto;
52 | }
53 |
54 | .sidebar .top-row {
55 | background-color: rgba(0,0,0,0.4);
56 | }
57 |
58 | .sidebar .navbar-brand {
59 | font-size: 1.1rem;
60 | }
61 |
62 | .sidebar .oi {
63 | width: 2rem;
64 | font-size: 1.1rem;
65 | vertical-align: text-top;
66 | top: -2px;
67 | }
68 |
69 | .sidebar .nav-item {
70 | font-size: 0.9rem;
71 | padding-bottom: 0.5rem;
72 | }
73 |
74 | .sidebar .nav-item:first-of-type {
75 | padding-top: 1rem;
76 | }
77 |
78 | .sidebar .nav-item:last-of-type {
79 | padding-bottom: 1rem;
80 | }
81 |
82 | .sidebar .nav-item a {
83 | color: #d7d7d7;
84 | border-radius: 4px;
85 | height: 3rem;
86 | display: flex;
87 | align-items: center;
88 | line-height: 3rem;
89 | }
90 |
91 | .sidebar .nav-item a.active {
92 | background-color: rgba(255,255,255,0.25);
93 | color: white;
94 | }
95 |
96 | .sidebar .nav-item a:hover {
97 | background-color: rgba(255,255,255,0.1);
98 | color: white;
99 | }
100 |
101 | .content {
102 | padding-top: 1.1rem;
103 | }
104 |
105 | .navbar-toggler {
106 | background-color: rgba(255, 255, 255, 0.1);
107 | }
108 |
109 | .valid.modified:not([type=checkbox]) {
110 | outline: 1px solid #26b050;
111 | }
112 |
113 | .invalid {
114 | outline: 1px solid red;
115 | }
116 |
117 | .validation-message {
118 | color: red;
119 | }
120 |
121 | #blazor-error-ui {
122 | background: lightyellow;
123 | bottom: 0;
124 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
125 | display: none;
126 | left: 0;
127 | padding: 0.6rem 1.25rem 0.7rem 1.25rem;
128 | position: fixed;
129 | width: 100%;
130 | z-index: 1000;
131 | }
132 |
133 | #blazor-error-ui .dismiss {
134 | cursor: pointer;
135 | position: absolute;
136 | right: 0.75rem;
137 | top: 0.5rem;
138 | }
139 |
140 | @media (max-width: 767.98px) {
141 | .main .top-row:not(.auth) {
142 | display: none;
143 | }
144 |
145 | .main .top-row.auth {
146 | justify-content: space-between;
147 | }
148 |
149 | .main .top-row a, .main .top-row .btn-link {
150 | margin-left: 0;
151 | }
152 | }
153 |
154 | @media (min-width: 768px) {
155 | app {
156 | flex-direction: row;
157 | }
158 |
159 | .sidebar {
160 | width: 250px;
161 | height: 100vh;
162 | position: sticky;
163 | top: 0;
164 | }
165 |
166 | .main .top-row {
167 | position: sticky;
168 | top: 0;
169 | }
170 |
171 | .main > div {
172 | padding-left: 2rem !important;
173 | padding-right: 1.5rem !important;
174 | }
175 |
176 | .navbar-toggler {
177 | display: none;
178 | }
179 |
180 | .sidebar .collapse {
181 | /* Never collapse the sidebar for wide screens */
182 | display: block;
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Server/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Server/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/App.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sorry, there's nothing at this address.
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/BlazorTable.Sample.Shared.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | 3.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Bugs/104.razor:
--------------------------------------------------------------------------------
1 | @page "/104"
2 |
3 | @using BlazorTable
4 |
5 | Issue #104
6 |
7 |
8 |
9 |
10 | @if (@context?.Child?.Name == null)
11 | {
12 | N/A
13 | }
14 | else
15 | {
16 | @context.Child.Name
17 | }
18 |
19 |
20 |
21 |
22 | @code
23 | {
24 | private List items = new List();
25 |
26 | protected override void OnInitialized()
27 | {
28 | for (int i = 0; i < 5; i++)
29 | {
30 | items.Add(new Parent() { Name = i.ToString(), Child = new Child() { Name = i.ToString() } });
31 | items.Add(new Parent() { Name = i.ToString() });
32 | }
33 | }
34 |
35 | private class Parent
36 | {
37 | public string Name { get; set; }
38 |
39 | public Child Child { get; set; }
40 | }
41 |
42 | private class Child
43 | {
44 | public string Name { get; set; }
45 |
46 | public GrandChild GrandChild { get; set; }
47 | }
48 |
49 | private class GrandChild
50 | {
51 | public string Name { get; set; }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Bugs/114.razor:
--------------------------------------------------------------------------------
1 | @page "/114"
2 |
3 | @using BlazorTable
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | HandleClick())">Edit
12 | HandleClick())">Delete
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | @code
22 | {
23 | [Inject]
24 | private HttpClient Http { get; set; }
25 |
26 | private PersonData[] data;
27 |
28 | protected override async Task OnInitializedAsync()
29 | {
30 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
31 | }
32 |
33 | public class PersonData
34 | {
35 | public int? id { get; set; }
36 | public string full_name { get; set; }
37 | public string email { get; set; }
38 | public bool? paid { get; set; }
39 | public decimal? price { get; set; }
40 | public CreditCard? cc_type { get; set; }
41 | public DateTime? created_date { get; set; }
42 | }
43 |
44 | public enum CreditCard
45 | {
46 | none = 0,
47 | [Description("MasterCard")]
48 | MasterCard = 1,
49 | Visa = 2
50 | }
51 |
52 | private void HandleClick()
53 | {
54 |
55 | }
56 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Bugs/135.razor:
--------------------------------------------------------------------------------
1 | @page "/135"
2 |
3 | @using BlazorTable
4 |
5 |
6 |
7 |
8 |
9 | RQ
10 |
11 |
12 |
13 |
14 | @code
15 | {
16 | private PersonData[] data;
17 |
18 | protected override void OnInitialized()
19 | {
20 | data = new PersonData[]
21 | {
22 | new PersonData()
23 | {
24 | ShortId = 5
25 | }
26 | };
27 | }
28 |
29 | public class PersonData
30 | {
31 | public int ShortId { get; set; }
32 | }
33 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Bugs/146.razor:
--------------------------------------------------------------------------------
1 | @page "/146"
2 |
3 | @using BlazorTable
4 |
5 |
6 |
7 |
8 | @(context.Child != null ? context.Child.Data : string.Empty)
9 |
10 |
11 |
12 |
13 | @(context.Child != null ? context.Child.Data : string.Empty)
14 |
15 |
16 |
17 |
18 |
19 | @code
20 | {
21 | private Root[] data;
22 |
23 | protected override void OnInitialized()
24 | {
25 | data = new Root[]
26 | {
27 | new Root()
28 | {
29 | Child = new Child(){ Data = "test1" }
30 | },
31 | new Root()
32 | {
33 | Child = new Child(){ Data = "test2" }
34 | },
35 | new Root()
36 | {
37 | Child = new Child(){ Data = "test3" }
38 | },
39 | new Root()
40 | {
41 | Child = new Child()
42 | },
43 | new Root()
44 | {
45 | Child = null
46 | }
47 | };
48 | }
49 |
50 | public class Root
51 | {
52 | public Child Child { get; set; }
53 | }
54 |
55 | public class Child
56 | {
57 | public string Data { get; set; }
58 | }
59 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Bugs/152.razor:
--------------------------------------------------------------------------------
1 | @page "/152"
2 |
3 | @using BlazorTable
4 |
5 |
6 |
7 |
8 | @context.ShortId
9 |
10 |
11 |
12 | @code
13 | {
14 | private PersonData[] data;
15 |
16 | protected override void OnInitialized()
17 | {
18 | data = new PersonData[]
19 | {
20 | new PersonData()
21 | {
22 | ShortId = 5
23 | }
24 | };
25 | }
26 |
27 | public class PersonData
28 | {
29 | public int ShortId { get; set; }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Bugs/157.razor:
--------------------------------------------------------------------------------
1 | @page "/157"
2 |
3 | @using BlazorTable
4 |
5 |
11 |
12 |
13 | @code {
14 | private List data;
15 |
16 | protected override void OnInitialized()
17 | {
18 | data = new List()
19 | {
20 | new MyData()
21 | {
22 | MyString = "One",
23 | MyInt = 1,
24 | MyEnum = MyEnum.One
25 | },
26 | new MyData()
27 | {
28 | MyString = "Two",
29 | MyInt = 2,
30 | MyEnum = MyEnum.Two
31 | },
32 | new MyData()
33 | {
34 | MyString = "Three",
35 | MyInt = 3,
36 | MyEnum = MyEnum.Three
37 | }
38 | };
39 |
40 |
41 | base.OnInitialized();
42 | }
43 | public enum MyEnum
44 | {
45 | One,
46 | Two,
47 | Three
48 | }
49 |
50 | public class MyData
51 | {
52 | public string MyString { get; set; }
53 | public int MyInt { get; set; }
54 | public MyEnum MyEnum { get; set; }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/MainLayout.razor:
--------------------------------------------------------------------------------
1 | @inherits LayoutComponentBase
2 |
3 |
6 |
7 |
8 |
11 |
12 |
13 | @Body
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/NavMenu.razor:
--------------------------------------------------------------------------------
1 |
7 |
8 |
87 |
88 | @code {
89 | private bool collapseNavMenu = true;
90 |
91 | private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
92 |
93 | private void ToggleNavMenu()
94 | {
95 | collapseNavMenu = !collapseNavMenu;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/AddColumn.razor:
--------------------------------------------------------------------------------
1 | @page "/AddColumn"
2 | @inject HttpClient Http
3 | @using BlazorTable
4 | @using System.ComponentModel
5 |
6 | Add Column Programmatically
7 |
8 | Add())">Add Column
9 |
10 |
11 |
15 |
16 | @code
17 | {
18 | private ITable Table;
19 |
20 | private PersonData[] data;
21 |
22 | protected override async Task OnInitializedAsync()
23 | {
24 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
25 | }
26 |
27 | public class PersonData
28 | {
29 | public int? id { get; set; }
30 | public string full_name { get; set; }
31 | public string email { get; set; }
32 | public bool? paid { get; set; }
33 | public decimal? price { get; set; }
34 | public CreditCard? cc_type { get; set; }
35 | public DateTime? created_date { get; set; }
36 | }
37 |
38 | public enum CreditCard
39 | {
40 | none = 0,
41 | [Description("MasterCard")]
42 | MasterCard = 1,
43 | Visa = 2
44 | }
45 |
46 | private void Add()
47 | {
48 | var col = new Column()
49 | {
50 | Title = "Enum",
51 | Field = (x) => x.cc_type,
52 | Sortable = true,
53 | Filterable = true,
54 | Width = "10%"
55 | };
56 |
57 | Table.AddColumn(col);
58 | }
59 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/CustomSelectExample.razor:
--------------------------------------------------------------------------------
1 | @page "/CustomSelect"
2 |
3 | @using BlazorTable
4 |
5 | CustomSelect
6 |
7 | The CustomSelect
can be used to display custom filter options.
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | @code
24 | {
25 | [Inject]
26 | private HttpClient Http { get; set; }
27 |
28 | private PersonData[] data;
29 |
30 | protected override async Task OnInitializedAsync()
31 | {
32 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
33 | }
34 |
35 | public class PersonData
36 | {
37 | public int? id { get; set; }
38 | public string full_name { get; set; }
39 | public string email { get; set; }
40 | public bool? paid { get; set; }
41 | public decimal? price { get; set; }
42 | public CreditCard? cc_type { get; set; }
43 | public DateTime? created_date { get; set; }
44 | }
45 |
46 | public enum CreditCard
47 | {
48 | none = 0,
49 | [Description("MasterCard")]
50 | MasterCard = 1,
51 | Visa = 2
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/Detail.razor:
--------------------------------------------------------------------------------
1 | @page "/Detail"
2 |
3 | @using BlazorTable
4 |
5 | DetailTemplate
6 |
7 | The DetailTemplate
can be used to display additional details below an item.
8 |
9 |
25 |
26 | @if (errorMessage != "")
27 | {
28 | @errorMessage
29 | }
30 |
31 |
32 |
33 |
34 |
35 | @context.email
36 |
37 |
38 |
39 |
40 | @context.paid.ToString()
41 |
42 |
43 |
44 |
45 |
46 | @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty)
47 |
48 |
49 |
50 |
51 | @context.cc_type
52 |
53 |
54 |
55 | Name @context.full_name
56 |
57 | Email @context.email
58 |
59 | Created Date @context.created_date
60 |
61 |
62 |
63 |
64 |
65 | @code
66 | {
67 | [Inject]
68 | private HttpClient Http { get; set; }
69 |
70 | private ITable table;
71 |
72 | private PersonData[] data;
73 |
74 | private int rowNumber;
75 |
76 | private string errorMessage = "";
77 |
78 | protected override async Task OnInitializedAsync()
79 | {
80 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
81 | }
82 |
83 | public class PersonData
84 | {
85 | public int? id { get; set; }
86 | public string full_name { get; set; }
87 | public string email { get; set; }
88 | public bool? paid { get; set; }
89 | public decimal? price { get; set; }
90 | public CreditCard? cc_type { get; set; }
91 | public DateTime? created_date { get; set; }
92 | }
93 |
94 | public enum CreditCard
95 | {
96 | none = 0,
97 | [Description("MasterCard")]
98 | MasterCard = 1,
99 | Visa = 2
100 | }
101 |
102 | private void Try(Action action)
103 | {
104 | try
105 | {
106 | errorMessage = "";
107 | action();
108 | }
109 | catch (Exception e)
110 | {
111 | errorMessage = e.Message;
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/DynamicColumn.razor:
--------------------------------------------------------------------------------
1 | @page "/DynamicColumns"
2 |
3 | Dynamic Columns
4 |
5 |
9 |
10 | @code
11 | {
12 | [Inject] private HttpClient Http { get; set; }
13 |
14 | private PersonData[] data;
15 |
16 | protected override async Task OnInitializedAsync()
17 | {
18 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
19 | }
20 |
21 | public class PersonData
22 | {
23 | public int? id { get; set; }
24 | public string full_name { get; set; }
25 | public string email { get; set; }
26 | public bool? paid { get; set; }
27 | public decimal? price { get; set; }
28 | public CreditCard? cc_type { get; set; }
29 | public DateTime? created_date { get; set; }
30 | //public SubData SubData {get;set;}
31 | }
32 |
33 | public class SubData
34 | {
35 | public string test { get; set; }
36 | }
37 |
38 | public enum CreditCard
39 | {
40 | none = 0,
41 | [Description("MasterCard")]
42 | MasterCard = 1,
43 | Visa = 2
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/EditMode.razor:
--------------------------------------------------------------------------------
1 | @page "/EditMode"
2 |
3 | @using BlazorTable
4 |
5 | Edit Mode
6 |
7 | ToggleEdit())">Toggle Edit Mode
8 |
9 |
10 |
52 |
53 | @code
54 | {
55 | [Inject]
56 | private HttpClient Http { get; set; }
57 |
58 | private ITable Table;
59 |
60 | private PersonData[] data;
61 |
62 | protected override async Task OnInitializedAsync()
63 | {
64 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
65 | }
66 |
67 | public class PersonData
68 | {
69 | public int? id { get; set; }
70 | public string full_name { get; set; }
71 | public string email { get; set; }
72 | public bool? paid { get; set; }
73 | public decimal? price { get; set; }
74 | public CreditCard? cc_type { get; set; }
75 | public DateTime? created_date { get; set; }
76 | }
77 |
78 | public enum CreditCard
79 | {
80 | none = 0,
81 | [Description("MasterCard")]
82 | MasterCard = 1,
83 | Visa = 2
84 | }
85 |
86 | private void ToggleEdit()
87 | {
88 | Table.ToggleEditMode();
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/EmptyData.razor:
--------------------------------------------------------------------------------
1 | @page "/EmptyData"
2 | @inject HttpClient Http
3 | @using BlazorTable
4 |
5 | EmptyDataTemplate
6 |
7 | The EmptyDataTemplate
can be used to display custom text when there are no rows to display.
8 |
9 |
10 |
11 |
12 |
13 |
14 | No rows found!
15 |
16 |
17 |
18 |
19 |
20 | @code
21 | {
22 | private ITable Table;
23 |
24 | private SampleData[] data;
25 |
26 | protected override async Task OnInitializedAsync()
27 | {
28 | await Task.Delay(250);
29 | data = Array.Empty();
30 | }
31 |
32 | public class SampleData
33 | {
34 | public int? id { get; set; }
35 | public string full_name { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/Error.razor:
--------------------------------------------------------------------------------
1 | @page "/error"
2 |
3 |
4 | Error.
5 | An error occurred while processing your request.
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/GlobalSearch.razor:
--------------------------------------------------------------------------------
1 | @page "/GlobalSearch"
2 |
3 | @using BlazorTable
4 |
5 | Global Search
6 |
7 |
8 |
9 |
10 |
11 |
12 | @context.email
13 |
14 |
15 |
16 |
17 | @context.paid.ToString()
18 |
19 |
20 |
21 |
22 |
23 | @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty)
24 |
25 |
26 |
27 |
28 | @context.cc_type
29 |
30 |
31 |
32 |
33 |
34 | @code
35 | {
36 | [Inject]
37 | private HttpClient Http { get; set; }
38 |
39 | private PersonData[] data;
40 |
41 | protected override async Task OnInitializedAsync()
42 | {
43 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
44 | }
45 |
46 | public class PersonData
47 | {
48 | public int? id { get; set; }
49 | public string full_name { get; set; }
50 | public string email { get; set; }
51 | public bool? paid { get; set; }
52 | public decimal? price { get; set; }
53 | public CreditCard? cc_type { get; set; }
54 | public DateTime? created_date { get; set; }
55 | }
56 |
57 | public enum CreditCard
58 | {
59 | none = 0,
60 | [Description("MasterCard")]
61 | MasterCard = 1,
62 | Visa = 2
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/Index.razor:
--------------------------------------------------------------------------------
1 | @page "/"
2 |
3 | @using BlazorTable
4 |
5 | BlazorTable
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | @context.email
20 |
21 |
22 |
23 |
24 | @context.paid.ToString()
25 |
26 |
27 |
28 |
29 |
30 | @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty)
31 |
32 |
33 |
34 |
35 | @context.cc_type
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | @context.email
45 |
46 |
47 |
48 |
49 | @context.paid.ToString()
50 |
51 |
52 |
53 |
54 |
55 | @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty)
56 |
57 |
58 |
59 |
60 | @context.cc_type
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | @code
70 | {
71 | [Inject]
72 | private HttpClient Http { get; set; }
73 |
74 | private PersonData[] data;
75 |
76 | protected override async Task OnInitializedAsync()
77 | {
78 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
79 | }
80 |
81 | public class PersonData
82 | {
83 | public int? id { get; set; }
84 | public string full_name { get; set; }
85 | public string email { get; set; }
86 | public bool? paid { get; set; }
87 | public decimal? price { get; set; }
88 | public CreditCard? cc_type { get; set; }
89 | public DateTime? created_date { get; set; }
90 |
91 | ///
92 | /// Returns row CSS if price over 800
93 | ///
94 | public string RowClass => price.GetValueOrDefault(0) > 800 ? "table-danger" : null;
95 | }
96 |
97 | public enum CreditCard
98 | {
99 | none = 0,
100 | [Description("MasterCard")]
101 | MasterCard = 1,
102 | Visa = 2
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/JObjectpg.razor:
--------------------------------------------------------------------------------
1 | @page "/JObject"
2 | @using BlazorTable
3 | @using Newtonsoft.Json.Linq
4 |
5 | JObject
6 |
7 |
8 |
9 | ())" Type="@(typeof(string))" Sortable="true" Filterable="true" DefaultSortColumn="true" />
10 | ())" Type="@(typeof(int))" Sortable="true" Filterable="true" />
11 | ().Property("Name").Value.Value())" Type="@(typeof(string))" Sortable="true" Filterable="true" />
12 |
13 |
14 |
15 | @code
16 | {
17 | private List data = new List();
18 |
19 | protected override void OnInitialized()
20 | {
21 | var row1 = new JObject();
22 | row1["Column1"] = "B";
23 | row1["Column2"] = 2;
24 | row1["Column3"] = new JObject();
25 | row1["Column3"]["Name"] = "D";
26 | data.Add(row1);
27 |
28 | var row2 = new JObject();
29 | row2["Column1"] = "B";
30 | row2["Column2"] = 1;
31 | row2["Column3"] = new JObject();
32 | row2["Column3"]["Name"] = "D";
33 | data.Add(row2);
34 |
35 | var row3 = new JObject();
36 | row3["Column1"] = "A";
37 | row3["Column2"] = 2;
38 | row3["Column3"] = new JObject();
39 | row3["Column3"]["Name"] = "C";
40 | data.Add(row3);
41 |
42 | var row4 = new JObject();
43 | row4["Column1"] = "A";
44 | row4["Column2"] = 1;
45 | row4["Column3"] = new JObject();
46 | row4["Column3"]["Name"] = "C";
47 | data.Add(row4);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/LoadingData.razor:
--------------------------------------------------------------------------------
1 | @page "/LoadingData"
2 | @inject HttpClient Http
3 | @using BlazorTable
4 | @using System.ComponentModel
5 |
6 | LoadingDataTemplate
7 |
8 | The LoadingDataTemplate
can be used to display custom text when the rows are null or loading.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Custom Loading Template
16 |
17 |
18 |
19 |
20 |
21 | @code
22 | {
23 | private ITable Table;
24 |
25 | private SampleData[] data;
26 |
27 | protected override async Task OnInitializedAsync()
28 | {
29 | await Task.Delay(2000);
30 | data = Array.Empty();
31 | }
32 |
33 | public class SampleData
34 | {
35 | public int? id { get; set; }
36 | public string full_name { get; set; }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/Row.razor:
--------------------------------------------------------------------------------
1 | @page "/Row"
2 |
3 | @using BlazorTable
4 |
5 | Row
6 |
7 | Selection Type:
8 | selectionType = (SelectionType)Enum.Parse(typeof(SelectionType), x.Value.ToString()))">
9 | @foreach (var option in Enum.GetValues(typeof(SelectionType)))
10 | {
11 | @option
12 | }
13 |
14 |
15 | Last Clicked: @selected?.full_name
16 |
17 | Selected: @(selectedItems.Any() ? selectedItems.Select(x => x.full_name).Aggregate((c, n) => $"{c},{n}") : "None")
18 |
19 |
20 |
21 |
22 |
23 |
24 | @context.email
25 |
26 |
27 |
28 |
29 |
30 |
31 | @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty)
32 |
33 |
34 |
35 |
36 |
37 |
38 | @code
39 | {
40 | [Inject]
41 | private HttpClient Http { get; set; }
42 |
43 | private PersonData[] data;
44 |
45 | private SelectionType selectionType;
46 |
47 | private PersonData selected;
48 |
49 | private List selectedItems = new List();
50 |
51 | protected override async Task OnInitializedAsync()
52 | {
53 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
54 | }
55 |
56 | public class PersonData
57 | {
58 | public int? id { get; set; }
59 | public string full_name { get; set; }
60 | public string email { get; set; }
61 | public bool? paid { get; set; }
62 | public decimal? price { get; set; }
63 | public CreditCard? cc_type { get; set; }
64 | public DateTime? created_date { get; set; }
65 | }
66 |
67 | public enum CreditCard
68 | {
69 | none = 0,
70 | [Description("MasterCard")]
71 | MasterCard = 1,
72 | Visa = 2
73 | }
74 |
75 | public void RowClick(PersonData data)
76 | {
77 | selected = data;
78 | StateHasChanged();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/RowTemplate.razor:
--------------------------------------------------------------------------------
1 | @page "/CustomRow"
2 | @inject HttpClient Http
3 | @using BlazorTable
4 | @using System.ComponentModel
5 |
6 | Row Template - Custom Row
7 |
8 |
9 |
10 | Use
11 |
12 |
13 |
14 |
15 |
16 |
17 | @context.email
18 |
19 |
20 |
21 |
22 | @context.paid.ToString()
23 |
24 |
25 |
26 |
27 |
28 | @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty)
29 |
30 |
31 |
32 |
33 | @context.cc_type
34 |
35 |
36 |
37 |
38 |
39 | Custom Row
40 |
41 |
42 |
43 |
44 |
45 |
46 | @code
47 | {
48 | [Inject]
49 | private HttpClient httpClient { get; set; }
50 |
51 | private ITable table;
52 |
53 | private PersonData[] data;
54 |
55 | private int i = 0;
56 |
57 | protected override async Task OnInitializedAsync()
58 | {
59 | data = await httpClient.GetFromJsonAsync("sample-data/MOCK_DATA.json");
60 | }
61 |
62 | public class PersonData
63 | {
64 | public int? id { get; set; }
65 | public string full_name { get; set; }
66 | public string email { get; set; }
67 | public bool? paid { get; set; }
68 | public decimal? price { get; set; }
69 | public CreditCard? cc_type { get; set; }
70 | public DateTime? created_date { get; set; }
71 | }
72 |
73 | public enum CreditCard
74 | {
75 | none = 0,
76 | [Description("MasterCard")]
77 | MasterCard = 1,
78 | Visa = 2
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/ServerSideData.razor:
--------------------------------------------------------------------------------
1 | @page "/ServerSideData"
2 | @inject HttpClient Http
3 | @using BlazorTable
4 | @using BlazorTable.Interfaces
5 | @using BlazorTable.Components.ServerSide
6 |
7 | Server side data
8 |
9 |
10 |
11 |
12 |
13 |
14 | @context.email
15 |
16 |
17 |
18 |
19 | @context.paid.ToString()
20 |
21 |
22 |
23 |
24 |
25 | @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty)
26 |
27 |
28 |
29 |
30 |
31 | @code
32 | {
33 | [Inject]
34 | private HttpClient httpClient { get; set; }
35 |
36 | public class PersonData
37 | {
38 | public int? id { get; set; }
39 | public string full_name { get; set; }
40 | public string email { get; set; }
41 | public bool? paid { get; set; }
42 | public decimal? price { get; set; }
43 | public DateTime? created_date { get; set; }
44 | }
45 |
46 | private IDataLoader _loader;
47 |
48 | private IEnumerable data;
49 |
50 | protected override async Task OnInitializedAsync()
51 | {
52 | _loader = new PersonDataLoader(httpClient);
53 | data = (await _loader.LoadDataAsync(null)).Records;
54 | }
55 |
56 | public class PersonDataLoader : IDataLoader
57 | {
58 | private readonly HttpClient _client;
59 | public PersonDataLoader(HttpClient client)
60 | {
61 | _client = client;
62 | }
63 | public async Task> LoadDataAsync(FilterData parameters)
64 | {
65 |
66 | var data = await _client.GetFromJsonAsync("sample-data/MOCK_DATA.json");
67 | IQueryable query = data.AsQueryable();
68 | if (parameters?.Query != null)
69 | {
70 | query = query.Where(
71 | x => x.email.ToLowerInvariant().Contains(parameters.Query.ToLowerInvariant()) ||
72 | x.full_name.ToLowerInvariant().Contains(parameters.Query.ToLowerInvariant()));
73 | }
74 | if (parameters?.OrderBy != null)
75 | {
76 | var orderBy = parameters.OrderBy.Split(" ");
77 | if (orderBy.Length == 2)
78 | {
79 | var isSortDescending = orderBy[1] == "desc";
80 | var prop = typeof(PersonData).GetProperty(orderBy[0]);
81 | query = isSortDescending ? query.OrderByDescending(x => prop.GetValue(x, null))
82 | : query.OrderBy(x => prop.GetValue(x, null));
83 | }
84 | }
85 | var results = parameters?.Top.HasValue ?? false ?
86 | query.Skip(parameters.Skip.GetValueOrDefault())
87 | .Take(parameters.Top.Value).ToArray() :
88 | query.ToArray();
89 |
90 | return new PaginationResult
91 | {
92 | Records = results,
93 | Skip = parameters?.Skip ?? 0,
94 | Total = query.ToList().Count,
95 | Top = parameters?.Top ?? 0
96 | };
97 | }
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/TableFooter.razor:
--------------------------------------------------------------------------------
1 | @page "/TableFooter"
2 |
3 | @using BlazorTable
4 |
5 | Table Footer
6 |
7 | This example is to demonstrate the table footer feature. There are 5 aggregation types built in: Sum
, Average
, Count
, Min
, and Max
. You have ability to set any string value into the footer by using SetFooterValue
attribute for the Column
tag if necessary.
8 |
9 |
10 |
11 |
12 |
13 |
14 | @context.email
15 |
16 |
17 |
18 |
19 | @context.paid.ToString()
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty)
29 |
30 |
31 |
32 |
33 |
34 | @code
35 | {
36 | [Inject]
37 | private HttpClient Http { get; set; }
38 |
39 | private PersonData[] data;
40 |
41 | public string TotalFooterText = "Totals";
42 |
43 | protected override async Task OnInitializedAsync()
44 | {
45 | data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json");
46 | }
47 |
48 | public class PersonData
49 | {
50 | public int? id { get; set; }
51 | public string full_name { get; set; }
52 | public string email { get; set; }
53 | public bool? paid { get; set; }
54 | public decimal? price { get; set; }
55 | public CreditCard? cc_type { get; set; }
56 | public DateTime? created_date { get; set; }
57 | }
58 |
59 | public enum CreditCard
60 | {
61 | none = 0,
62 | [Description("MasterCard")]
63 | MasterCard = 1,
64 | Visa = 2
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/Pages/ToggleColumnVisibility.razor:
--------------------------------------------------------------------------------
1 | @page "/ToggleColumnVisibility"
2 | @inject HttpClient Http
3 | @using BlazorTable
4 | @using System.ComponentModel
5 |
6 | Toggle Column Visibility
7 |
8 | Users can change the visibility of a column if its "Hideable" attribute is set to true.
9 |
10 | showSearchBar = !showSearchBar)">Toggle Search Bar
11 |
12 |
13 |
14 |
15 |
16 |
17 | @context.email
18 |
19 |
20 |
21 |
22 | @context.paid.ToString()
23 |
24 |
25 |
26 |
27 |
28 | @(context.created_date.HasValue ? context.created_date.Value.ToShortDateString() : string.Empty)
29 |
30 |
31 |
32 |
33 | @context.cc_type
34 |
35 |
36 |
37 |
38 |
39 | @code
40 | {
41 | [Inject]
42 | private HttpClient httpClient { get; set; }
43 |
44 | private ITable table;
45 |
46 | private PersonData[] data;
47 |
48 | private bool showSearchBar;
49 |
50 | protected override async Task OnInitializedAsync()
51 | {
52 | data = await httpClient.GetFromJsonAsync("sample-data/MOCK_DATA.json");
53 |
54 | Random random = new Random(123);
55 |
56 | foreach (IColumn column in table.Columns)
57 | {
58 | column.Visible = random.Next(2) == 1 ? true : false; // column visibility
59 | }
60 | }
61 |
62 | public class PersonData
63 | {
64 | public int? id { get; set; }
65 | public string full_name { get; set; }
66 | public string email { get; set; }
67 | public bool? paid { get; set; }
68 | public decimal? price { get; set; }
69 | public CreditCard? cc_type { get; set; }
70 | public DateTime? created_date { get; set; }
71 | }
72 |
73 | public enum CreditCard
74 | {
75 | none = 0,
76 | [Description("MasterCard")]
77 | MasterCard = 1,
78 | Visa = 2
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Shared/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using BlazorTable.Sample.Shared
2 | @using BlazorTable.Sample.Shared.Pages
3 | @using System.Net.Http
4 | @using Microsoft.AspNetCore.Components.Forms
5 | @using Microsoft.AspNetCore.Components.Routing
6 | @using Microsoft.AspNetCore.Components.Web
7 | @using Microsoft.JSInterop
8 | @using System.ComponentModel
9 | @using System.Net.Http.Json
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/BlazorTable.Sample.Wasm.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | 3.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/Program.cs:
--------------------------------------------------------------------------------
1 | using BlazorTable.Sample.Shared;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using System.Net.Http;
6 | using System;
7 |
8 | namespace BlazorTable.Sample.Wasm
9 | {
10 | public class Program
11 | {
12 | public static async Task Main(string[] args)
13 | {
14 | var builder = WebAssemblyHostBuilder.CreateDefault(args);
15 |
16 | builder.RootComponents.Add("app");
17 |
18 | builder.Services.AddSingleton(new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
19 | builder.Services.AddBlazorTable();
20 |
21 | await builder.Build().RunAsync();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:51076/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "BlazorTable.Sample.Wasm": {
20 | "commandName": "Project",
21 | "launchBrowser": true,
22 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | },
26 | "applicationUrl": "http://localhost:51076/"
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using System.Net.Http
2 | @using Microsoft.AspNetCore.Components.Forms
3 | @using Microsoft.AspNetCore.Components.Routing
4 | @using Microsoft.AspNetCore.Components.Web
5 | @using Microsoft.JSInterop
6 | @using BlazorTable.Sample.Shared
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/FONT-LICENSE:
--------------------------------------------------------------------------------
1 | SIL OPEN FONT LICENSE Version 1.1
2 |
3 | Copyright (c) 2014 Waybury
4 |
5 | PREAMBLE
6 | The goals of the Open Font License (OFL) are to stimulate worldwide
7 | development of collaborative font projects, to support the font creation
8 | efforts of academic and linguistic communities, and to provide a free and
9 | open framework in which fonts may be shared and improved in partnership
10 | with others.
11 |
12 | The OFL allows the licensed fonts to be used, studied, modified and
13 | redistributed freely as long as they are not sold by themselves. The
14 | fonts, including any derivative works, can be bundled, embedded,
15 | redistributed and/or sold with any software provided that any reserved
16 | names are not used by derivative works. The fonts and derivatives,
17 | however, cannot be released under any other type of license. The
18 | requirement for fonts to remain under this license does not apply
19 | to any document created using the fonts or their derivatives.
20 |
21 | DEFINITIONS
22 | "Font Software" refers to the set of files released by the Copyright
23 | Holder(s) under this license and clearly marked as such. This may
24 | include source files, build scripts and documentation.
25 |
26 | "Reserved Font Name" refers to any names specified as such after the
27 | copyright statement(s).
28 |
29 | "Original Version" refers to the collection of Font Software components as
30 | distributed by the Copyright Holder(s).
31 |
32 | "Modified Version" refers to any derivative made by adding to, deleting,
33 | or substituting -- in part or in whole -- any of the components of the
34 | Original Version, by changing formats or by porting the Font Software to a
35 | new environment.
36 |
37 | "Author" refers to any designer, engineer, programmer, technical
38 | writer or other person who contributed to the Font Software.
39 |
40 | PERMISSION & CONDITIONS
41 | Permission is hereby granted, free of charge, to any person obtaining
42 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
43 | redistribute, and sell modified and unmodified copies of the Font
44 | Software, subject to the following conditions:
45 |
46 | 1) Neither the Font Software nor any of its individual components,
47 | in Original or Modified Versions, may be sold by itself.
48 |
49 | 2) Original or Modified Versions of the Font Software may be bundled,
50 | redistributed and/or sold with any software, provided that each copy
51 | contains the above copyright notice and this license. These can be
52 | included either as stand-alone text files, human-readable headers or
53 | in the appropriate machine-readable metadata fields within text or
54 | binary files as long as those fields can be easily viewed by the user.
55 |
56 | 3) No Modified Version of the Font Software may use the Reserved Font
57 | Name(s) unless explicit written permission is granted by the corresponding
58 | Copyright Holder. This restriction only applies to the primary font name as
59 | presented to the users.
60 |
61 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
62 | Software shall not be used to promote, endorse or advertise any
63 | Modified Version, except to acknowledge the contribution(s) of the
64 | Copyright Holder(s) and the Author(s) or with their explicit written
65 | permission.
66 |
67 | 5) The Font Software, modified or unmodified, in part or in whole,
68 | must be distributed entirely under this license, and must not be
69 | distributed under any other license. The requirement for fonts to
70 | remain under this license does not apply to any document created
71 | using the Font Software.
72 |
73 | TERMINATION
74 | This license becomes null and void if any of the above conditions are
75 | not met.
76 |
77 | DISCLAIMER
78 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
80 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
81 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
82 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
83 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
84 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
85 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
86 | OTHER DEALINGS IN THE FONT SOFTWARE.
87 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/ICON-LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Waybury
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/README.md:
--------------------------------------------------------------------------------
1 | [Open Iconic v1.1.1](http://useiconic.com/open)
2 | ===========
3 |
4 | ### Open Iconic is the open source sibling of [Iconic](http://useiconic.com). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons)
5 |
6 |
7 |
8 | ## What's in Open Iconic?
9 |
10 | * 223 icons designed to be legible down to 8 pixels
11 | * Super-light SVG files - 61.8 for the entire set
12 | * SVG sprite—the modern replacement for icon fonts
13 | * Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats
14 | * Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats
15 | * PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.
16 |
17 |
18 | ## Getting Started
19 |
20 | #### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](http://useiconic.com/open#icons) and [Reference](http://useiconic.com/open#reference) sections.
21 |
22 | ### General Usage
23 |
24 | #### Using Open Iconic's SVGs
25 |
26 | We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute).
27 |
28 | ```
29 |
30 | ```
31 |
32 | #### Using Open Iconic's SVG Sprite
33 |
34 | Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack.
35 |
36 | Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.*
37 |
38 | ```
39 |
40 |
41 |
42 | ```
43 |
44 | Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions.
45 |
46 | ```
47 | .icon {
48 | width: 16px;
49 | height: 16px;
50 | }
51 | ```
52 |
53 | Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag.
54 |
55 | ```
56 | .icon-account-login {
57 | fill: #f00;
58 | }
59 | ```
60 |
61 | To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/).
62 |
63 | #### Using Open Iconic's Icon Font...
64 |
65 |
66 | ##### …with Bootstrap
67 |
68 | You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}`
69 |
70 |
71 | ```
72 |
73 | ```
74 |
75 |
76 | ```
77 |
78 | ```
79 |
80 | ##### …with Foundation
81 |
82 | You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}`
83 |
84 | ```
85 |
86 | ```
87 |
88 |
89 | ```
90 |
91 | ```
92 |
93 | ##### …on its own
94 |
95 | You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}`
96 |
97 | ```
98 |
99 | ```
100 |
101 | ```
102 |
103 | ```
104 |
105 |
106 | ## License
107 |
108 | ### Icons
109 |
110 | All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT).
111 |
112 | ### Fonts
113 |
114 | All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web).
115 |
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
2 |
3 | html, body {
4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
5 | }
6 |
7 | a, .btn-link {
8 | color: #0366d6;
9 | }
10 |
11 | .btn-primary {
12 | color: #fff;
13 | background-color: #1b6ec2;
14 | border-color: #1861ac;
15 | }
16 |
17 | app {
18 | position: relative;
19 | display: flex;
20 | flex-direction: column;
21 | }
22 |
23 | .top-row {
24 | height: 3.5rem;
25 | display: flex;
26 | align-items: center;
27 | }
28 |
29 | .main {
30 | flex: 1;
31 | }
32 |
33 | .main .top-row {
34 | background-color: #f7f7f7;
35 | border-bottom: 1px solid #d6d5d5;
36 | justify-content: flex-end;
37 | }
38 |
39 | .main .top-row > a, .main .top-row .btn-link {
40 | white-space: nowrap;
41 | margin-left: 1.5rem;
42 | }
43 |
44 | .main .top-row a:first-child {
45 | overflow: hidden;
46 | text-overflow: ellipsis;
47 | }
48 |
49 | .sidebar {
50 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
51 | overflow: auto;
52 | }
53 |
54 | .sidebar .top-row {
55 | background-color: rgba(0,0,0,0.4);
56 | }
57 |
58 | .sidebar .navbar-brand {
59 | font-size: 1.1rem;
60 | }
61 |
62 | .sidebar .oi {
63 | width: 2rem;
64 | font-size: 1.1rem;
65 | vertical-align: text-top;
66 | top: -2px;
67 | }
68 |
69 | .sidebar .nav-item {
70 | font-size: 0.9rem;
71 | padding-bottom: 0.5rem;
72 | }
73 |
74 | .sidebar .nav-item:first-of-type {
75 | padding-top: 1rem;
76 | }
77 |
78 | .sidebar .nav-item:last-of-type {
79 | padding-bottom: 1rem;
80 | }
81 |
82 | .sidebar .nav-item a {
83 | color: #d7d7d7;
84 | border-radius: 4px;
85 | height: 3rem;
86 | display: flex;
87 | align-items: center;
88 | line-height: 3rem;
89 | }
90 |
91 | .sidebar .nav-item a.active {
92 | background-color: rgba(255,255,255,0.25);
93 | color: white;
94 | }
95 |
96 | .sidebar .nav-item a:hover {
97 | background-color: rgba(255,255,255,0.1);
98 | color: white;
99 | }
100 |
101 | .content {
102 | padding-top: 1.1rem;
103 | }
104 |
105 | .navbar-toggler {
106 | background-color: rgba(255, 255, 255, 0.1);
107 | }
108 |
109 | .valid.modified:not([type=checkbox]) {
110 | outline: 1px solid #26b050;
111 | }
112 |
113 | .invalid {
114 | outline: 1px solid red;
115 | }
116 |
117 | .validation-message {
118 | color: red;
119 | }
120 |
121 | #blazor-error-ui {
122 | background: lightyellow;
123 | bottom: 0;
124 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
125 | display: none;
126 | left: 0;
127 | padding: 0.6rem 1.25rem 0.7rem 1.25rem;
128 | position: fixed;
129 | width: 100%;
130 | z-index: 1000;
131 | }
132 |
133 | #blazor-error-ui .dismiss {
134 | cursor: pointer;
135 | position: absolute;
136 | right: 0.75rem;
137 | top: 0.5rem;
138 | }
139 |
140 | @media (max-width: 767.98px) {
141 | .main .top-row:not(.auth) {
142 | display: none;
143 | }
144 |
145 | .main .top-row.auth {
146 | justify-content: space-between;
147 | }
148 |
149 | .main .top-row a, .main .top-row .btn-link {
150 | margin-left: 0;
151 | }
152 | }
153 |
154 | @media (min-width: 768px) {
155 | app {
156 | flex-direction: row;
157 | }
158 |
159 | .sidebar {
160 | width: 250px;
161 | height: 100vh;
162 | position: sticky;
163 | top: 0;
164 | }
165 |
166 | .main .top-row {
167 | position: sticky;
168 | top: 0;
169 | }
170 |
171 | .main > div {
172 | padding-left: 2rem !important;
173 | padding-right: 1.5rem !important;
174 | }
175 |
176 | .navbar-toggler {
177 | display: none;
178 | }
179 |
180 | .sidebar .collapse {
181 | /* Never collapse the sidebar for wide screens */
182 | display: block;
183 | }
184 | }
185 |
186 | .spinner {
187 | margin: 100px auto;
188 | width: 50px;
189 | height: 40px;
190 | text-align: center;
191 | font-size: 10px;
192 | }
193 |
194 | .spinner > div {
195 | background-color: #fff;
196 | height: 100%;
197 | width: 6px;
198 | display: inline-block;
199 | -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out;
200 | animation: sk-stretchdelay 1.2s infinite ease-in-out;
201 | }
202 |
203 | .spinner .rect2 {
204 | -webkit-animation-delay: -1.1s;
205 | animation-delay: -1.1s;
206 | }
207 |
208 | .spinner .rect3 {
209 | -webkit-animation-delay: -1.0s;
210 | animation-delay: -1.0s;
211 | }
212 |
213 | .spinner .rect4 {
214 | -webkit-animation-delay: -0.9s;
215 | animation-delay: -0.9s;
216 | }
217 |
218 | .spinner .rect5 {
219 | -webkit-animation-delay: -0.8s;
220 | animation-delay: -0.8s;
221 | }
222 |
223 | @-webkit-keyframes sk-stretchdelay {
224 | 0%, 40%, 100% {
225 | -webkit-transform: scaleY(0.4)
226 | }
227 |
228 | 20% {
229 | -webkit-transform: scaleY(1.0)
230 | }
231 | }
232 |
233 | @keyframes sk-stretchdelay {
234 | 0%, 40%, 100% {
235 | transform: scaleY(0.4);
236 | -webkit-transform: scaleY(0.4);
237 | }
238 |
239 | 20% {
240 | transform: scaleY(1.0);
241 | -webkit-transform: scaleY(1.0);
242 | }
243 | }
244 |
245 | .modal-overlay {
246 | position: fixed;
247 | top: 0;
248 | bottom: 0;
249 | left: 0;
250 | right: 0;
251 | background-color: rgba(28,28,28);
252 | z-index: 2000;
253 | display: flex;
254 | align-items: center;
255 | justify-content: center;
256 | flex-direction: column;
257 | --sk-color: white;
258 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable.Sample.Wasm/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/src/BlazorTable.Sample.Wasm/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | BlazorTable.Sample
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | An unhandled error has occurred.
26 |
Reload
27 |
🗙
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/BlazorTable.Tests/AddNullChecks.cs:
--------------------------------------------------------------------------------
1 | using Shouldly;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Linq.Expressions;
6 | using Xunit;
7 |
8 | namespace BlazorTable.Tests
9 | {
10 | public class AddNullChecks
11 | {
12 | [Fact]
13 | public void AddToSingle()
14 | {
15 | Expression> Field = x => x.Child;
16 | var exp = Field.Body.CreateNullChecks();
17 | exp.ToString().ShouldBe("(x.Child != null)");
18 | }
19 |
20 | [Fact]
21 | public void AddToMulti()
22 | {
23 | Expression> Field = x => x.Child.Name;
24 | var exp = Field.Body.CreateNullChecks();
25 | exp.ToString().ShouldBe("((x.Child != null) AndAlso (x.Child.Name != null))");
26 | }
27 |
28 | [Fact]
29 | public void AddToMulti2()
30 | {
31 | Expression> Field = x => x.Child.GrandChild.Name;
32 | var exp = Field.Body.CreateNullChecks();
33 | exp.ToString().ShouldBe("(((x.Child != null) AndAlso (x.Child.GrandChild != null)) AndAlso (x.Child.GrandChild.Name != null))");
34 | }
35 |
36 | [Fact]
37 | public void Skip()
38 | {
39 | Expression> Field = x => x.Child;
40 | var exp = Field.Body.CreateNullChecks(true);
41 | exp.ToString().ShouldBe("(x.Child != null)");
42 | }
43 |
44 | [Fact]
45 | public void Skip2()
46 | {
47 | Expression> Field = x => x.Child.Name;
48 | var exp = Field.Body.CreateNullChecks(true);
49 | exp.ToString().ShouldBe("(x.Child != null)");
50 | }
51 |
52 | [Fact]
53 | public void Skip3()
54 | {
55 | Expression> Field = x => x.Child.GrandChild.Name;
56 | var exp = Field.Body.CreateNullChecks(true);
57 | exp.ToString().ShouldBe("((x.Child != null) AndAlso (x.Child.GrandChild != null))");
58 | }
59 |
60 | [Fact]
61 | public void NonNullable()
62 | {
63 | Expression> Field = x => x.Enum;
64 | var exp = Field.Body.CreateNullChecks();
65 | exp.ToString().ShouldBe("(True == True)");
66 | }
67 |
68 | [Fact]
69 | public void NonNullable2()
70 | {
71 | Expression> Field = x => x.Child.Enum;
72 | var exp = Field.Body.CreateNullChecks();
73 | exp.ToString().ShouldBe("(x.Child != null)");
74 | }
75 |
76 | private class Parent
77 | {
78 | public Child Child { get; set; }
79 |
80 | public MyEnum Enum { get; set; }
81 | }
82 |
83 | private class Child
84 | {
85 | public string Name { get; set; }
86 |
87 | public GrandChild GrandChild { get; set; }
88 |
89 | public MyEnum Enum { get; set; }
90 | }
91 |
92 | private class GrandChild
93 | {
94 | public string Name { get; set; }
95 | }
96 |
97 | private enum MyEnum
98 | {
99 | One,
100 | Two,
101 | Three
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/BlazorTable.Tests/BlazorTable.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | all
18 | runtime; build; native; contentfiles; analyzers; buildtransitive
19 |
20 |
21 | all
22 | runtime; build; native; contentfiles; analyzers; buildtransitive
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Always
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/BlazorTable.Tests/BrowserTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using PuppeteerSharp;
6 | using PuppeteerSharp.Contrib.Extensions;
7 | using Shouldly;
8 | using Xunit;
9 |
10 | namespace BlazorTable.Tests
11 | {
12 | public class BrowserTests : IAsyncLifetime
13 | {
14 | private string BaseAddress;
15 |
16 | private Browser Browser { get; set; }
17 |
18 | public async Task InitializeAsync()
19 | {
20 | string filename = "BrowserTestsAddress.config";
21 |
22 | if (File.Exists(filename))
23 | BaseAddress = File.ReadAllText(filename);
24 | else
25 | throw new Exception($"Missing {filename}");
26 |
27 | await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultChromiumRevision);
28 |
29 | Browser = await Puppeteer.LaunchAsync(new LaunchOptions
30 | {
31 | Headless = true
32 | });
33 | }
34 |
35 | public async Task DisposeAsync()
36 | {
37 | await Browser?.CloseAsync();
38 | }
39 |
40 | private async Task PrintPerf(Page page)
41 | {
42 | var perf = await page.EvaluateExpressionAsync("window.performance.timing.domContentLoadedEventEnd - window.performance.timing.navigationStart");
43 | Console.WriteLine($"Load Time: {perf}ms");
44 | }
45 |
46 | [Fact]
47 | public async Task CheckRoot()
48 | {
49 | bool hasError = false;
50 |
51 | var page = await Browser.NewPageAsync();
52 |
53 | page.Console += Page_Console;
54 |
55 | void Page_Console(object sender, ConsoleEventArgs e)
56 | {
57 | if (e.Message.Type == ConsoleType.Error)
58 | hasError = true;
59 | }
60 |
61 | await page.GoToAsync(BaseAddress);
62 |
63 | var selector = await page.WaitForSelectorAsync("div.table-responsive > table > tbody > tr:nth-child(1) > td:nth-child(3)");
64 |
65 | (await selector.InnerTextAsync()).ShouldBe("Astrix Mariette");
66 |
67 | hasError.ShouldBeFalse();
68 |
69 | await PrintPerf(page);
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/src/BlazorTable.Tests/BrowserTestsAddress.config:
--------------------------------------------------------------------------------
1 | http://localhost:51076
--------------------------------------------------------------------------------
/src/BlazorTable/BlazorTable.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | 3.0
6 | true
7 | BlazorTable
8 | BlazorTable
9 | Blazor Table Component with Sorting, Paging and Filtering
10 | Ivan Josipovic
11 | https://BlazorTable.netlify.app
12 | Blazor;Table;Component;Grid;DataTable;Data;Sort;Filter;AspNetCore;AspNet
13 | icon.png
14 | https://github.com/IvanJosipovic/BlazorTable
15 | git
16 | MIT
17 | true
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | $(MSBuildProjectName).xml
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | all
36 | runtime; build; native; contentfiles; analyzers; buildtransitive
37 |
38 |
39 |
40 |
41 |
42 | <_Parameter1>$(AssemblyName).Tests
43 |
44 |
45 |
46 |
47 |
48 |
49 | True
50 | True
51 | Localization.resx
52 |
53 |
54 |
55 |
56 |
57 | ResXFileCodeGenerator
58 | Localization.Designer.cs
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/AggregateType.cs:
--------------------------------------------------------------------------------
1 | namespace BlazorTable
2 | {
3 | public enum AggregateType
4 | {
5 | Sum,
6 | Average,
7 | Count,
8 | Min,
9 | Max
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/Align.cs:
--------------------------------------------------------------------------------
1 | namespace BlazorTable
2 | {
3 | public enum Align
4 | {
5 | None,
6 | Left,
7 | Center,
8 | Right
9 | }
10 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Components/Column.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
4 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/CustomRow.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/CustomRow.razor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using System;
3 |
4 | namespace BlazorTable
5 | {
6 | ///
7 | /// A custom row template
8 | ///
9 | ///
10 | public partial class CustomRow : ComponentBase
11 | {
12 | ///
13 | /// Parent Table
14 | ///
15 | [CascadingParameter(Name = "Table")]
16 | public ITable Table { get; set; }
17 |
18 | ///
19 | /// Function that defines if the custom row is active for the TableItem inserted as parameter
20 | ///
21 | [Parameter]
22 | public Func IsActiveForItem { get; set; }
23 |
24 | ///
25 | /// Content to show
26 | ///
27 | [Parameter]
28 | public RenderFragment ChildContent { get; set; }
29 |
30 | ///
31 | /// When initialized, add custom row to table
32 | ///
33 | protected override void OnInitialized()
34 | {
35 | Table.AddCustomRow(this);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/CustomSelectOption.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
--------------------------------------------------------------------------------
/src/BlazorTable/Components/CustomSelectOption.razor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 |
3 | namespace BlazorTable
4 | {
5 | ///
6 | /// Option for CustomSelect
7 | ///
8 | public partial class CustomSelectOption
9 | {
10 | ///
11 | /// Parent table
12 | ///
13 | [CascadingParameter(Name = "CustomSelect")]
14 | public ICustomSelect CustomSelect { get; set; }
15 |
16 | [Parameter]
17 | public string Key { get; set; }
18 |
19 | [Parameter]
20 | public object Value { get; set; }
21 |
22 | ///
23 | /// When initialized, tell CustomSelect of this item
24 | ///
25 | protected override void OnInitialized()
26 | {
27 | CustomSelect.AddSelect(Key, Value);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/DetailTemplate.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
--------------------------------------------------------------------------------
/src/BlazorTable/Components/DetailTemplate.razor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 |
3 | namespace BlazorTable
4 | {
5 | ///
6 | /// Detail Template
7 | ///
8 | ///
9 | public partial class DetailTemplate
10 | {
11 | ///
12 | /// Parent table
13 | ///
14 | [CascadingParameter(Name = "Table")]
15 | public ITable Table { get; set; }
16 |
17 | ///
18 | /// Content to show
19 | ///
20 | [Parameter]
21 | public RenderFragment ChildContent { get; set; }
22 |
23 | ///
24 | /// When initialized, tell table of this item
25 | ///
26 | protected override void OnInitialized()
27 | {
28 | Table.SetDetailTemplate(this);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/DynamicColumns.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
4 | @foreach (var propertyInfo in (Type == null ? typeof(TableItem).GetProperties() : Type.GetProperties() ))
5 | {
6 | if(propertyInfo.PropertyType.MemberType == System.Reflection.MemberTypes.NestedType)
7 | {
8 |
9 | } else {
10 |
11 | var member = GenerateMemberExpression(propertyInfo);
12 |
13 |
14 |
15 | @RenderProperty(context, propertyInfo, member.Compile())
16 |
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/DynamicColumns.razor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Linq;
6 | using System.Linq.Expressions;
7 | using System.Reflection;
8 |
9 | namespace BlazorTable
10 | {
11 | ///
12 | /// BlazorTable Dynamic Columns
13 | ///
14 | ///
15 | public partial class DynamicColumns
16 | {
17 | ///
18 | /// Parent Table
19 | ///
20 | [CascadingParameter(Name = "Table")]
21 | public ITable Table { get; set; }
22 |
23 | ///
24 | /// Column can be sorted
25 | ///
26 | [Parameter]
27 | public bool Sortable { get; set; }
28 |
29 | ///
30 | /// Column can be filtered
31 | ///
32 | [Parameter]
33 | public bool Filterable { get; set; }
34 |
35 | ///
36 | /// Horizontal alignment
37 | ///
38 | [Parameter]
39 | public Align Align { get; set; }
40 |
41 | ///
42 | /// Column CSS Class
43 | ///
44 | [Parameter]
45 | public string Class { get; set; }
46 |
47 | [Parameter]
48 | public Type Type { get; set; }
49 |
50 | private static Expression> GenerateMemberExpression(PropertyInfo propertyInfo)
51 | {
52 | var entityParam = Expression.Parameter(typeof(TModel), "x");
53 |
54 | Expression columnExpr = null;
55 |
56 | if (propertyInfo.ReflectedType.Name == "JObject")
57 | {
58 | var assembly = AppDomain.CurrentDomain.GetAssemblies().Where(x => x.ManifestModule.Name == "Newtonsoft.Json.dll").First();
59 |
60 | var type = propertyInfo.ReflectedType;// assembly.GetType("Newtonsoft.Json.Linq.JToken");
61 | var exttype = assembly.GetType("Newtonsoft.Json.Linq.Extensions");
62 |
63 | columnExpr = Expression.Call(exttype.GetMethod("Value", new[] { typeof(IEnumerable<>).MakeGenericType(type) }).MakeGenericMethod(new[] {type}),
64 | Expression.Property(
65 | Expression.Call(entityParam, "Property", null, Expression.Constant(propertyInfo.Name)),
66 | "Value")
67 | );
68 | }
69 | else
70 | {
71 | columnExpr = Expression.Property(entityParam, propertyInfo);
72 |
73 | if (propertyInfo.PropertyType != typeof(T))
74 | columnExpr = Expression.Convert(columnExpr, typeof(T));
75 | }
76 |
77 | return Expression.Lambda>(columnExpr, entityParam);
78 | }
79 |
80 | private string RenderProperty(TableItem data, PropertyInfo property, Func func = null)
81 | {
82 | if (property.ReflectedType.Name == "JObject")
83 | {
84 | return "";// func.Invoke(data)?.ToString();
85 | }
86 |
87 | object rawData = property.GetValue(data);
88 |
89 | if (rawData == null)
90 | return "";
91 |
92 | if (rawData.GetType().IsEnum)
93 | {
94 | Type enumType = property.GetValue(data).GetType();
95 |
96 | MemberInfo[] memberInfo = enumType.GetMember(rawData.ToString());
97 | if (memberInfo != null && memberInfo.Length > 0)
98 | {
99 | object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
100 |
101 | if (attrs != null && attrs.Length > 0)
102 | {
103 | //Pull out the description value
104 | return ((DescriptionAttribute)attrs[0]).Description;
105 | }
106 | }
107 | }
108 |
109 | return rawData.ToString();
110 | }
111 | }
112 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Components/EmptyDataTemplate.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
--------------------------------------------------------------------------------
/src/BlazorTable/Components/EmptyDataTemplate.razor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 |
3 | namespace BlazorTable
4 | {
5 | ///
6 | /// Child content for empty dataset
7 | ///
8 | public partial class EmptyDataTemplate
9 | {
10 | ///
11 | /// Parent table
12 | ///
13 | [CascadingParameter(Name = "Table")]
14 | public ITable Table { get; set; }
15 |
16 | ///
17 | /// Content to show
18 | ///
19 | [Parameter]
20 | public RenderFragment ChildContent { get; set; }
21 |
22 | ///
23 | /// When initialized, tell table of this item
24 | ///
25 | protected override void OnInitialized()
26 | {
27 | Table.SetEmptyDataTemplate(this);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/FilterManager.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
4 |
5 | @ChildContent
6 |
7 |
8 |
9 |
10 | Column.ToggleFilter())">@Localization["FilterManagerClose"]
11 | await ClearFilterAsync())">@Localization["FilterManagerClear"]
12 | await ApplyFilterAsync())">@Localization["FilterManagerApply"]
13 |
14 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/FilterManager.razor.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Components;
3 | using Microsoft.Extensions.Localization;
4 | using Microsoft.Extensions.Logging;
5 |
6 | namespace BlazorTable
7 | {
8 | public partial class FilterManager
9 | {
10 | [CascadingParameter(Name = "Column")]
11 | public IColumn Column { get; set; }
12 |
13 | [Parameter]
14 | public RenderFragment ChildContent { get; set; }
15 |
16 | [Inject]
17 | public ILogger> Logger { get; set; }
18 |
19 | [Inject]
20 | IStringLocalizer Localization { get; set; }
21 |
22 | private async Task ApplyFilterAsync()
23 |
24 | {
25 | Column.ToggleFilter();
26 |
27 | if (Column.FilterControl != null)
28 | {
29 | Column.Filter = Column.FilterControl.GetFilter();
30 | await Column.Table.UpdateAsync().ConfigureAwait(false);
31 | await Column.Table.FirstPageAsync().ConfigureAwait(false);
32 | }
33 | else
34 | {
35 | Logger.LogInformation("Filter is null");
36 | }
37 | }
38 |
39 | private async Task ClearFilterAsync()
40 | {
41 | Column.ToggleFilter();
42 |
43 | if (Column.Filter != null)
44 | {
45 | Column.Filter = null;
46 | await Column.Table.UpdateAsync().ConfigureAwait(false);
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/LoadingDataTemplate.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/LoadingDataTemplate.razor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 |
3 | namespace BlazorTable
4 | {
5 | ///
6 | /// Child content for null dataset
7 | ///
8 | public partial class LoadingDataTemplate
9 | {
10 | ///
11 | /// Parent table
12 | ///
13 | [CascadingParameter(Name = "Table")]
14 | public ITable Table { get; set; }
15 |
16 | ///
17 | /// Content to show
18 | ///
19 | [Parameter]
20 | public RenderFragment ChildContent { get; set; }
21 |
22 | ///
23 | /// When initialized, tell table of this item
24 | ///
25 | protected override void OnInitialized()
26 | {
27 | Table.SetLoadingDataTemplate(this);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/Pager.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 |
3 | @if (AlwaysShow || (Table.TotalPages > 1))
4 | {
5 |
6 |
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/Pager.razor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using Microsoft.Extensions.Localization;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | namespace BlazorTable
7 | {
8 | ///
9 | /// BlazorTable Pager
10 | ///
11 | public partial class Pager
12 | {
13 | [CascadingParameter(Name = "Table")]
14 | public ITable Table { get; set; }
15 |
16 | ///
17 | /// Always show Pager, otherwise only show if TotalPages > 1
18 | ///
19 | [Parameter]
20 | public bool AlwaysShow { get; set; }
21 |
22 | ///
23 | /// Show current page number
24 | ///
25 | [Parameter]
26 | public bool ShowPageNumber { get; set; }
27 |
28 | ///
29 | /// Show total item count
30 | ///
31 | [Parameter]
32 | public bool ShowTotalCount { get; set; }
33 |
34 | ///
35 | /// Page size options
36 | ///
37 | [Parameter]
38 | public List PageSizes { get; set; } = new List() { 15, 30, 60 };
39 |
40 | ///
41 | /// Show Page Size Options
42 | ///
43 | [Parameter]
44 | public bool ShowPageSizes { get; set; }
45 |
46 | [Inject]
47 | IStringLocalizer Localization { get; set; }
48 |
49 | private async Task SetPageSizeAsync(ChangeEventArgs args)
50 | {
51 | if (int.TryParse(args.Value.ToString(), out int result))
52 | {
53 | await Table.SetPageSizeAsync(result).ConfigureAwait(false);
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/Popover.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 |
3 | @if (IsOpen ?? false)
4 | {
5 |
6 |
7 | @ChildContent
8 |
9 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Components/Popover.razor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using Microsoft.JSInterop;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Threading.Tasks;
6 |
7 | namespace BlazorTable
8 | {
9 | public partial class Popover
10 | {
11 | [Parameter(CaptureUnmatchedValues = true)]
12 | public IReadOnlyDictionary UnknownParameters { get; set; }
13 |
14 | [Parameter]
15 | public EventCallback IsOpenChanged { get; set; }
16 |
17 | [Parameter]
18 | public bool? IsOpen
19 | {
20 | get => _isOpen;
21 | set
22 | {
23 | if (value != null)
24 | {
25 | Manual = true;
26 | if (value.Value != _isOpen)
27 | {
28 | Changed(value ?? false);
29 | StateHasChanged();
30 | }
31 | _isOpen = value ?? false;
32 | }
33 | }
34 | }
35 |
36 | [Parameter]
37 | public Placement Placement { get; set; } = Placement.Auto;
38 |
39 | [Parameter]
40 | public ElementReference Reference { get; set; }
41 |
42 | [Parameter]
43 | public RenderFragment ChildContent { get; set; }
44 |
45 | [Parameter]
46 | public bool DismissOnNextClick { get; set; } = true;
47 |
48 | [Inject]
49 | protected IJSRuntime JSRuntime { get; set; }
50 |
51 | public bool Manual { get; set; }
52 |
53 | private bool _isOpen { get; set; }
54 |
55 | protected virtual Task Changed(bool e)
56 | {
57 | return Task.CompletedTask;
58 | }
59 |
60 | public virtual void Hide()
61 | {
62 | _isOpen = false;
63 | if (!Manual) Changed(_isOpen);
64 | IsOpenChanged.InvokeAsync(false);
65 | }
66 |
67 | protected string Classname => $"popover bs-popover-{Placement.ToDescriptionString()} {(IsOpen == true ? "show" : string.Empty)}";
68 |
69 | protected ElementReference MyRef { get; set; }
70 |
71 | protected ElementReference Arrow { get; set; }
72 |
73 | protected override void OnAfterRender(bool firstRender)
74 | {
75 | if (IsOpen ?? false)
76 | {
77 | var placement = Placement.ToDescriptionString();
78 | JSRuntime.InvokeVoidAsync("BlazorTablePopper", Reference, MyRef, Arrow, placement);
79 | }
80 | }
81 |
82 | protected void OnClick()
83 | {
84 | if (DismissOnNextClick)
85 | {
86 | Hide();
87 | }
88 | }
89 | }
90 |
91 | public enum Placement
92 | {
93 | [Description("auto")]
94 | Auto,
95 |
96 | [Description("auto-start")]
97 | AutoStart,
98 |
99 | [Description("auto-end")]
100 | AutoEnd,
101 |
102 | [Description("top")]
103 | Top,
104 |
105 | [Description("top-start")]
106 | TopStart,
107 |
108 | [Description("top-end")]
109 | TopEnd,
110 |
111 | [Description("right")]
112 | Right,
113 |
114 | [Description("right-start")]
115 | RightStart,
116 |
117 | [Description("right-end")]
118 | EightEnd,
119 |
120 | [Description("bottom")]
121 | Bottom,
122 |
123 | [Description("bottom-start")]
124 | BottomStart,
125 |
126 | [Description("bottom-end")]
127 | BottomEnd,
128 |
129 | [Description("left")]
130 | Left,
131 |
132 | [Description("left-start")]
133 | LeftStart,
134 |
135 | [Description("left-end")]
136 | LeftEnd
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/SelectionType.cs:
--------------------------------------------------------------------------------
1 | namespace BlazorTable
2 | {
3 | public enum SelectionType
4 | {
5 | None,
6 | Single,
7 | Multiple
8 | }
9 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Components/ServerSide/FilterData.cs:
--------------------------------------------------------------------------------
1 | namespace BlazorTable.Components.ServerSide
2 | {
3 | public class FilterData
4 | {
5 | public string OrderBy { get; set; }
6 |
7 | public string Query { get; set; }
8 |
9 | public int? Top { get; set; }
10 |
11 | public int? Skip { get; set; }
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/BlazorTable/Components/ServerSide/PaginationResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace BlazorTable.Components.ServerSide
6 | {
7 | public class PaginationResult
8 | {
9 | public int Top { get; set; }
10 |
11 | public int Skip { get; set; }
12 |
13 | public int? Total { get; set; }
14 |
15 | public IEnumerable Records { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/BooleanFilter.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
4 | @if (Column.FilterControl == this)
5 | {
6 | Condition = (BooleanCondition)Enum.Parse(typeof(BooleanCondition), x.Value.ToString()))">
7 | @foreach (var option in (BooleanCondition[])Enum.GetValues(typeof(BooleanCondition)))
8 | {
9 | @option.GetDescription()
10 | }
11 |
12 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/BooleanFilter.razor.cs:
--------------------------------------------------------------------------------
1 | using BlazorTable.Localization;
2 | using Microsoft.AspNetCore.Components;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq.Expressions;
6 |
7 | namespace BlazorTable
8 | {
9 | public partial class BooleanFilter : IFilter
10 | {
11 | [CascadingParameter(Name = "Column")]
12 | public IColumn Column { get; set; }
13 |
14 | private BooleanCondition Condition { get; set; }
15 |
16 | public List FilterTypes => new List()
17 | {
18 | typeof(bool)
19 | };
20 |
21 | protected override void OnInitialized()
22 | {
23 | if (FilterTypes.Contains(Column.Type.GetNonNullableType()))
24 | {
25 | Column.FilterControl = this;
26 |
27 | if (Column.Filter != null)
28 | {
29 | var nodeType = Column.Filter.Body.NodeType;
30 |
31 | if (Column.Filter.Body is BinaryExpression binaryExpression
32 | && binaryExpression.NodeType == ExpressionType.AndAlso)
33 | {
34 | nodeType = binaryExpression.Right.NodeType;
35 | }
36 |
37 | switch (nodeType)
38 | {
39 | case ExpressionType.IsTrue:
40 | Condition = BooleanCondition.True;
41 | break;
42 | case ExpressionType.IsFalse:
43 | Condition = BooleanCondition.False;
44 | break;
45 | case ExpressionType.Equal:
46 | Condition = BooleanCondition.IsNull;
47 | break;
48 | case ExpressionType.NotEqual:
49 | Condition = BooleanCondition.IsNotNull;
50 | break;
51 | }
52 | }
53 | }
54 | }
55 |
56 | public Expression> GetFilter()
57 | {
58 | return Condition switch
59 | {
60 | BooleanCondition.True =>
61 | Expression.Lambda>(
62 | Expression.AndAlso(
63 | Column.Field.Body.CreateNullChecks(),
64 | Expression.IsTrue(Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()))),
65 | Column.Field.Parameters),
66 |
67 | BooleanCondition.False =>
68 | Expression.Lambda>(
69 | Expression.AndAlso(
70 | Column.Field.Body.CreateNullChecks(),
71 | Expression.IsFalse(Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()))),
72 | Column.Field.Parameters),
73 |
74 | BooleanCondition.IsNull =>
75 | Expression.Lambda>(
76 | Expression.AndAlso(
77 | Column.Field.Body.CreateNullChecks(true),
78 | Expression.Equal(Column.Field.Body, Expression.Constant(null))),
79 | Column.Field.Parameters),
80 |
81 | BooleanCondition.IsNotNull =>
82 | Expression.Lambda>(
83 | Expression.AndAlso(
84 | Column.Field.Body.CreateNullChecks(true),
85 | Expression.NotEqual(Column.Field.Body, Expression.Constant(null))),
86 | Column.Field.Parameters),
87 |
88 | _ => null,
89 | };
90 | }
91 | }
92 |
93 | public enum BooleanCondition
94 | {
95 | [LocalizedDescription("BooleanConditionTrue", typeof(Localization.Localization))]
96 | True,
97 |
98 | [LocalizedDescription("BooleanConditionFalse", typeof(Localization.Localization))]
99 | False,
100 |
101 | [LocalizedDescription("BooleanConditionIsNull", typeof(Localization.Localization))]
102 | IsNull,
103 |
104 | [LocalizedDescription("BooleanConditionIsNotNull", typeof(Localization.Localization))]
105 | IsNotNull
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/CustomSelect.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
4 | @if (Column.FilterControl == this)
5 | {
6 | Condition = (CustomSelectCondition)Enum.Parse(typeof(CustomSelectCondition), x.Value.ToString()))">
7 | @foreach (CustomSelectCondition option in Enum.GetValues(typeof(CustomSelectCondition)))
8 | {
9 | @option.GetDescription()
10 | }
11 |
12 |
13 | @if (Condition != CustomSelectCondition.IsNull && Condition != CustomSelectCondition.IsNotNull)
14 | {
15 | FilterValue = x.Value)">
16 | @foreach (var option in Items)
17 | {
18 | @option.Key
19 | }
20 |
21 | }
22 | }
23 |
24 |
25 | @ChildContent
26 |
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/CustomSelect.razor.cs:
--------------------------------------------------------------------------------
1 | using BlazorTable.Localization;
2 | using Microsoft.AspNetCore.Components;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using System.Linq;
7 | using System.Linq.Expressions;
8 |
9 | namespace BlazorTable
10 | {
11 | public partial class CustomSelect : IFilter, ICustomSelect
12 | {
13 | [CascadingParameter(Name = "Column")]
14 | public IColumn Column { get; set; }
15 |
16 | [Parameter]
17 | public RenderFragment ChildContent { get; set; }
18 |
19 | private List> Items = new List>();
20 |
21 | private CustomSelectCondition Condition { get; set; }
22 |
23 | private object FilterValue { get; set; }
24 |
25 | protected override void OnInitialized()
26 | {
27 | Column.FilterControl = this;
28 |
29 | if (Column.Filter?.Body is BinaryExpression binaryExpression
30 | && binaryExpression.Right is BinaryExpression logicalBinary
31 | && logicalBinary.Right is ConstantExpression constant)
32 | {
33 | switch (logicalBinary.NodeType)
34 | {
35 | case ExpressionType.Equal:
36 | Condition = constant.Value == null ? CustomSelectCondition.IsNull : CustomSelectCondition.IsEqualTo;
37 | break;
38 | case ExpressionType.NotEqual:
39 | Condition = constant.Value == null ? CustomSelectCondition.IsNotNull : CustomSelectCondition.IsNotEqualTo;
40 | break;
41 | }
42 |
43 | FilterValue = constant.Value;
44 | }
45 | }
46 |
47 | public Expression> GetFilter()
48 | {
49 | return Condition switch
50 | {
51 | CustomSelectCondition.IsEqualTo =>
52 | Expression.Lambda>(
53 | Expression.AndAlso(
54 | Column.Field.Body.CreateNullChecks(),
55 | Expression.Equal(
56 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
57 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
58 | Column.Field.Parameters),
59 |
60 | CustomSelectCondition.IsNotEqualTo => Expression.Lambda>(
61 | Expression.AndAlso(
62 | Column.Field.Body.CreateNullChecks(),
63 | Expression.NotEqual(
64 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
65 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
66 | Column.Field.Parameters),
67 |
68 | CustomSelectCondition.IsNull =>
69 | Expression.Lambda>(
70 | Expression.AndAlso(
71 | Column.Field.Body.CreateNullChecks(true),
72 | Expression.Equal(Column.Field.Body, Expression.Constant(null))),
73 | Column.Field.Parameters),
74 |
75 | CustomSelectCondition.IsNotNull =>
76 | Expression.Lambda>(
77 | Expression.AndAlso(
78 | Column.Field.Body.CreateNullChecks(true),
79 | Expression.NotEqual(Column.Field.Body, Expression.Constant(null))),
80 | Column.Field.Parameters),
81 |
82 | _ => throw new ArgumentException(Condition + " is not defined!"),
83 | };
84 | }
85 |
86 | public void AddSelect(string key, object value)
87 | {
88 | Items.Add(new KeyValuePair(key, value));
89 |
90 | if (FilterValue == null)
91 | {
92 | FilterValue = Items.FirstOrDefault().Value;
93 | }
94 |
95 | StateHasChanged();
96 | }
97 |
98 | public enum CustomSelectCondition
99 | {
100 | [LocalizedDescription("CustomSelectConditionIsEqualTo", typeof(Localization.Localization))]
101 | IsEqualTo,
102 |
103 | [LocalizedDescription("CustomSelectConditionIsNotEqualTo", typeof(Localization.Localization))]
104 | IsNotEqualTo,
105 |
106 | [LocalizedDescription("CustomSelectConditionIsNull", typeof(Localization.Localization))]
107 | IsNull,
108 |
109 | [LocalizedDescription("CustomSelectConditionIsNotNull", typeof(Localization.Localization))]
110 | IsNotNull
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/DateFilter.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
4 | @if (Column.FilterControl == this)
5 | {
6 | Condition = (NumberCondition)Enum.Parse(typeof(NumberCondition), x.Value.ToString()))">
7 | @foreach (var option in (NumberCondition[])Enum.GetValues(typeof(NumberCondition)))
8 | {
9 | @option.GetDescription()
10 | }
11 |
12 | @if (Condition != NumberCondition.IsNull && Condition != NumberCondition.IsNotNull)
13 | {
14 |
15 | }
16 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/DateFilter.razor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using System;
3 | using System.Linq.Expressions;
4 |
5 | namespace BlazorTable
6 | {
7 | public partial class DateFilter : IFilter
8 | {
9 | [CascadingParameter(Name = "Column")]
10 | public IColumn Column { get; set; }
11 |
12 | private NumberCondition Condition { get; set; }
13 |
14 | private DateTime FilterValue { get; set; } = DateTime.Now;
15 |
16 | protected override void OnInitialized()
17 | {
18 | if (Column.Type.GetNonNullableType() == typeof(DateTime))
19 | {
20 | Column.FilterControl = this;
21 |
22 | if (Column.Filter?.Body is BinaryExpression binaryExpression
23 | && binaryExpression.Right is BinaryExpression logicalBinary
24 | && logicalBinary.Right is ConstantExpression constant)
25 | {
26 | switch (binaryExpression.Right.NodeType)
27 | {
28 | case ExpressionType.Equal:
29 | Condition = constant.Value == null ? NumberCondition.IsNull : NumberCondition.IsEqualTo;
30 | break;
31 | case ExpressionType.NotEqual:
32 | Condition = constant.Value == null ? NumberCondition.IsNotNull : NumberCondition.IsNotEqualTo;
33 | break;
34 | case ExpressionType.GreaterThanOrEqual:
35 | Condition = NumberCondition.IsGreaterThanOrEqualTo;
36 | break;
37 | case ExpressionType.GreaterThan:
38 | Condition = NumberCondition.IsGreaterThan;
39 | break;
40 | case ExpressionType.LessThanOrEqual:
41 | Condition = NumberCondition.IsLessThanOrEqualTo;
42 | break;
43 | case ExpressionType.LessThan:
44 | Condition = NumberCondition.IsLessThan;
45 | break;
46 | }
47 |
48 | if (constant.Value != null && DateTime.TryParse(constant.Value.ToString(), out DateTime result))
49 | {
50 | FilterValue = result;
51 | }
52 | }
53 | }
54 | }
55 |
56 | public Expression> GetFilter()
57 | {
58 | return Condition switch
59 | {
60 | NumberCondition.IsEqualTo =>
61 | Expression.Lambda>(
62 | Expression.AndAlso(
63 | Column.Field.Body.CreateNullChecks(),
64 | Expression.Equal(
65 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
66 | Expression.Constant(FilterValue))),
67 | Column.Field.Parameters),
68 |
69 | NumberCondition.IsNotEqualTo =>
70 | Expression.Lambda>(
71 | Expression.AndAlso(
72 | Column.Field.Body.CreateNullChecks(),
73 | Expression.NotEqual(
74 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
75 | Expression.Constant(FilterValue))),
76 | Column.Field.Parameters),
77 |
78 | NumberCondition.IsGreaterThanOrEqualTo =>
79 | Expression.Lambda>(
80 | Expression.AndAlso(
81 | Column.Field.Body.CreateNullChecks(),
82 | Expression.GreaterThanOrEqual(
83 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
84 | Expression.Constant(FilterValue))),
85 | Column.Field.Parameters),
86 |
87 | NumberCondition.IsGreaterThan =>
88 | Expression.Lambda>(
89 | Expression.AndAlso(
90 | Column.Field.Body.CreateNullChecks(),
91 | Expression.GreaterThan(
92 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
93 | Expression.Constant(FilterValue))),
94 | Column.Field.Parameters),
95 |
96 | NumberCondition.IsLessThanOrEqualTo =>
97 | Expression.Lambda>(
98 | Expression.AndAlso(
99 | Column.Field.Body.CreateNullChecks(),
100 | Expression.LessThanOrEqual(
101 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
102 | Expression.Constant(FilterValue))),
103 | Column.Field.Parameters),
104 |
105 | NumberCondition.IsLessThan =>
106 | Expression.Lambda>(
107 | Expression.AndAlso(
108 | Column.Field.Body.CreateNullChecks(),
109 | Expression.LessThan(
110 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
111 | Expression.Constant(FilterValue))),
112 | Column.Field.Parameters),
113 |
114 | NumberCondition.IsNull =>
115 | Expression.Lambda>(
116 | Expression.AndAlso(
117 | Column.Field.Body.CreateNullChecks(true),
118 | Expression.Equal(Column.Field.Body, Expression.Constant(null))),
119 | Column.Field.Parameters),
120 |
121 | NumberCondition.IsNotNull =>
122 | Expression.Lambda>(
123 | Expression.AndAlso(
124 | Column.Field.Body.CreateNullChecks(true),
125 | Expression.NotEqual(Column.Field.Body, Expression.Constant(null))),
126 | Column.Field.Parameters),
127 |
128 | _ => throw new ArgumentException(Condition + " is not defined!"),
129 | };
130 | }
131 | }
132 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/EnumFilter.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
4 | @if (Column.FilterControl == this)
5 | {
6 | Condition = (EnumCondition)Enum.Parse(typeof(EnumCondition), x.Value.ToString()))">
7 | @foreach (EnumCondition option in Enum.GetValues(typeof(EnumCondition)))
8 | {
9 | @option.GetDescription()
10 | }
11 |
12 |
13 | @if (Condition != EnumCondition.IsNull && Condition != EnumCondition.IsNotNull)
14 | {
15 | FilterValue = Enum.Parse(Column.Type.GetNonNullableType(), x.Value.ToString()))">
16 | @foreach (var option in Enum.GetValues(Column.Type.GetNonNullableType()))
17 | {
18 | @((option as Enum).GetDescription() ?? option)
19 | }
20 |
21 | }
22 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/EnumFilter.razor.cs:
--------------------------------------------------------------------------------
1 | using BlazorTable.Localization;
2 | using Microsoft.AspNetCore.Components;
3 | using System;
4 | using System.Globalization;
5 | using System.Linq.Expressions;
6 | using Microsoft.Extensions.Localization;
7 |
8 | namespace BlazorTable
9 | {
10 | public partial class EnumFilter : IFilter
11 | {
12 | [CascadingParameter(Name = "Column")]
13 | public IColumn Column { get; set; }
14 |
15 | [Inject]
16 | IStringLocalizer Localization { get; set; }
17 |
18 | private EnumCondition Condition { get; set; }
19 |
20 | private object FilterValue { get; set; }
21 |
22 | protected override void OnInitialized()
23 | {
24 | if (Column.Type.GetNonNullableType().IsEnum)
25 | {
26 | Column.FilterControl = this;
27 |
28 | if (Column.Filter?.Body is BinaryExpression binaryExpression
29 | && binaryExpression.Right is BinaryExpression logicalBinary
30 | && logicalBinary.Right is ConstantExpression constant)
31 | {
32 | switch (binaryExpression.Right.NodeType)
33 | {
34 | case ExpressionType.Equal:
35 | Condition = constant.Value == null ? EnumCondition.IsNull : EnumCondition.IsEqualTo;
36 | break;
37 | case ExpressionType.NotEqual:
38 | Condition = constant.Value == null ? EnumCondition.IsNotNull : EnumCondition.IsNotEqualTo;
39 | break;
40 | }
41 |
42 | FilterValue = constant.Value;
43 | }
44 |
45 | if (FilterValue == null)
46 | {
47 | FilterValue = Enum.GetValues(Column.Type.GetNonNullableType()).GetValue(0);
48 | }
49 | }
50 | }
51 |
52 | public Expression> GetFilter()
53 | {
54 | return Condition switch
55 | {
56 | EnumCondition.IsEqualTo =>
57 | Expression.Lambda>(
58 | Expression.AndAlso(
59 | Column.Field.Body.CreateNullChecks(),
60 | Expression.Equal(
61 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
62 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
63 | Column.Field.Parameters),
64 |
65 | EnumCondition.IsNotEqualTo =>
66 | Expression.Lambda>(
67 | Expression.AndAlso(
68 | Column.Field.Body.CreateNullChecks(),
69 | Expression.NotEqual(
70 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
71 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
72 | Column.Field.Parameters),
73 |
74 | EnumCondition.IsNull =>
75 | Expression.Lambda>(
76 | Expression.AndAlso(
77 | Column.Field.Body.CreateNullChecks(true),
78 | Expression.Equal(Column.Field.Body, Expression.Constant(null))),
79 | Column.Field.Parameters),
80 |
81 | EnumCondition.IsNotNull =>
82 | Expression.Lambda>(
83 | Expression.AndAlso(
84 | Column.Field.Body.CreateNullChecks(true),
85 | Expression.NotEqual(Column.Field.Body, Expression.Constant(null))),
86 | Column.Field.Parameters),
87 |
88 | _ => throw new ArgumentException(Condition + " is not defined!"),
89 | };
90 | }
91 |
92 | public enum EnumCondition
93 | {
94 | [LocalizedDescription("EnumConditionIsEqualTo", typeof(Localization.Localization))]
95 | IsEqualTo,
96 |
97 | [LocalizedDescription("EnumConditionIsNotEqualTo", typeof(Localization.Localization))]
98 | IsNotEqualTo,
99 |
100 | [LocalizedDescription("EnumConditionIsNull", typeof(Localization.Localization))]
101 | IsNull,
102 |
103 | [LocalizedDescription("EnumConditionIsNotNull", typeof(Localization.Localization))]
104 | IsNotNull
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/NumberFilter.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
4 | @if (Column.FilterControl == this)
5 | {
6 | Condition = (NumberCondition)Enum.Parse(typeof(NumberCondition), x.Value.ToString()))">
7 | @foreach (var option in (NumberCondition[])Enum.GetValues(typeof(NumberCondition)))
8 | {
9 | @option.GetDescription()
10 | }
11 |
12 | @if (Condition != NumberCondition.IsNull && Condition != NumberCondition.IsNotNull)
13 | {
14 |
15 | }
16 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/NumberFilter.razor.cs:
--------------------------------------------------------------------------------
1 | using BlazorTable.Localization;
2 | using Microsoft.AspNetCore.Components;
3 | using System;
4 | using System.Globalization;
5 | using System.Linq.Expressions;
6 |
7 | namespace BlazorTable
8 | {
9 | public partial class NumberFilter : IFilter
10 | {
11 | [CascadingParameter(Name = "Column")]
12 | public IColumn Column { get; set; }
13 |
14 | [Inject]
15 | Microsoft.Extensions.Localization.IStringLocalizer Localization { get; set; }
16 |
17 | private NumberCondition Condition { get; set; }
18 |
19 | private string FilterValue { get; set; }
20 |
21 | protected override void OnInitialized()
22 | {
23 | if (Column.Type.IsNumeric() && !Column.Type.GetNonNullableType().IsEnum)
24 | {
25 | Column.FilterControl = this;
26 |
27 | if (Column.Filter?.Body is BinaryExpression binaryExpression
28 | && binaryExpression.Right is BinaryExpression logicalBinary
29 | && logicalBinary.Right is ConstantExpression constant)
30 | {
31 | switch (binaryExpression.Right.NodeType)
32 | {
33 | case ExpressionType.Equal:
34 | Condition = constant.Value == null ? NumberCondition.IsNull : NumberCondition.IsEqualTo;
35 | break;
36 | case ExpressionType.NotEqual:
37 | Condition = constant.Value == null ? NumberCondition.IsNotNull : NumberCondition.IsNotEqualTo;
38 | break;
39 | case ExpressionType.GreaterThanOrEqual:
40 | Condition = NumberCondition.IsGreaterThanOrEqualTo;
41 | break;
42 | case ExpressionType.GreaterThan:
43 | Condition = NumberCondition.IsGreaterThan;
44 | break;
45 | case ExpressionType.LessThanOrEqual:
46 | Condition = NumberCondition.IsLessThanOrEqualTo;
47 | break;
48 | case ExpressionType.LessThan:
49 | Condition = NumberCondition.IsLessThan;
50 | break;
51 | }
52 |
53 | if (constant.Value != null)
54 | {
55 | FilterValue = constant.Value.ToString();
56 | }
57 | }
58 | }
59 | }
60 |
61 | public Expression> GetFilter()
62 | {
63 | if (Condition != NumberCondition.IsNull && Condition != NumberCondition.IsNotNull && string.IsNullOrEmpty(FilterValue))
64 | {
65 | return null;
66 | }
67 |
68 | return Condition switch
69 | {
70 | NumberCondition.IsEqualTo =>
71 | Expression.Lambda>(
72 | Expression.AndAlso(
73 | Column.Field.Body.CreateNullChecks(),
74 | Expression.Equal(
75 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
76 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
77 | Column.Field.Parameters),
78 |
79 | NumberCondition.IsNotEqualTo =>
80 | Expression.Lambda>(
81 | Expression.AndAlso(
82 | Column.Field.Body.CreateNullChecks(),
83 | Expression.NotEqual(
84 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
85 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
86 | Column.Field.Parameters),
87 |
88 | NumberCondition.IsGreaterThanOrEqualTo =>
89 | Expression.Lambda>(
90 | Expression.AndAlso(
91 | Column.Field.Body.CreateNullChecks(),
92 | Expression.GreaterThanOrEqual(
93 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
94 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
95 | Column.Field.Parameters),
96 |
97 | NumberCondition.IsGreaterThan =>
98 | Expression.Lambda>(
99 | Expression.AndAlso(
100 | Column.Field.Body.CreateNullChecks(),
101 | Expression.GreaterThan(
102 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
103 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
104 | Column.Field.Parameters),
105 |
106 | NumberCondition.IsLessThanOrEqualTo =>
107 | Expression.Lambda>(
108 | Expression.AndAlso(
109 | Column.Field.Body.CreateNullChecks(),
110 | Expression.LessThanOrEqual(
111 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
112 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
113 | Column.Field.Parameters),
114 |
115 | NumberCondition.IsLessThan =>
116 | Expression.Lambda>(
117 | Expression.AndAlso(
118 | Column.Field.Body.CreateNullChecks(),
119 | Expression.LessThan(
120 | Expression.Convert(Column.Field.Body, Column.Type.GetNonNullableType()),
121 | Expression.Constant(Convert.ChangeType(FilterValue, Column.Type.GetNonNullableType(), CultureInfo.InvariantCulture)))),
122 | Column.Field.Parameters),
123 |
124 | NumberCondition.IsNull =>
125 | Expression.Lambda>(
126 | Expression.AndAlso(
127 | Column.Field.Body.CreateNullChecks(true),
128 | Expression.Equal(Column.Field.Body, Expression.Constant(null))),
129 | Column.Field.Parameters),
130 |
131 | NumberCondition.IsNotNull =>
132 | Expression.Lambda>(
133 | Expression.AndAlso(
134 | Column.Field.Body.CreateNullChecks(true),
135 | Expression.NotEqual(Column.Field.Body, Expression.Constant(null))),
136 | Column.Field.Parameters),
137 |
138 | _ => throw new ArgumentException(Condition + " is not defined!"),
139 | };
140 | }
141 | }
142 |
143 | public enum NumberCondition
144 | {
145 | [LocalizedDescription("NumberConditionIsEqualTo", typeof(Localization.Localization))]
146 | IsEqualTo,
147 |
148 | [LocalizedDescription("NumberConditionIsnotEqualTo", typeof(Localization.Localization))]
149 | IsNotEqualTo,
150 |
151 | [LocalizedDescription("NumberConditionIsGreaterThanOrEqualTo", typeof(Localization.Localization))]
152 | IsGreaterThanOrEqualTo,
153 |
154 | [LocalizedDescription("NumberConditionIsGreaterThan", typeof(Localization.Localization))]
155 | IsGreaterThan,
156 |
157 | [LocalizedDescription("NumberConditionIsLessThanOrEqualTo", typeof(Localization.Localization))]
158 | IsLessThanOrEqualTo,
159 |
160 | [LocalizedDescription("NumberConditionIsLessThan", typeof(Localization.Localization))]
161 | IsLessThan,
162 |
163 | [LocalizedDescription("NumberConditionIsNull", typeof(Localization.Localization))]
164 | IsNull,
165 |
166 | [LocalizedDescription("NumberConditionIsNotNull", typeof(Localization.Localization))]
167 | IsNotNull
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/BlazorTable/Filters/StringFilter.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @typeparam TableItem
3 |
4 | @if (Column.FilterControl == this)
5 | {
6 | Condition = (StringCondition)Enum.Parse(typeof(StringCondition), x.Value.ToString()))">
7 | @foreach (var option in (StringCondition[])Enum.GetValues(typeof(StringCondition)))
8 | {
9 | @option.GetDescription()
10 | }
11 |
12 |
13 | @if (Condition != StringCondition.IsNotNulOrEmpty && Condition != StringCondition.IsNullOrEmpty)
14 | {
15 |
16 | }
17 | }
--------------------------------------------------------------------------------
/src/BlazorTable/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 | // This file is used by Code Analysis to maintain SuppressMessage
2 | // attributes that are applied to this project.
3 | // Project-level suppressions either have no target or are given
4 | // a specific target and scoped to a namespace, type, member, etc.
5 |
6 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1715:Identifiers should have correct prefix", Justification = "", Scope = "namespaceanddescendants", Target = "BlazorTable")]
7 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "", Scope = "namespaceanddescendants", Target = "BlazorTable")]
8 |
--------------------------------------------------------------------------------
/src/BlazorTable/IServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace BlazorTable
4 | {
5 | public static class IServiceCollectionExtensions
6 | {
7 | public static IServiceCollection AddBlazorTable(this IServiceCollection services)
8 | {
9 | return services.AddLocalization();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Interfaces/IColumn.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using System;
3 | using System.Linq.Expressions;
4 | using System.Threading.Tasks;
5 |
6 | namespace BlazorTable
7 | {
8 | ///
9 | /// Table Column
10 | ///
11 | ///
12 | public interface IColumn
13 | {
14 | ///
15 | /// Parent Table
16 | ///
17 | ITable Table { get; set; }
18 |
19 | ///
20 | /// Title (Optional, will use Field Name if null)
21 | ///
22 | string Title { get; set; }
23 |
24 | ///
25 | /// Width auto|value|initial|inherit
26 | ///
27 | string Width { get; set; }
28 |
29 | ///
30 | /// Column can be sorted
31 | ///
32 | bool Sortable { get; set; }
33 |
34 | ///
35 | /// Column can be filtered
36 | ///
37 | bool Filterable { get; set; }
38 |
39 | ///
40 | /// Column can be hidden
41 | ///
42 | bool Hideable { get; set; }
43 |
44 | ///
45 | /// Set the format for values if no template
46 | ///
47 | string Format { get; set; }
48 |
49 | ///
50 | /// Filter Panel is open
51 | ///
52 | bool FilterOpen { get; }
53 |
54 | ///
55 | /// Column visibility
56 | /// True if current column is visible else false.
57 | ///
58 | bool Visible { get; set; }
59 |
60 | ///
61 | /// Opens/Closes the Filter Panel
62 | ///
63 | void ToggleFilter();
64 |
65 | ///
66 | /// Sort by this column
67 | ///
68 | Task SortByAsync();
69 |
70 | ///
71 | /// Column Data Type
72 | ///
73 | Type Type { get; set; }
74 |
75 | ///
76 | /// Field which this column is for
77 | /// Required when Sortable = true
78 | /// Required when Filterable = true
79 | ///
80 | Expression> Field { get; set; }
81 |
82 | ///
83 | /// Filter expression
84 | ///
85 | Expression> Filter { get; set; }
86 |
87 | ///
88 | /// Edit Mode Item Template
89 | ///
90 | RenderFragment EditTemplate { get; set; }
91 |
92 | ///
93 | /// Normal Item Template
94 | ///
95 | RenderFragment Template { get; set; }
96 |
97 | ///
98 | /// Set custom Footer column value
99 | ///
100 | string SetFooterValue { get; set; }
101 |
102 | ///
103 | /// Currently applied Filter Control
104 | ///
105 | IFilter FilterControl { get; set; }
106 |
107 | ///
108 | /// Place custom controls which implement IFilter
109 | ///
110 | RenderFragment> CustomIFilters { get; set; }
111 |
112 | ///
113 | /// True if this is the current Sort Column
114 | ///
115 | bool SortColumn { get; set; }
116 |
117 | ///
118 | /// Direction of sorting
119 | ///
120 | bool SortDescending { get; set; }
121 |
122 | ///
123 | /// ARIA sort value, if any
124 | ///
125 | string AriaSort => SortColumn ? (SortDescending ? "descending" : "ascending") : null;
126 |
127 | ///
128 | /// Horizontal alignment
129 | ///
130 | Align Align { get; set; }
131 |
132 | ///
133 | /// Aggregates table column for the footer. It can only be applied to numerical fields (e.g. int, long decimal, double, etc.).
134 | ///
135 | AggregateType? Aggregate { get; set; }
136 |
137 | ///
138 | /// Filter Icon Element
139 | ///
140 | ElementReference FilterRef { get; set; }
141 |
142 | ///
143 | /// Column CSS Class
144 | ///
145 | string Class { get; set; }
146 |
147 | ///
148 | /// Column Footer CSS Class
149 | ///
150 | string ColumnFooterClass { get; set; }
151 |
152 | ///
153 | /// True if this is the default Sort Column
154 | ///
155 | bool? DefaultSortColumn { get; set; }
156 |
157 | ///
158 | /// Direction of default sorting
159 | ///
160 | bool? DefaultSortDescending { get; set; }
161 |
162 |
163 | ///
164 | /// Returns aggregation of this column for the table footer based on given type: Sum, Average, Count, Min, or Max.
165 | ///
166 | /// string results
167 | string GetFooterValue();
168 |
169 | ///
170 | /// Default render if no Template specified
171 | ///
172 | ///
173 | ///
174 | string Render(TableItem item);
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/src/BlazorTable/Interfaces/ICustomSelect.cs:
--------------------------------------------------------------------------------
1 | namespace BlazorTable
2 | {
3 | public interface ICustomSelect
4 | {
5 | public void AddSelect(string key, object value);
6 | }
7 | }
--------------------------------------------------------------------------------
/src/BlazorTable/Interfaces/IDataLoader.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using BlazorTable.Components.ServerSide;
3 |
4 | namespace BlazorTable.Interfaces
5 | {
6 | public interface IDataLoader
7 | {
8 | public Task> LoadDataAsync(FilterData parameters);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/BlazorTable/Interfaces/IFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace BlazorTable
5 | {
6 | ///
7 | /// Filter Component Interface
8 | ///
9 | ///
10 | public interface IFilter
11 | {
12 | ///
13 | /// Get Filter Expression
14 | ///
15 | ///
16 | Expression> GetFilter();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/BlazorTable/Interfaces/ITable.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace BlazorTable
4 | {
5 | ///
6 | /// BlazorTable Interface
7 | ///
8 | public interface ITable
9 | {
10 | ///
11 | /// Page Size
12 | ///
13 | int PageSize { get; }
14 |
15 | ///
16 | /// Allow Columns to be reordered
17 | ///
18 | bool ColumnReorder { get; set; }
19 |
20 | ///
21 | /// Current Page Number
22 | ///
23 | int PageNumber { get; }
24 |
25 | ///
26 | /// Total Count of Items
27 | ///
28 | int TotalCount { get; }
29 |
30 | ///
31 | /// Total Pages
32 | ///
33 | public int TotalPages { get; }
34 |
35 | ///
36 | /// Is Table in Edit mode
37 | ///
38 | bool IsEditMode { get; }
39 |
40 |
41 | ///
42 | /// Go to First Page Async
43 | ///
44 | Task FirstPageAsync();
45 |
46 | ///
47 | /// Go to Next Page
48 | ///
49 | Task NextPageAsync();
50 |
51 | ///
52 | /// Go to Previous Page
53 | ///
54 | Task PreviousPageAsync();
55 |
56 | ///
57 | /// Go to Last Page
58 | ///
59 | Task LastPageAsync();
60 |
61 | ///
62 | /// Redraws the Table using EditTemplate instead of Template
63 | ///
64 | void ToggleEditMode();
65 |
66 | ///
67 | /// Table Element CSS
68 | ///
69 | string TableClass { get; set; }
70 |
71 | ///
72 | /// Table Body CSS
73 | ///
74 | string TableBodyClass { get; set; }
75 |
76 | ///
77 | /// Table Head CSS
78 | ///
79 | string TableHeadClass { get; set; }
80 |
81 | ///
82 | /// Redraws Table without Getting Data
83 | ///
84 | void Refresh();
85 |
86 | ///
87 | /// Gets Data and redraws the Table
88 | ///
89 | Task UpdateAsync();
90 | ///
91 | /// Open/Close detail view in specified row.
92 | ///
93 | /// number of row to toggle detail view
94 | /// true for openening detail view, false for closing detail view
95 | void ToggleDetailView(int row, bool open);
96 |
97 | ///
98 | /// Open/Close all detail views.
99 | ///
100 | /// true for openening detail view, false for closing detail view
101 | void ToggleAllDetailsView(bool open);
102 |
103 | ///
104 | /// Set the EmptyDataTemplate for the table
105 | ///
106 | ///
107 | void SetEmptyDataTemplate(EmptyDataTemplate template);
108 |
109 | ///
110 | /// Set the LoadingDataTemplate for the table
111 | ///
112 | ///
113 | void SetLoadingDataTemplate(LoadingDataTemplate template);
114 |
115 |
116 | ///
117 | /// Select Type: None, Single or Multiple
118 | ///
119 | public SelectionType SelectionType { get; set; }
120 |
121 | ///
122 | /// Search all columns for the specified string, supports spaces as a delimiter
123 | ///
124 | string GlobalSearch { get; set; }
125 |
126 | ///
127 | /// Shows Search Bar above the table
128 | ///
129 | bool ShowSearchBar { get; set; }
130 |
131 | ///
132 | /// Show or hide table footer. Hide by default.
133 | ///
134 | bool ShowFooter { get; set; }
135 |
136 | ///
137 | /// Set Table Page Size
138 | ///
139 | ///
140 | Task SetPageSizeAsync(int pageSize);
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/BlazorTable/Interfaces/ITableGen.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 |
6 | namespace BlazorTable
7 | {
8 | ///
9 | /// BlazorTable Interface
10 | ///
11 | ///
12 | public interface ITable : ITable
13 | {
14 | ///
15 | /// List of All Available Columns
16 | ///
17 | List> Columns { get; }
18 |
19 | ///
20 | /// Adds a Column to the Table
21 | ///
22 | ///
23 | void AddColumn(IColumn column);
24 |
25 | ///
26 | /// Removes a Column from the Table
27 | ///
28 | ///
29 | void RemoveColumn(IColumn column);
30 |
31 | ///
32 | /// IQueryable data source to display in the table
33 | ///
34 | IQueryable ItemsQueryable { get; set; }
35 |
36 | ///
37 | /// Collection to display in the table
38 | ///
39 | IEnumerable Items { get; set; }
40 |
41 | ///
42 | /// Collection of filtered items
43 | ///
44 | IEnumerable FilteredItems { get; }
45 |
46 | ///
47 | /// Action performed when the row is clicked
48 | ///
49 | Action RowClickAction { get; set; }
50 |
51 | ///
52 | /// Collection of selected items
53 | ///
54 | List SelectedItems { get; }
55 |
56 | ///
57 | /// Set the SetDetailTemplate for the table
58 | ///
59 | ///
60 | void SetDetailTemplate(DetailTemplate template);
61 |
62 | ///
63 | /// Add custom row to table
64 | ///
65 | /// Custom row to add
66 | void AddCustomRow(CustomRow customRow);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/BlazorTable/LinkerConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/BlazorTable/LocalizedDescriptionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Reflection;
4 | using System.Resources;
5 |
6 | namespace BlazorTable
7 | {
8 | public class LocalizedDescriptionAttribute : DescriptionAttribute
9 | {
10 | private readonly string _resourceKey;
11 | private readonly ResourceManager _resource;
12 | public LocalizedDescriptionAttribute(string resourceKey, Type resourceType)
13 | {
14 | _resource = new ResourceManager(resourceType);
15 | _resourceKey = resourceKey;
16 | }
17 |
18 | public override string Description
19 | {
20 | get
21 | {
22 | string displayName = _resource.GetString(_resourceKey);
23 |
24 | return string.IsNullOrEmpty(displayName)
25 | ? string.Format("[[{0}]]", _resourceKey)
26 | : displayName;
27 | }
28 | }
29 | }
30 |
31 | public static class EnumExtensions
32 | {
33 | public static string GetDescription(this Enum enumValue)
34 | {
35 | FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());
36 |
37 | DescriptionAttribute[] attributes =
38 | (DescriptionAttribute[])fi.GetCustomAttributes(
39 | typeof(DescriptionAttribute),
40 | false);
41 |
42 | if (attributes != null &&
43 | attributes.Length > 0)
44 | return attributes[0].Description;
45 | else
46 | return enumValue.ToString();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/BlazorTable/_Imports.razor:
--------------------------------------------------------------------------------
1 | @namespace BlazorTable
2 | @using System.Net.Http
3 | @using Microsoft.AspNetCore.Components
4 | @using Microsoft.AspNetCore.Components.Web
--------------------------------------------------------------------------------
/src/BlazorTable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable/icon.png
--------------------------------------------------------------------------------
/src/BlazorTable/wwwroot/images/filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable/wwwroot/images/filter.png
--------------------------------------------------------------------------------
/src/BlazorTable/wwwroot/images/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable/wwwroot/images/minus.png
--------------------------------------------------------------------------------
/src/BlazorTable/wwwroot/images/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable/wwwroot/images/plus.png
--------------------------------------------------------------------------------
/src/BlazorTable/wwwroot/images/sort-asc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable/wwwroot/images/sort-asc.png
--------------------------------------------------------------------------------
/src/BlazorTable/wwwroot/images/sort-desc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvanJosipovic/BlazorTable/758cdeef0ffda428889ced0e13d34007be29bd54/src/BlazorTable/wwwroot/images/sort-desc.png
--------------------------------------------------------------------------------