In a regular MVC view table, rendering more than a few Blazor components triggers a disconnect from the server - asp.net-core

In a .NET Core 3.1 MVC application, we use blazor components to for creating and editing records in a table.
The table is built in a CSHTML view, and the rows are supplied by foreaching through a list.
Each row has one 'edit' button, which is actually a blazor component set to 'prerender', and which takes in the record as a parameter.
When the view loads, some 500+ records are added to the table, and each record gets one instance of the component. We didn't expect very good performance out of it, but appereantly after around 70 rows are added to the table, the blazor server sends a disconnect signal to the client - the reason for which I have not yet discovered - and I'm guessing that somewhere a limit is reached.
We know there is no exception happening in the blazor component itself, because the same behavior can be reproduced when you use a component that has just a simple paragraph tag with text.
Some solutions we've come up with are:
Moving the whole table to a blazor component, since we've built pure blazor apps that never have had this issue. But this comes at a downside because, that would mean we need to manually do the JS stuff and manage the table instantiation ourselves. This is not an option.
Using the RenderTreeBuilder API to use 1 instance of the EditModalComponent, and manually build the component when it's necessary. But so far, I haven't been able to output the actual component, just the namespace. This still seems like it would be a best-of-both-worlds situation, where I can keep the number of rendered components to 1 (instead of 500). This would be my bet.
I'm about to open a question on using the RenderTreeBuilder in this particular case, but I'm wondering whether anyone can explain to me, why below solution will trigger a disconnect after a certain number of components? Am I overloading the SignalR connection?
<!-- Table implements Datatables.js -->
<table id="table" class="table hover responsive row-border" width="100%">
<thead>
<tr>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var record in Model.Records) // Count would be around 500 records.
{
<tr>
<td>#record.FullName</td>
<td><component type="typeof(EditModalComponent)" render-mode="ServerPrerendered" param-Record="#record" /></td>
</tr>
}
</tbody>
</table>

Related

Update JS datatable in Blazor

I am using the Datatables.net library (https://datatables.net) in my Blazor app by following the suggested solution here (Using datatables.net with server-side Blazor application).
This all works well for the initial load, however, when I want to update my data and essentially reload/redraw the datatable, I can not for the life of me get it to re-render correctly and the datatable goes empty and says there is no data.
Essentially I am wanting to update the following and have the JS datatables redraw:
<tbody>
#foreach (var administrator in Administrators)
{
<tr>
<td>#administrator.Id</td>
<td>#administrator.LastName</td>
<td>#administrator.AccessLevel.GetDisplayName()</td>
<td>#administrator.DateCreated.ToShortDateString()</td>
</tr>
}
</tbody>
I do this via a button click (server side) that runs code to go to the database and update the list of Administrators. Sometimes it seems that the JS interop code to create the table runs before the actual HTML is updated by the change of the Administrators list even when I call `StateHasChanged()``` at every turn.
I have tried updating my JS function to .clear() and .destory() the datatable before recreating it, I have just tried to only create it once and call invalidate() and .draw() but nothing seemed to make a difference.
I have searched through the net looking for a way to achieve this but all the solutions seem to only cater for the initial render and do not talk about modifying/updating the data. The closest I could find was not to use the HTML/DOM to generate the data for the datatables library but send a JSON object back and rebuild it but I feel that defeats the purpose of using Blazor and means if I want to have any customised html display (e.g. a link) I need to really start to modify the JS code.

How can add table pagination using vueJS?

I have a data table that displays multiple records in one page.. I need to do the following:
1- Pagination of the data table pages.
2- Display 10 records per page and give the user the ability to increase this number. For example.. (10, 20, 50, 100) records per page.
How can I do it using VueJS?
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Email</th>
<th>Date & Time</th>
</thead>
<tbody>
<tr> <td>1</td>
<td>Sara</td> <td>example1#example.com</td>
<td>12/2/2021 16:40</td>
</tr>
<tr>
<td>2</td>
<td>Safa</td> <td>example2#example.com</td>
<td>24/2/2021 08:40</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-4">
Showing 10 out of 100
</div>
<div class="col-8 text-end">
<div class="btn-group" role="group" aria-label="Basic outlined example">
<button type="button" class="btn btn-outline-primary">1</button>
<button type="button" class="btn btn-outline-primary">2</button>
<button type="button" class="btn btn-outline-primary">3</button>
</div>
</div>
</div>
You could tackle this a number of ways. To start, you could keep all of your logic in your current file, open a script block, define a Vue instance, set up a data object, define a data variable for the number of items per page as well as anything else you want to track.
Then, you'll use a v-model binding on an input field in your template, which you would need to read the Vue docs to get a better handle on (very good documentation available). Keep it simple to start. Don't have pagination, just begin with an input field in which your user enters the number of items that should render in the table. Get that working. Then, shift to a drop-down with multiple defined options, which again you could define in the data object and iterate through those (new now) in your template using a v-for loop. You can use a prebuilt dropdown with any number of Vue UI libraries like Vuetify or VueBoostrap or many others. You'll need to read their respective documentation, but it's pretty straight forward.
Then to add pagination, you'd need to learn about routing and route parameters and how to send such parameters to your API as params on the get request. Axios can handle this for you.
Sounds like you need to start with basics and get comfortable with simple projects. Building fully functional data tables are quite hard! There are many great libraries available for VueJS that help you with data tables, even large commercial ones as well.
Read the documentation and watch YT tutorials before tackling complex stuff. To be sure, tables are well suited for components as opposed to single templates. You would need to learn how to separate out logic, e.g. a dropdown component. Take your time and keep learning!
Here would be a list of table related projects to help you understand, see their docs and examples:
https://awesome-vue.js.org/components-and-libraries/ui-components.html#table
-Marcus

Vuetify v-data-table not responsive when using v-slot:body

Vuetify v-data-table not stacking on mobile devices when using v-slot:body
How can I get the data table to stack if it implements the body v-slot? As can be seen in the Vuetify documentation this is how a normal v-data-table behaves:
And this is how it behaves when using body slot:
Thank you.
The default body implementation of v-data-table has two components for the table rows - Row and MobileRow. When the page's width is under 600px, MobileRow is used.
By using the body slot, the default implementation is discarded, along with the mobile logic, so you must supply your own. Fortunately, there's a handy helper class we can use to easily switch styling depending on the current page size.
Here's a codepen with a sketch up of the solution. The relevant part:
<template v-slot:body="props">
<tbody>
<tr v-for="item in props.items">
<td class="d-block d-sm-table-cell" v-for="field in Object.keys(item)">
{{item[field]}}
</td>
</tr>
</tbody>
</template>
For more precise styling, you might want to use the visibility helper classes and have two separate implementations for the table rows - just like the default implementation.

Get product price in html module opencart 2.x

Im beginner in opencart developing, and now i need something pretty simple ( as i think...) im using opencart 2.1.0.1 and i made a simple table
<table align="left" border="1" cellspacing="1" style="table-layout:fixed;width:500px;">
<tbody>
<tr>
<td style="text-align: center;"></td>
<td style="text-align: center;"></td>
</tr>
<tr>
<td>here i want the product price</td>
<td>here i want the prduct price</td>
</tr>
</tbody>
I want to get the product price in the data cells(and maybe to make some operations with it later on the backend).
Is it possible by making a html module, or i need to put my code directly on my .tpl page and use the controller?
EDIT: Given the feedback on my original answer, the updated response is below:
You can access the price by using $price but this will contain the currency so you can insert the code below on the tpl file before your table:
<?php
$pricenew = $product['price'];
$pricenew = preg_replace( '/\D/', '', $pricenew );
?>
Now you can use $pricenew on your table as your formula requires it.
Original Answer:
Assuming you're creating an extension for the OpenCart install, you will need to have both a controller and a view (.tpl file) at the very least, best practises would encourage you to include a language file to make translation simpler. You may not require a model if you're just displaying certain products.
I would suggest reading this from the OpenCart documentation, there are also tutorials that make learning OpenCart extension development simpler. Here's a tutorial on making an extension that displays recent products.

WinJS render listView in a table

I am working on HTML/JS Win8 store app. I would like to render ListView in a table. How would I achieve this?
For now I have something like that:
<table id="products">
<tbody>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
<tr data-win-control="WinJS.Binding.Template" id="productsRowTemplate">
<td data-win-bind="textContent: name"></td>
<td data-win-bind="textContent: description"></td>
</tr>
</tbody>
</table>
<div id="productsListView"
data-win-control="WinJS.UI.ListView"
data-win-bind="winControl.itemDataSource: products.dataSource;"
data-win-options="{
itemTemplate: select('#productsRowTemplate'),
layout: { type: WinJS.UI.ListLayout }
}">
</div>
However, the result is not what I expect at all:
http://postimg.org/image/4z39tvu9v/
I would like to achieve effect similar to this one (I used styling from that example in my view):
http://www.w3schools.com/css/tryit.asp?filename=trycss_table_fancy
The reason why I use listView is that I am working with ViewModels which expose collections via properties - I just want to bind data to the view and show it using specific template. I would definately not want to create table dynamically from view's code behind.
If your goal is to render a table, the ListView is not what you want. The key thing is to separate the idea of the collection--your data source--from the control that you use to present it. That's why there's a WinJS.Binding.List collection class and a WinJS.UI.ListView control as separate entities.
A table is one way to present a collection; a ListView is another. So it doesn't really make sense to try to combine the two. In your markup, the template elements will actually be removed from the DOM and not render in the table. The ListView will attempt to use that template to render itself, but as it generates <tr> and <td> elements within its own div (outside of a <table>) it won't really work. That is, the template gets rendered for each item in the data source as children of the div where you declare the ListView, not at the place where you declare the template.
Although you could declare the ListView as a child of the table, it won't quite work there either because the ListView creates a deep div structure below the element where you declare it.
So count the ListView out for this purpose. What you want instead is a simple custom control that can take a WinJS.Binding.List and render a template as direct children of that control. In Windows 8.1 Preview there is a new control called the Repeater that serves this exact purpose, and the HTML Repeater control sample demonstrates it in the context of a <table>. Note that you'll want to use a <thead> for your headings and declare the control on the <tbody> so it can render copies of the template that has <tr> as the root element.
If you're targeting Windows 8 you won't have the Repeater, of course, but it's not too complicated to create one of your own (borrowing from the Win8.1 Repeater sources if you want). Define a constructor with WinJS.Class.define and make sure you have options through which you can declaratively specify the data source and the template. The template would contain your data-win-bind attributes. In the controls' constructor, iterate through the Binding.List, rendering a copy of template for each item in the list. Then call WinJS.Binding.processAll with the root element of that item and the item from the data source, which will set up the data binding you want.
You'd declare this control again on the tbody element so it creates tr children in the right place. To use the Repeater example (where it uses an inline template):
<table class="table">
<thead class="table-header"><tr><td>Id</td><td>Description</td></tr></thead>
<tbody class="table-body"
data-win-control="WinJS.UI.Repeater" data-win-options="{data: Data.items}">
<tr class="table-body-row">
<td data-win-bind="textContent: id"></td>
<td data-win-bind="textContent: description"></td>
</tr>
</tbody>
</table>
In the end you are creating the table dynamically, but it's encapsulated in the control so you can set up the data binding relationships declaratively.