Blazor navigation from within a loop? - c#

So I'm trying to make a Blazor application that displays a customers data. When all the customers are displayed I would like to be able to navigate to an individual customer. I am having trouble making this work. The main concept is in the code below as well I have the expected model.
#for(int i = 0; i < customers.Length-1; i++)
{
<tr>
<td>#customer.Id</td>
<td>#customer.CustomerId</td>
<td>#customer.LastName</td>
<td>#customer.FirstName</td>
<td>#customer.Name1056Form</td>
<td>#customer.TrapezeClientId</td>
<td>#customer.CustomerNote</td>
<td #onclick="NavToCustomer(i)"> Details</td>
</tr>
private void NavToCustomer(int i)
{
int Id = i;
navigation.NavigateTo("/Customer/" + Id);
}
}

<td #onclick="()=>NavToCustomer(#customer.Id)"> Details</td>
private void NavToCustomer(int custID)
{
navigation.NavigateTo("/Customer/" + custID);
}
Explanation: the vanilla #onclick sends its own arguments (you can see what they are by hovering over "#onclick" in your markup). Your event handler doesn't handle MouseEventArgs, so the signatures don't match. You want to send custom info, so you should use the lambda expression instead.
--edit--
On second thought, can you just directly do this?
<td #onclick="()=>navigation.NavigateTo("/Customer/" + customer.Id)"> Details</td>

Related

ASP.NET Blazor uncheck all checkboxes in foreach loop with function

My Problem is that i have a list of checkboxes which are generated by a foreach loop.
How can i uncheck all the checkboxes with one function. Here is my code:
<tbody>
#foreach (var mandant in supportUserResult)
{
<tr>
<td><input type="checkbox" #onchange="eventArgs => { AddChosenSupportUserToList(mandant, eventArgs.Value); }" /></td>
<td>#(mandant.Scope)</td>
<td>#(mandant.Name)</td>
<td>#(usercategory)</td>
<td>#(mandant.FullName)</td>
<td>#(mandant.MailAddress)</td>
<td>#(mandant.Language)</td>
</tr>
}
</tbody>
I know how i can uncheck one with the #bind value, but ist not clear for me how to do that with all the generated checkboxes. And its important, that checkbox call the function 'AddChosenSupportUSerToList'.
What you're doing now is triggering an event when the checkbox is fired, without saving the state of your checkbox in your code.
You want to bind the actual state to a property. Once you've done so, you can then create a button to 'reset' each checkbox to the default state (this is how I interpret your desired behavior).
This post shows how to bind the state for one checkbox. For your purposes, you incorporate in your supportUserResult loop:
2 useful examples;
Blazor Checkbox two-way binding and change event
Blazor - Create select box dynamically
Using that example, you get something like this:
#for (int i = 0; i < supportUserResult.Count(); i++)
{
var mandant = supportUserResult[i];
<tr>
<td><input type="checkbox" #onchange="eventArgs => { ValueHasChanged(i, mandant, eventArgs.Value); }" /></td>
<td>#(mandant.Scope)</td>
<td>#(mandant.Name)</td>
<td>#(usercategory)</td>
<td>#(mandant.FullName)</td>
<td>#(mandant.MailAddress)</td>
<td>#(mandant.Language)</td>
</tr>
}
#code {
// this is your view model
var checkBoxValues = new List<bool>();
// this method will add a new item to the collection of select boxes
void ValueHasChanged(int i, Mandant mandant, eventArgs.Value )
{
if (eventArgs.Value) {
AddChosenSupportUserToList(mandant, eventArgs.Value)
}
checkBoxValues[i] = eventArgs.Value;
}
}
I'm not in a position to test the above for errors but this should help you.

Refresh html table data using Blazor and C#

I have a situation where I have a for loop that creates my html table from my datamodel which gets the data from SQL server express. I would like to know if it is possible to create a auto refresh method where the table data only gets refreshed and not the full page, if not then maybe a method that OnClick button will retrieve the latest data from datamodel and update the table accordingly.
I'm new to blazor and C# so any help would be appreciated, my current page structure currently looks as follows:
#page "/employees"
#using DataLib;
#inject IEmployeeData _db
#if (employees is null)
{
<p style="color:white;"><em>Loading . . .</em></p>
}
else
{
<table class="table" id="myTable">
<thead>
<tr>
<th>Entry Date</th>
<th>Employee</th>
</tr>
</thead>
<tbody>
#foreach (var employee in employees)
{
<tr>
<td>#employee.EntryDate</td>
<td>#employee.POI</td>
</tr>
}
</tbody>
</table>
}
#code{
private List<EmployeeModel> employees;
protected override async Task OnInitializedAsync()
{
employees = await _db.GetEmployee();
}
}
The above works perfect when I'm loading this page and when I do a manual refresh.
Is there a way that you guys can maybe assist me?
Thanks.
Not sure this is your aim butt you could try;
#inject IEmployeeData _db
#if (employees is null)
{
<p style="color:white;"><em>Loading . . .</em></p>
}
else
{
<table class="table" id="myTable">
<thead>
<tr>
<th>Entry Date</th>
<th>Employee</th>
</tr>
</thead>
<tbody>
#foreach (var employee in employees)
{
<tr>
<td>#employee.EntryDate</td>
<td>#employee.POI</td>
</tr>
}
</tbody>
</table>
<button #onclick="GetEmployees"> Refresh Employee List</button>
}
#code{
private List<EmployeeModel> employees;
protected override async Task OnInitializedAsync()
{
GetEmployees()
}
private async void GetEmployees()
{
employees.Clear();
employees = await _db.GetEmployee();
StateHasChanged();
}
Good luck,
You could create a SignalR hub on your server. Inject the hub into your api controllers, use it to signal clients that updates have occurred to the data from the API.
Mathias Z
I not understand why not this answer is not taken for good, but for me is all that i want, StateHasChanged(); because i still not use JavaScript.
public MyConstructor()
{
_My_collection_.CollectionChanged += Change_EventArgs;
}
void Change_EventArgs(object sender, EventArgs e)
{
StateHasChanged();
}
If your aim is just to refresh the data at regular interval then you can make use of Javascript Interop that is supported by Blazor. The set-up documentation is available in this link.
Like said by Mathias Z in this solution you would need a button for this to work.
I can see you have been writing both C# code and HTML in same file however I personally prefer keeping them separately. Coming back to the solution you can make use to JavaScript and c# to periodically refresh your displayable content.
Below are the changes you need to make to make it work.
Code-Behind
using Microsoft.JSInterop; // import this library
using this you can invoke JavaScript methods.
[Inject]
private IJSRuntime JSRuntime { get; set; }
OnAfterRenderAsync and OnAfterRender are called after a component has finished rendering. Element and component references are populated at this point. Use this stage to perform additional initialization steps using the rendered content, such as activating third-party JavaScript libraries that operate on the rendered DOM elements.
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await JSRuntime.InvokeVoidAsync("EmployeeInterop.refreshEmployeeData");
}
// This method will be called on button click.
protected async Task GetEmployees()
{
employees = await _db.GetEmployee();
}
wwwroot
Within this folder we generally keep our web-resources including js libraries. Here, create a javascript file e.g. EmployeeInterop.js and below code.
(function () {
window.EmployeeInterop = {
refreshEmployeeData: () => {
setInterval(() => {
document.getElementById("btnGetEmployeeData").click();
}, 3000);
}
};
})();
The setInterval() method calls a function or evaluates an expression at specified intervals (in milliseconds). You can define your own time of refresh.
_Host.cshtml
Register this script file here.
<script src="EmployeeInterop.js"></script>
EmployeeDetail.razor
<button id="btnGetEmployeeData" #onclick="GetEmployees"> Refresh Employee List</button>
Add this below your table tag. In-case you don't want this button to be visible to the end-user then add a style attribute and set it to display:none.

How to search in website and retrieve data using loop

Pardon me if my question title is not expressive ,but what I want to say is I have a simple tool that should search in a website and get the result which is 3 kinds of data (name,phone,address) I had written some codes for opening the website inside web browser tool and applied a loop statement to search for 30 numbers and it really works but the problem is it works for only one time and the second problem is in retrieving data from the other page which opens when the search button is clicked ,so suppose that I will start my sequential based number in search as 737000000 it should search for this number and opens the other page which contains the data and put these data in 3 text boxes finally back to previous page and search for 737000001 (adding 1 each time)
My codes are
private void searchBtn_Click(object sender, EventArgs e)
{
for (int i = 0; i < 30; i++)
{
string temp = string.Format("{0:D6}", i);
string formula = textBox1.Text + temp;
// Get all input elements
HtmlElementCollection inputs = webBrowser1.Document.GetElementsByTagName("input");
// Select "txtSearch" input
HtmlElement input = inputs["q"];
if (input != null)
{
string value = input.GetAttribute("VALUE");
if (!string.IsNullOrEmpty(value))
{
// Already searched but no results
}
else
{
// Input search text
string searchText = formula;
input.SetAttribute("VALUE", searchText);
var elements = webBrowser1.Document.GetElementsByTagName("button");
foreach (HtmlElement element in elements)
{
element.InvokeMember("click");
}
}
}
}
the data in the other page when I view the page source appears like
<table class="table table-responsive table-striped">
<thead>
<tr>
<th>name</th>
<th>number</th>
<th>address</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mat Adam</td>
<td><b class="text-success">737000000</b></td>
<td>New York</td>
</tr> </tbody>
</table>

Get HTML check box to toggle MVC model boolean

I am trying to use an MVC form to modify some information in my database. I want to be able to select a few items from a table using a series check boxes. It should update the database boolean values when I hit a link at the bottom of my form.
So far, I have tried a few solutions from other threads, but since I am new to MVCs, they are rather confusing.
This is what I have right now for my HTML:
#foreach (var item in Model)
{
<tr>
#if (!item.IsCurated)
{
<td>
#Html.CheckBoxFor(modelItem => item.isChecked, new { #checked = true })
</td>
{
</tr>
#Html.ActionLink("Update", "updateDatabase", Model)
The "updateDatabase" method calls
public void updateDatabase()
{
db.SaveChanges();
}
I believe the changes to the database are being saved, but that the check boxes are not actually assigning any changed values.

ASP.NET grid with auto-paging,sortable,searchable... GridView? ListView?

I need to build a <table> to display Products. I am not very familiar with GridView or ListView, not sure if they can do these below.
The requirements:
Automatic paging. Fetch only 100 records at a time (not the whole 1000000 records when it first loads)
Sortable. I need to be able to specify the default sort order, but user can also click on the header
Searchable. User needs to be able to filter the data they want to see.
I (the programmer) need to be able to easily turn off/on columns (Ideally I only need to comment out one line to hide a column)
Data will be from SQL Server, multiple tables
Does anyone know any ASP.NET control that can do all the above? Thanks in advance!
Both GridView and ListView can do paging if you put a DataPager in them. ListView is a templated control - the display is completely customised so you have to roll your own "columns"; don't have much use for GridView so I don't know about that one.
As for searching and sorting, there's some sort of builtin support for it that becomes useless if you need a data source ASP.NET can't query directly - an ObjectDataSource lets you create your own data access code, but you also have to implement everything that can't be done automatically.
For searching, you can handle the ODS's Selecting event, you can pass arbitrary parameters to the query method; I believe there's also some way to automagically get control values / query string parameters etc.
For sorting, ListView lets you add Buttons where CommandName="Sort" and CommandArgument="[column to sort by]". When using a non-custom data source, I believe they will Just Work. When using an ObjectDataSource, all they do is make the ListView keep track of a "sort expression" that you can pass into your data source in the ODS.Selecting event. The format of the sort expression is specified… somewhere I can never find when I need it. When using single-column sorting, this will be either "[column name]" for an ascending sort, or "[column name] DESC" for a descending one. You can pass this directly to ObjectQuery.OrderBy; EntityFramework.Extended also provides that extension method for the new API surface. ListView (I believe) only handles single column sorting, for multiple-column sorting you have to manage the sort expression yourself anyway.
The documentation for all this is scattered, a good starting point is this tutorial, its followups, and the links for ListView you can find in the sidebar to the left.
My project also has a reasonably simple use of a ListView in combination with an ObjectDataSource – meaning, no part of it relies on magic RAD features, that follows below. I extracted it from my actual project, so it might have minor inconsistencies.
ListView+ObjectDataSource Example
The following example retrieves "messages" (think news announcements on a company portal) from a WCF service (not included).
MessagesDataSource.cs
An ObjectDataSource delegate that calls a WCF service. The data source is responsible for:
filtering based on the username and type parameters
sorting based on the sort expression in the sort parameter
paging as specified by the skip and take parameters - named to be consistent with the LINQ operators
Because we're using an ObjectDataSource, all of this has be implemented in the delegate – this is where the service is ultimately called.
public enum MessageType
{
None = 0,
All,
General,
OfficeHoursUpdate,
// …
}
[DataObject]
public class MessagesDataSource : IDisposable
{
IMessagesService _svc = new MessagesServiceClient();
[DataObjectMethod(DataObjectMethodType.Select)]
public IEnumerable<Message> Select(string username, MessageType type, string sort, int skip, int take)
{
return _svc.GetMessages(username, type, sort, skip, take);
}
public int SelectCount(string username, MessageType type, string sort, int skip, int take)
{
return _svc.CountMessages(username, type);
}
}
Messages.ascx
Renders a list of messages as a table with one <tbody> per message, with one row split into columns for the message "headers", and a second row with all columns merged for the message body. Points to note:
When a value is selected in the dropdown list, the ListView is refreshed starting with the first page.
All the parameters the MessageDataSource.Select() and .SelectCount() methods take should be declared in the ODS's <SelectParameters>. (Visual Studio will show an error if they don't match.)
The TypeName attribute of the ObjectDataSource control indicates the ODS delegate that gets instantiated by the ODS. For more control over this, handle the ObjectCreating / ObjectCreated events of the ODS. (For instance, you can pass the containing control to the ODS delegate.)
The values for the parameters named by the StartRowIndexParameterName and MaximumRowsParameterName attributes will be provided automatically by the data pager.
I don't believe the value for the SortParameterName parameter is filled in by the ListView when using an ObjectDataSource - it might or might not be when using a GridView. I also don't think it's necessary in this case but then again it's not hurting anybody to keep it there.
I omitted the data pager fields, they're just clutter here.
The CommandArgument values of the sorting LinkButtons in the header don't have to match up the properties of the data objects and can in fact be completely arbitrary.
<asp:Label ID="lblType" runat="server" AssociatedControlID="ddlType" Text="Message Type:"/>
<asp:DropDownList runat="server" ID="ddlType" AutoPostBack="true"
OnSelectedIndexChanged="ddlType_SelectedIndexChanged"
OnLoad="ddlType_Load" />
<table>
<asp:ListView ID="lvMessages" runat="server" DataSourceID="dsMessages" ItemPlaceholderID="message">
<LayoutTemplate>
<thead>
<tr>
<th>
<asp:LinkButton runat="server" Text='Timestamp'
CommandName="Sort" CommandArgument="Timestamp" />
<asp:Literal ID="lvMessages__Timestamp" runat="server"
OnPreRender="UpdateSortIndicator" />
</th>
<th>
Sender
</th>
<th>
<asp:LinkButton runat="server" Text='Subject'
CommandName="Sort" CommandArgument="Subject" />
<asp:Literal ID="lvMessages__Subject" runat="server"
OnPreRender="UpdateSortIndicator" />
</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="3">
<asp:DataPager ID="dpMessages" runat="server"
PageSize="10" PagedControlID="lvMessages"
OnInit="dpMessages_Init">
<Fields>
<%-- Data Pager Fields --%>
</Fields>
</asp:DataPager>
</td>
</tr>
</tfoot>
<%--
The following tag gets replaced with the rendered contents of
ItemTemplate for each data item
--%>
<tbody runat="server" id="message" />
</LayoutTemplate>
<ItemTemplate>
<tbody>
<tr>
<td>
<%# Eval("Timestamp") %>
</td>
<td>
<%# Eval("Sender") %>
</td>
<td>
<%# Eval("Subject") %>
</td>
</tr>
<tr>
<td colspan="3">
<%# Eval("Body") %>
</td>
</tr>
</tbody>
</ItemTemplate>
<EmptyDataTemplate>
No messages loaded!
</EmptyDataTemplate>
</asp:ListView>
</table>
<asp:ObjectDataSource ID="dsMessages" runat="server" TypeName="Foo.MessagesDataSource"
DataObjectTypeName="Foo.Message" SelectMethod="Select"
SelectCountMethod="SelectCount" StartRowIndexParameterName="skip" MaximumRowsParameterName="take"
OnSelecting="dsMessages_Selecting" EnablePaging="true" SortParameterName="sort">
<SelectParameters>
<asp:Parameter Name="username" />
<asp:Parameter Name="scope" />
<asp:Parameter Name="sort" />
<asp:Parameter Name="skip" />
<asp:Parameter Name="take" />
</SelectParameters>
</asp:ObjectDataSource>
Messages.ascx.cs
This class is reasonably straightforward and deals mostly with initialising the page and tangential issues like sort indicators. Most of the "interesting" bits have had comments added to them.
public partial class Messages : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Initialise the dropdown list values
var types = Enum.GetValues(typeof(MessageType));
types.Remove(MessageType.None);
foreach (var t in types)
{
ddlType.Items.Add(new ListItem(t.ToString()));
}
// Default message filter and sort
Type = MessageType.All;
lvMessages.Sort("Timestamp", SortDirection.Descending);
}
}
private MessageType _type;
public MessageType Type
{
get { return _type; }
set
{
if (!_type.Equals(value))
{
ddlType.SelectedValue = value.ToString();
_type = value;
}
}
}
private static readonly IDictionary<SortDirection, string> SortIndicators =
new Dictionary<SortDirection, string>
{
{SortDirection.Ascending, "\u25b4"}, // upwards triangle
{SortDirection.Descending, "\u25be"} // downwards triangle
};
/// This is where you can programmatically add / change the values of
/// parameters that will get passed to MessagesDataSource.Select()
protected void dsMessages_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
// Add "filter" parameters that have to be determined programmatically.
e.InputParameters["username"] = GetUsernameLoggedIn();
e.InputParameters["type"] = Type;
}
/// When the message type changes, go back to the first page
protected void ddlType_SelectedIndexChanged(object sender, EventArgs e)
{
Type = (MessageType) ddlType.SelectedValue);
var pager = (DataPager)lvMessages.FindControl("dpMessages");
if (pager == null)
{
((IPageableItemContainer)lvMessages).SetPageProperties(0, 10, true);
}
else
{
pager.SetPageProperties(0, pager.PageSize, true);
}
}
/// Reload the value from the dropdown list.
protected void ddlType_Load(object sender, EventArgs e)
{
Type = (MessageType) ddlType.SelectedValue;
}
protected void UpdateSortIndicator(object sender, EventArgs e)
{
var indicator = (Literal) sender;
if (indicator.ID.EndsWith("__"+ lvMessages.SortExpression))
{
indicator.Text = SortIndicators[lvMessages.SortDirection];
}
else
{
indicator.Text = "";
}
}
}
Disclaimer: I don't claim to be an authority on the topic and am in fact fairly new to .NET. This just happens to be something I had to deal with recently and was also confused by the scattered documentation that tended to either take shortcuts with a part of the problem (i.e. either use GridView to get a complete view automatically, or use an ADO.NET data source instead of custom data access code); or spend too much space on fluff (e.g. screenshots of what button to click in which Visual Studio wizard.)
It's not free but Telerik's RadGrid is incredibly full-featured and either does 100% of what you need or else it will get you pretty darn close.
Telerik RadGrid: http://demos.telerik.com/aspnet-ajax/grid/examples/overview/defaultcs.aspx
if your data is going to be just displayed only not edited or updated you can go with a Data Repeater control. It is a very light weight control but then you may have write all the logic for the paging and sorting.It is good in a way so that you get fine grained control over your code..
Check this link for more details.ASP.net Repeater Control

Categories