TL;DR: Deliver all the table content continuously paginated to the browser with .NET Core and Angular
Long Description:
I was thinking that delivering paginating data is kind of lame. Why should I , for seeing the whole data, should keep pressing next page / or scrolling down ? I understand that on the server it is necessary to do this – but on the client ?
And I was thinking – what about Observables in Angular , combined with SignalR ? Those observables could obtain data every time – and SignalR is pushing cotinously, until it arrives at the end of the data.
Done with talking – let’s show some code:
We have an Employee classs
public class Employee
{
public string Name { get; set; }
public int Id { get; set; }
}
code
and we are feeding with data in a DALEmployee
public class DalEmployee
{
public int FindCountEmployees(string name)
{
return ((name ?? "").Length + 1) * 10;
}
public async Task<Employee[]> FindEmployee(int pageNumber, int pageSize, string name)
{
await Task.Delay((pageNumber + 1) * 1000);
var ret = new Employee[pageSize];
int startNumber = (pageNumber - 1) * pageSize;
for (int i = 0; i < pageSize; i++)
{
var e =new Employee();
e.Id = startNumber + i;
e.Name = e.Id + "employee ";
ret[i] = e;
}
return ret;
}
}
We have SignalR that delivers continously the data via a Hub that is connected to an URL
//do not forget services.AddSignalR().AddJsonProtocol() ;
app.UseSignalR(routes =>
{
routes.MapHub<MyHub>("/employees");
})
and delivers all data continuously
public class MyHub: Hub
{
public override async Task OnConnectedAsync()
{
Console.WriteLine("!!!!connected");
await Task.Delay(1000);
}
public ChannelReader<Employee[]> GetEmps(string name)
{
var channel = Channel.CreateUnbounded<Employee[]>();
_ = WriteItems(channel.Writer, name); //it not awaits!
return channel.Reader;
}
private async Task WriteItems(ChannelWriter<Employee[]> writer, string name)
{
var dal = new DalEmployee();
var nr = dal.FindCountEmployees(name);
int nrPages = 10;
for (int i = 0; i < nr / nrPages; i++)
{
var data = await dal.FindEmployee(i+1, nrPages, name);
await writer.WriteAsync(data);
}
writer.TryComplete();
}
And this is all that is required on the .NET Core side
For the Angular Part
We have a hubconnectionbuilder that connect to the hub
export class MydataService {
h:HubConnection;
constructor(private http: HttpClient) {
this.h= new HubConnectionBuilder()
.withUrl(environment.urlAPI + "/employees")
.withHubProtocol(new JsonHubProtocol())
//.withHubProtocol(new MessagePackHubProtocol())
.build();
window.alert('start');
this.h.start()
.catch((t) => window.alert(1));
}
}
and a observable that returns the values
public getAllEmpsStream(name:string): Observable<Employee[]>{
const subject = new Subject<Employee[]>();
this.h.stream<Employee[]>("GetEmps",name).subscribe(subject);
return subject.asObservable();
}
The code on the component is aggregating the values into an array
findEmployees(){
this.load=true;
this.service
.getAllEmpsStream(this.nameEmp)
//.getEmps(this.nameEmp)
.pipe(finalize(() => this.load=false))
.subscribe(it => {
//window.alert(it.length);
this.emp.push(...it);
});
}
And that is all. All the values are returned page after page without the need of human intervention…