Display item of instance - asp.net

I have made an instance of the type competition by retrieving data from my database.
The function selectCompetitionById return one row of data.
Competition competition = BLLc.selectCompetitionById(competitionId);
How can I display item of this instance on my page? (Repeater doesn't work)

If you want to create an auto-generated form, then you could use a DetailsView:
<asp:DetailsView ID="competitionDetails" RunAt="Server" AutoGenerateColumns="true" />
Create a dummy array (with just the one item) as the data source:
competitionDetails.DataSource = new Competition[] { competition };
The other way is to use standard HTML template that references your object. Make it a property of the page first:
<script runat="Server">
public Competition competition { get; set; }
void Page_Load()
{
competition = BLLc.selectCompetitionById(competitionId);;
this.DataBind();
}
</script>
Then reference it in markup as needed:
<div>
<span>Title</span>
</div>
<div>
<span><%# competition.Title %></span>
</div>
<div> etc ... </div>

Related

.Net 7 Quick Grid Filter Not Refreshing Properly

I have a grid with both Template and Property Columns (code below only showing a single column.) The grid seems to work as expected with sorting and filtering. However, I want a way to clear all filters. I know how I would do this and it is just clearing each of the variables tied to each of the filtered columns (like filterProjectName below.) So, I need to UI to display a button when there is at least 1 filter in place. I have code in the Filtered data property that determines if we have any filters and then totals them up. This always seems to be a step behind what is actual (the #CurrentFilters.Count below.) Despite the Console.WriteLine that shows the correct number when the property returns.
Here is my HTML:
<label class="ms-3">Filters: #CurrentFilters.Count</label>
<div class="fs-08">
<QuickGrid #ref="MyWorkGrid" Items="FilteredQuickProjects" ItemKey="#(p => p.ProjectId)" Pagination="QuickPagination" Class="table table-fixed table-sm table-bordered table-striped table-hover">
<TemplateColumn Title="Project Name" Class="project-name text-truncate" Sortable="true" SortBy="sortProjectName">
<ColumnOptions>
<div class="search-box">
<input type="search" class="form-control form-control-xs" autofocus #bind="filterProjectName" #bind:event="oninput" placeholder="Project Name..." />
</div>
</ColumnOptions>
<ChildContent>
<div class="d-flex justify-content-between align-items-start">
...
</div>
</ChildContent>
</TemplateColumn>
</QuickGrid>
<Paginator Value="QuickPagination" />
</div>
The code behind is:
public HashSet<string> CurrentFilters { get; set; } = new();
public QuickGrid<MyWorkViewModel> MyWorkGrid { get; set; }
public IQueryable<MyWorkViewModel> FilteredQuickProjects
{
get
{
if (!PageIsLoaded)
return MyQuickProjects;
CurrentFilters.Clear();
if (!string.IsNullOrWhiteSpace(filterProjectName))
{
result = result.Where(x => x.Name.Contains(filterProjectName, StringComparison.InvariantCultureIgnoreCase));
CurrentFilters.Add("ProjectName");
}
System.Console.WriteLine($"Total Filters: {CurrentFilters.Count}");
return result;
}
}
I put StateHasChanged() at the end of the FilteredQuickProjects and that had created an endless loop.
I am not sure what to do here.

Return Different Views From MVC Controller

I've a MVC application, whose SharedLayout view(Master Page) gives user capability to search. They could search their order by Order No or By Bill no. So there are two option buttons the Shared View along with the textbox. Code is somewhat like this
#using (Html.BeginForm("Track", "Tracking", FormMethod.Post))
{
<div style="text-align: center">
<textarea cols="20" id="txtNo" name="txtOrderNo" rows="2" ></textarea>
</div>
<div style="text-align: center">
<input type="radio" name="optOrderNo" checked="checked" value="tracking" />Order No <input type="radio" name="optRefNo" value="tracking" />Ref No
</div>
<div style="text-align: center">
<input type="submit" value="Track" />
</div>
}
So it'll go to TrackingController and Track Method in it and return the view. It works fine for a single search as a View is associated with a controller's methods. It works fine but how could i conditionally return the other view based on the radio button selection.
What i come up with is this
[HttpPost]
public ActionResult Track(FormCollection form)
{
string refNo = null;
if (form["optRefNo"] == null)
{
string OrderNo = form["txtOrderNo"];
var manager = new TrackingManager();
var a = manager.ConsignmentTracking(OrderNo);
var model = new TrackingModel();
if (OrderNo != null)
model.SetModelForConsNo(a, consNo);
return View(model);
}
refNo = form["txtConsNo"];
return TrackByRef(refNo);
}
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View();
}
Kindly guide.
Thanks
View has an overload where the first parameter is a string. This is the name (or path) to the view you want to use, rather than the default (which is a view that matches the action's name).
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View("Track");
// or, if you want to supply a model to Track:
// return View("Track", myModel);
}

ASP.NET MVC Shopping Cart & jQuery

I have a pricing page which display a list of products along with their prices. User can choose to add multiple products to shopping cart (active shopping cart is being shown on right hand side of page). Currently this is how I have implemented it using Ajax/Jquery...
Code snippet from my view (ASPX): Looping thro available products in ViewModel and displaying details:
<% foreach (var _product in _supplier.HotelProducts)
{ %>
<tr>
<td colspan="2" align="left" valign="top"><% = _product.Description %></td>
<td align="left">
<% using (Html.BeginForm("AddToCart", "ShoppingCart", FormMethod.Post, new { #class = "addProductToCartForm" }))
{ %>
<input type="hidden" name="hSupplierID" id="hSupplierID" value="<% = _supplier.ID %>" />
<input type="hidden" name="hProductCode" id="hProductCode" value="<% = _product.Code %>" />
<input type="hidden" name="hProductDescription" id="hProductDescription" value="<% = _product.Description %>" />
<input type="hidden" name="hProductPrice" id="hProductPrice" value="<% = _product.TotalPrice %>" />
<input type="submit" value="+ Add to cart" />
<% } %>
</td>
<td valign="top" align="center">
<span id="spanProductPrice" class="_price">$<% = _product.TotalPrice %></span>
</td>
</tr>
<% } %>
As you can see from above code snippet, I have "+ Add to cart" button againts each product and my requirement is to pass SupplierID and Product details (Code, Desc & Price) to my Controller and Cart. Please note that I get list of Products & their pricing from an external webservice and there is no way for me to just pass the Product Code and retrieve corresponding description & price on server side, that's why I need to capture required product details when user adds it to cart.
$(function () {
$(".addProductToCartForm").submit(function (e) {
e.preventDefault();
var HiddenCartForm = {
SupplierID: $(this.hSupplierID).val(),
Code: $(this.hProductCode).val(),
Description: $(this.hProductDescription).val(),
TotalPrice: $(this.hProductPrice).val()
};
$.post($(this).attr("action"), HiddenCartForm, function (data) {
//alert("Success");
renderCart(data);
});
return false; // form already submitted using ajax, don't submit it again the regular way
});
});
function renderCart(data) {
$("#rightColumn").html(data);
}
Here is my custom HiddenCartForm object which I use to pass information from View to Controller via JQuery
public class HiddenCartForm
{
public string SupplierID { get; set; }
public string Code { get; set; }
public string Description { get; set; }
public decimal? TotalPrice { get; set; }
//public ProductView Product { get; set; }
}
I have TWO questions:
[1] Is there a better way to handle this scenario? I am little uncomfortable with so many forms & hidden fields (for holding SupplierID & Product Details) on the View. These forms & hidden fields will be visible when someone does view source.
[2] I need pretty much all of the information from "_product" when user adds a particular product to shopping cart. Is there a better way to pass this information via JQuery instead of using hidden fields as I am looping thro the products foreach (var _product in _supplier.HotelProducts) in my view?
I am on MVC 2 currently.
Why do you need to pass the product's description and price in your form post? Couldn't the controller action that handles the AJAX post look those values up from the database? Depending on how model is defined, supplier ID might also be removed for similar reasons.

Custom ViewModel with MVC 2 Strongly Typed HTML Helpers return null object on Create?

I am having a trouble while trying to create an entity with a custom view modeled create form. Below is my custom view model for Category Creation form.
public class CategoryFormViewModel
{
public CategoryFormViewModel(Category category, string actionTitle)
{
Category = category;
ActionTitle = actionTitle;
}
public Category Category { get; private set; }
public string ActionTitle { get; private set; }
}
and this is my user control where the UI is
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CategoryFormViewModel>" %>
<h2>
<span><%= Html.Encode(Model.ActionTitle) %></span>
</h2>
<%=Html.ValidationSummary() %>
<% using (Html.BeginForm()) {%>
<p>
<span class="bold block">Başlık:</span>
<%=Html.TextBoxFor(model => Model.Category.Title, new { #class = "width80 txt-base" })%>
</p>
<p>
<span class="bold block">Sıra Numarası:</span>
<%=Html.TextBoxFor(model => Model.Category.OrderNo, new { #class = "width10 txt-base" })%>
</p>
<p>
<input type="submit" class="btn-admin cursorPointer" value="Save" />
</p>
<% } %>
When i click on save button, it doesnt bind the category for me because of i am using custom view model and strongly typed html helpers like that
<%=Html.TextBoxFor(model => Model.Category.OrderNo) %>
My html source looks like this
<form action="/Admin/Categories/Create" method="post">
<p>
<span class="bold block">Başlık:</span>
<input class="width80 txt-base" id="Category_Title" name="Category.Title" type="text" value="" />
</p>
<p>
<span class="bold block">Sıra Numarası:</span>
<input class="width10 txt-base" id="Category_OrderNo" name="Category.OrderNo" type="text" value="" />
</p>
<p>
<input type="submit" class="btn-admin cursorPointer" value="Kaydet" />
</p>
</form>
How can i fix this?
Your View Model needs a default constructor without parameters and you need public set methods for each of the properties. The default model binder uses the public setters to populate the object.
The default model binder has some rules it follows. It chooses what data to bind to in the following order:
Form parameters from a post
Url route data defined by your route definitions in global.asax.cs
Query string parameters
The default model binder then uses several strategies to bind to models/parameters in your action methods:
Exact name matches
Matches with prefix.name where prefix is the parent class and name is the subclass/property
Name without prefix (as long as there are no collisions you don't have to worry about providing the prefix)
You can override the behavior with several options from the Bind attribute. These include:
[Bind(Prefix = "someprefix")] -- Forces a map to a specific parent class identified by the prefix.
[Bind(Include = "val1, val2")] -- Whitelist of names to bind to
[Bind(Exclude = "val1, val2")] -- Names to exclude from default behavior
You could use editor templates. Put your ascx control in ~/Views/Shared/EditorTemplates/SomeControl.ascx. Then inside your main View (aspx page) include the template like so (assuming your view is strongly typed to CategoryFormViewModel):
<%= Html.EditorForModel("SomeControl") %>
instead of
<% Html.RenderPartial("SomeControl", Model) %>
Make a default constructor for your viewmodel and initialize the Category there
public CategoryFormViewModel()
{
Category = new Category()
}
And at your controller action receive the viewmodel
public ActionResult ActionName(CategoryFormViewModel model)
{
//here you can access model.Category.Title
}

ASP.NET: User control with access to the controls that it wraps

I have a bunch of occurrences of this kind of boilerplate code in my ASP.NET project.
<div class="inputfield">
<div class="tl">
<span class="tr"><!-- --></span>
<span class="ll"><!-- --></span>
<div class="lr">
<div class="cntnt">
<asp:TextBox .../>
</div>
</div>
</div>
</div>
As you may have guessed, everything in that snippet is pure boilerplate except for the innermost text field.
What is the best way to avoid such boilerplate in ASP.NET? In e.g. Django I would make a custom tag for it, as such:
{% boiler %}
<input ... />
{% endboiler %}
I was thinking that maybe I can create a user control, but all the tutorials on ASP.NET user controls that I've found are very simplistic and "self-closing", i.e. they are not aware of the contents of the tag. I need something along the lines of:
<Hello:MyControl>
<asp:TextBox .../>
</Hello>
So my question is the following: what's the best way to avoid the boilerplate?
You can use an ITemplate property. Thus, you can inject different content in different situations.
[PersistChildren(false), ParseChildren(true, "ContentTemplate")]
public partial class WebUserControl1 : System.Web.UI.UserControl
{
[System.ComponentModel.Browsable(false), System.Web.UI.PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate ContentTemplate { get; set; }
protected override void CreateChildControls()
{
if (this.ContentTemplate != null)
this.ContentTemplate.InstantiateIn(this);
base.CreateChildControls();
}
}
Put the asp:TextBox in your user control, along with the other html tags. Provide properties on your user control that match the properties of the text box, so that you would do something like this:
<Hello:MyControl ID="myControl" runat="server" Width="300px" MaxLength="30" />
and then the width and maxlength properties would just get transferred to the internal textbox.
You could also provide access to the textbox from the usercontrol and set all the properties in the code behind.
Create a class like this:
[PersistChildren(false), ParseChildren(true, "ContentTemplate")]
public class CustomContent:WebControl
{
[System.ComponentModel.Browsable(false), System.Web.UI.PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public ITemplate ContentTemplate { get; set; }
private PlaceHolder m_placeHolder;
protected override void CreateChildControls()
{
m_placeHolder = new PlaceHolder();
if (this.ContentTemplate != null)
this.ContentTemplate.InstantiateIn(m_placeHolder);
Controls.Add(m_placeHolder);
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write(#"<div class=""inputfield"">
<div class=""tl"">
<span class=""tr""><!-- --></span>
<span class=""ll""><!-- --></span>
<div class=""lr"">
<div class=""cntnt"">
");
base.RenderContents(writer);
writer.Write(#" </div>
</div>
</div>
</div>
");
}
}
This class isn't a "User Control" it's a "Server Control". You can do the same thing with a user control but you'll have issues with the designer. This will work in the designer.
And you can put markup like this in your ASPX:
<uc1:CustomContent runat="server" ID="content">
<asp:textbox runat="server"></asp:textbox>
</uc1:CustomContent>
don't forget the Register page declaration at the top of the aspx
<%# Register tagprefix="uc1" Assembly="Assembly where CustomContent is" Namespace="namespace where CustomContent is" %>
You can put whatever you want inside the uc1:CustomContent tags and it will render that boilerplate html around it. If you are curious about how ITemplate works, there are plenty of articles on msdn, etc.

Resources