This is the continuation of the Part 1 tutorial. The main goal here is to apply rendered elements in the datatable, which can contain various HTML tags, such as links/operations with other pages.
Technologies used:
1. Javascript, Datatables.js
2. Razor Pages, .Net Core
3. In-Memory Database in .Net Core
Prerequisites:
1. Asp.Net Core 2.2 Razor Pages, see suggested learning: https://mydev-journey.blogspot.com/2019/11/razor-pages-not-for-shaving.html
2. In-memory Database, presented in tutorial: https://exceptionnotfound.net/ef-core-inmemory-asp-net-core-store-database/
3. I was inspired by this tutorial: https://www.c-sharpcorner.com/article/using-datatables-grid-with-asp-net-mvc/
4. See Part 1, which is the more simple approach for DataTables: https://mydev-journey.blogspot.com/
5. Link for Part 2 Repository, zipped: https://drive.google.com/open?id=1PT9Tk77m2gfZVrFmLwefSt_lqXuYyvEr
6. setup the wwwroot folder, in a similar way as for the Part 1 tutorial
7. you can view the application live online: http://datatables.azurewebsites.net/
Steps:
1. Create Razor Web Project
2. Create Base Class:
public class InvoiceModel
{
[JsonProperty(PropertyName = "ID")]
public int ID { get; set; }
[JsonProperty(PropertyName = "InvoiceNumber")]
public int InvoiceNumber { get; set; }
[JsonProperty(PropertyName = "Amount")]
public double Amount { get; set; }
[JsonProperty(PropertyName = "CostCategory")]
public string CostCategory { get; set; }
[JsonProperty(PropertyName = "Period")]
public string Period { get; set; }
}
3. Create and Populate in-memory database and table
Create Context:
public class InvoiceContext : DbContext
{
public InvoiceContext(DbContextOptions<InvoiceContext> options)
: base(options)
{
}
public DbSet<InvoiceModel> InvoiceTable { get; set; }
}
Create Invoice Generator Service
public class InvoiceGenerator
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var context = new InvoiceContext(serviceProvider.GetRequiredService<DbContextOptions<InvoiceContext>>()))
{
// Look for any board games.
if (context.InvoiceTable.Any())
{
return; // Data was already seeded
}
context.InvoiceTable.AddRange(
new InvoiceModel() { ID=1, InvoiceNumber = 1, Amount = 10, CostCategory = "Utilities", Period = "2019_11" },
new InvoiceModel() { ID=2, InvoiceNumber = 2, Amount = 50, CostCategory = "Telephone", Period = "2019_12" },
new InvoiceModel() { ID = 3, InvoiceNumber = 3, Amount = 30, CostCategory = "Services", Period = "2019_11" },
new InvoiceModel() { ID = 4, InvoiceNumber = 4, Amount = 40, CostCategory = "Consultancy", Period = "2019_11" },
new InvoiceModel() { ID = 5, InvoiceNumber = 5, Amount = 60, CostCategory = "Raw materials", Period = "2019_10" },
new InvoiceModel() { ID = 6, InvoiceNumber = 6, Amount = 10, CostCategory = "Raw materials", Period = "2019_11" },
new InvoiceModel() { ID = 7, InvoiceNumber = 7, Amount = 30, CostCategory = "Raw materials", Period = "2019_11" },
new InvoiceModel() { ID = 8, InvoiceNumber = 8, Amount = 30, CostCategory = "Services", Period = "2019_11" },
new InvoiceModel() { ID = 9, InvoiceNumber = 8, Amount = 20, CostCategory = "Services", Period = "2019_11" },
new InvoiceModel() { ID = 10, InvoiceNumber = 9, Amount = 2, CostCategory = "Services", Period = "2019_11" },
new InvoiceModel() { ID = 11, InvoiceNumber = 10, Amount = 24, CostCategory = "Services", Period = "2019_11" },
new InvoiceModel() { ID = 12, InvoiceNumber = 11, Amount = 10, CostCategory = "Telephone", Period = "2019_11" },
new InvoiceModel() { ID = 13, InvoiceNumber = 12, Amount = 40, CostCategory = "Consultancy", Period = "2019_12" },
new InvoiceModel() { ID = 14, InvoiceNumber = 13, Amount = 50, CostCategory = "Services", Period = "2019_11" },
new InvoiceModel() { ID = 15, InvoiceNumber = 14, Amount = 40, CostCategory = "Utilities", Period = "2019_11" },
new InvoiceModel() { ID = 16, InvoiceNumber = 15, Amount = 10, CostCategory = "Services", Period = "2019_11" });
context.SaveChanges();
}
}
4. Register the database
within Startup cs, above add MVC command:
services.AddDbContext<InvoiceContext>(options => options.UseInMemoryDatabase(databaseName: "InvoiceDB"));
within Program Cs, we need to make changes, see final version:
public class Program
{
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args).Build();
//2. Find the service layer within our scope.
using (var scope = host.Services.CreateScope())
{
//3. Get the instance of BoardGamesDBContext in our services layer
var services = scope.ServiceProvider;
var context = services.GetRequiredService<InvoiceContext>();
//4. Call the DataGenerator to create sample data
InvoiceGenerator.Initialize(services);
}
//Continue to run the application
host.Run();
//CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
5. Using EF, the tables are populated in all Pages, see example for Index:
PageModel:
public class IndexModel : PageModel
{
private InvoiceContext _context;
public List<InvoiceModel> InvoiceList;
public IndexModel(InvoiceContext context)
{
_context = context;
}
public void OnGet()
{
InvoiceList = _context.InvoiceTable.ToList();
}
}
CSHTML file
will be a simple listing of the InvoiceTable using foreach (actually you can scaffold this view)
6. DataTableArrayRender page:
Will contain the datatable js code, together with the rendered html elements:
@page
@model DataTableArrayRenderModel
@{
ViewData["Title"] = "Invoice List - With Datatable - from Javascript Array";
}
<div class="text-center">
<h1 class="display-4">Show DataTable - from Javascript Array - Rendered Columns</h1>
<p>
<a asp-page="Index">Show original Table (Html from Razor)</a>
</p>
<p>
<a asp-page="InvoiceAdd" class="btn btn-info">Add New Invoice</a>
</p>
</div>
<script type="text/javascript" language="javascript" src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/js/jquery.dataTables.min.js"></script>
<script>
/////////
function convertToDataSet(responseJSON) {
console.log(responseJSON);
var returnList = [];
var returnitem = [];
for (var i = 0; i < responseJSON.length; i++) {
console.log(responseJSON[i]);
returnitem = [];
returnitem.push(responseJSON[i].ID);
returnitem.push(responseJSON[i].InvoiceNumber);
returnitem.push(responseJSON[i].Amount);
returnitem.push(responseJSON[i].CostCategory);
returnitem.push(responseJSON[i].Period);
returnList.push(returnitem);
}
return returnList;
}
function getTable() {
return fetch('./DataTableArrayRender?handler=ArrayDataRender',
{
method: 'get',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
.then(function (response) {
if (response.ok) {
return response.text();
} else {
throw Error('Response Not OK');
}
})
.then(function (text) {
try {
return JSON.parse(text);
} catch (err) {
throw Error('Method Not Found');
}
})
.then(function (responseJSON) {
var dataSet = convertToDataSet(responseJSON);
console.log(dataSet);
$(document).ready(function () {
$('#example').DataTable({
data: dataSet,
"processing": true, // for show progress bar
"filter": true, // this is for disable filter (search box)
"orderMulti": false, // for disable multiple column at once
columns: [
{ title: "ID" },
{ title: "InvoiceNumber" },
{ title: "Amount" },
{ title: "CostCategory" },
{ title: "Period" },
{
data: null, render: function (data, type, row) {
return '<a class="btn btn-danger" href="/InvoiceDelete?id=' + row[0] + '">Delete</a>';
}
},
{
"render": function (data, type, full, meta)
{ return '<a class="btn btn-info" href="/InvoiceEdit?id=' + full[0] + '">Edit</a>'; }
},
{
"render": function (data, type, full, meta)
{ return '<a class="btn btn-warning" href="/Index">Main Page</a>'; }
},
]
});
});
})
}
getTable();
</script>
<table id="example" class="display" width="100%"></table>
7. Using the InvoiceModel, we can scaffold all pages like Delete, Create, Edit using EF model scaffolding of Razor Pages.
8. The end result will be a nice navigation table that besides the invoice data, will contain the rendered buttons/links.
End result:
No comments:
Post a Comment