Hi I'm trying to use DotNet HighCharts to create a simple chart to display my ticket sales data in my C# asp.net MVC site.
I wish to create a bar/column chart which will show how many tickets in total were available for the event and how many are remaining. I had planned to pass the chart to the view and display it. However my chart is not rendered in my view and I cannot find a reason why it won't display, any help would be greatly appreciated!
This is my controller method
[Authorize(Roles = "canEdit")]
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest)
}
Event events = db.Events.Find(id);
if (events == null)
{
return HttpNotFound();
}
Highcharts chart = new Highcharts("chart")
.SetCredits(new Credits { Enabled = false })
.InitChart(new Chart { DefaultSeriesType = ChartTypes.Column })
.SetTitle(new Title { Text = "Ticket Sales" })
.SetXAxis(new XAxis { Categories = new[] { "Total Tickets", "Tickets Remaining"} })
.SetYAxis(new YAxis
{
Min = 0,
Title = new YAxisTitle { Text = "Quantity" }
})
.SetTooltip(new Tooltip { Formatter = "function() { return ''+ this.series.name +': '+ this.y +''; }" })
.SetPlotOptions(new PlotOptions { Bar = new PlotOptionsBar { Stacking = Stackings.Normal } })
.SetSeries(new[]
{
new Series { Name = "Total", Data = new Data(new object[] { events.TicketsAvailable, events.TicketsRemaining }) }
});
return View(chart);
}
And this is my view
#model DotNet.Highcharts.Highcharts
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<head>
<script src="~/Scripts/jquery-2.1.3.min.js"></script>
<script src="~/Scripts/Highcharts-4.0.1/js/highcharts.js"></script>
<title>Event Title</title>
</head>
<body>
<p>Chart Displaying Ticket Sales </p>
<div>#(Model)</div>
<div>
#Html.ActionLink("Back to List", "Index", "EventsAdmin")
</div>
</body>
I think the issue is that your js files are not loading.
<script src="~/Scripts/jquery-2.1.3.min.js"></script>
<script src="~/Scripts/Highcharts-4.0.1/js/highcharts.js"></script>
I tried the following code and it worked for me. You can modify the code as per your requirements.
View:
#model DotNet.Highcharts.Highcharts
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script src="http://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.jquery.com/jquery-1.12.1.min.js" integrity="sha256-I1nTg78tSrZev3kjvfdM5A5Ak/blglGzlaZANLPDl3I=" crossorigin="anonymous"></script>
<head>
<title>Event Title</title>
</head>
<body>
<p>Chart Displaying Ticket Sales </p>
<div>#(Model)</div>
</body>
Controller:
public ActionResult Index()
{
object[] desktops = new object[] {17368, 17792, 18235, 18136 };
var monthsList = new[] { "Feb-15", "Mar-15", "Apr-15", "May-15",};
Highcharts chart = new Highcharts("chart")
.SetCredits(new Credits { Enabled = false })
.InitChart(new Chart { DefaultSeriesType = ChartTypes.Column , Height = 190, Width=190})
.SetTitle(new Title { Text = "Ticket Sales" })
.SetXAxis(new XAxis { Categories = monthsList, Labels = new XAxisLabels() { } })
.SetYAxis(new YAxis
{
Min = 0,
Title = new YAxisTitle { Text = "Quantity" }
})
.SetTooltip(new Tooltip { Formatter = "function() { return ''+ this.series.name +': '+ this.y +''; }" })
.SetPlotOptions(new PlotOptions { Column = new PlotOptionsColumn{ Color = System.Drawing.Color.Black } })
.SetSeries(new[]
{
new Series { Name = "Total", Data = new Data(desktops) }
});
return View(chart);
}
If you still face issues, look into your browser's debug console if there are any javascript issues.
Related
I need help to get a solution to a question. The case is as follows:
We are working on a group project with asp.net, c #, javascript, html and razor technologies.
The structure of projects within the solution is as follows:
1.POJO-entities: where the models are located.
2.DataAccess: it is divided into three folders: 1. Crud (where are the classes that contain the "crudfactory" of each Pojo, 2. Dao (find the connection to the database, in this case SQL Server) and finally, the Mapper
3.CoreApi, where are the managers of each well.
4.WebApi, where are the controllers of each well.
5.WepApp, where is the UI (cshtmls) and javascripts.
Now, I have to implement a virtual wallet that can be topped up via PayPal and I have a method that receives the price and the description of the payment, for now it is "burned", but it must be parameterizable. I want to know if I can take the value of CtrlInput and put it in the HTMLAtributes of my ActionLink.
The idea may remove the # Html.ActionLink and leave the functionality in the "Update", but I don't know how to send the parameters from the view JS to the PayPal controller.
This is the javascript code for the wallet view:
function vMonedero() {
//this.tblMonederoId = 'tblMonedero';
this.service = 'monedero';
this.ctrlActions = new ControlActions();
this.columns = "IdUsuario, IdMonedero, Monto";
this.paypal = new PaymentWithPayPal();
this.RetrieveAll = function () {
this.ctrlActions.FillTable(this.service, this.tblMonedero, false);
}
this.Create = function () {
var monederoData = {};
monederoData = this.ctrlActions.GetDataForm('frmEdition');
if (monederoData["Monto"] == "") {
this.ctrlActions.ShowMessage('E', "Favor ingresar el nuevo valor");
}
else if (isNaN(monederoData["Monto"])) {
this.ctrlActions.ShowMessage('E', "Favor ingresar un valor numérico");
}
else {
this.ctrlActions.PostToAPI(this.service, monederoData);
}
}
this.Update = function () {
var monederoData = {};
monederoData = this.ctrlActions.GetDataForm('frmEdition');
price = monederoData["Monto"];
paypal.PaymentWithPayPal(price, "Recarga de monedero");
//Hace el post al create
this.ctrlActions.PutToAPI(this.service, monederoData);
//Refresca la tabla
}
this.Delete = function () {
var monederoData = {};
monederoData = this.ctrlActions.GetDataForm('frmEdition');
//Hace el post al create
this.ctrlActions.DeleteToAPI(this.service, monederoData);
//Refresca la tabla
}
this.BindFields = function (data) {
this.ctrlActions.BindFields('frmEdition', data);
}
}
//ON DOCUMENT READY
$(document).ready(function () {
var vmonedero = new vMonedero();
//vmonedero.RetrieveAll();
});
This is the view code:
#using WebApp.Helpers;
<script src="~/Scripts/Views/vMonedero.js"></script>
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="card border-secondary" style="margin-top: 50px;">
<div class="card-header">
<div class="row pull-right">
<div class="col-md-8">Monedero</div>
<div class="col-md-4">
#Html.CtrlButton(viewName: "vMonedero", id: "btnCreate", label: "Crear", onClickFunction: "Create", buttonType: "success")
#Html.CtrlButton(viewName: "vMonedero", id: "btnUpdate", label: "Recargar", onClickFunction: "Update", buttonType: "info")
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-lg-6">
<div class="bs-component">
<form id="frmEdition">
#Html.CtrlInput(id: "txtIdUsuario", type: "text", label: "N° de identificación", columnDataName: "IdUsuario")
#Html.CtrlInput(id: "txtIdMonedero", type: "text", label: "N° de monedero", columnDataName: "IdMonedero")
#Html.CtrlInput(id: "txtIdMonto", type: "text", label: "Monto", columnDataName: "Monto")
#* #Html.CtrlDropDown(id: "drpGender", label: "Gender", listId: "LST_GENERO")*#
</form>
</div>
</div>
</div>
</div>
</div>
#*<script>
$('#price').click(function () {
var monederoData = {};
ctrlActions = new ControlActions();
ctrlActions.GetDataForm('frmEdition');
monederoData["Monto"] = price;
return price;
});
</script>*#
Paypal Controller Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PaymentPayPal.Models;
using PayPal.Api;
namespace WebApp.Controllers
{
public class PayPalController : Controller
{
// GET: PayPal
public ActionResult Index()
{
return View();
}
public ActionResult PaymentWithPaypal(string price, string product)
{
//getting the apiContext as earlier
APIContext apiContext = ConfigurationPayPal.GetAPIContext();
try
{
string payerId = Request.Params["PayerID"];
if (string.IsNullOrEmpty(payerId))
{
string baseURI = Request.Url.Scheme + "://" + Request.Url.Authority +
"/Paypal/PaymentWithPayPal?";
var guid = Convert.ToString((new Random()).Next(100000));
var createdPayment = this.CreatePayment(apiContext, baseURI + "guid=" + guid, price, product);
var links = createdPayment.links.GetEnumerator();
string paypalRedirectUrl = null;
while (links.MoveNext())
{
Links lnk = links.Current;
if (lnk.rel.ToLower().Trim().Equals("approval_url"))
{
paypalRedirectUrl = lnk.href;
}
}
Session.Add(guid, createdPayment.id);
Console.WriteLine(createdPayment.id);
return Redirect(paypalRedirectUrl);
}
else
{
var guid = Request.Params["guid"];
Console.WriteLine("Session:" + Session[guid] as string);
var executedPayment = ExecutePayment(apiContext, payerId, Session[guid] as string);
if (executedPayment.state.ToLower() != "approved")
{
return View("FailureView");
}
}
}
catch (Exception ex)
{
return View("FailureView");
}
return View("SuccessView");
}
private PayPal.Api.Payment payment;
private Payment ExecutePayment(APIContext apiContext, string payerId, string paymentId)
{
var paymentExecution = new PaymentExecution() { payer_id = payerId };
this.payment = new Payment() { id = paymentId };
return this.payment.Execute(apiContext, paymentExecution);
}
private Payment CreatePayment(APIContext apiContext, string redirectUrl, string price, string product)
{
var itemList = new ItemList() { items = new List<Item>() };
itemList.items.Add(new Item()
{
name = product,
currency = "USD",
price = price,
quantity = "1",
sku = "sku"
});
var payer = new Payer() { payment_method = "paypal" };
var redirUrls = new RedirectUrls()
{
cancel_url = redirectUrl,
return_url = redirectUrl
};
// similar as we did for credit card, do here and create details object
var details = new Details()
{
tax = "1",
shipping = "1",
subtotal = price
};
// similar as we did for credit card, do here and create amount object
var amount = new Amount()
{
currency = "USD",
total = "" + (int.Parse(price) + 1 + 1), // Total must be equal to sum of shipping, tax and subtotal.
details = details
};
var transactionList = new List<Transaction>();
transactionList.Add(new Transaction()
{
description = "Transaction description.",
invoice_number = Convert.ToString((new Random()).Next(100000)),
amount = amount,
item_list = itemList
});
this.payment = new Payment()
{
intent = "sale",
payer = payer,
transactions = transactionList,
redirect_urls = redirUrls
};
// Create a payment using a APIContext
return this.payment.Create(apiContext);
}
}
}
I have a requirement where I need to display a Modal popup. When the user clicks on the link inside a grid, then that has to open a modal popup with the respective values. But currently it is taking me to a new page instead of displaying it as a modal popup in the same page. Can someone have a look at this an tell me what is going wrong?
Popup is being called here:
grid.AddColumn("ProductName", "Product",
format: (item) =>
{
return Warehouse.Helpers.HtmlHelpers.DialogFormLink2(Html, item.ProductName, #Url.Content("~/Service/ProductCategory/ProductTransactionsPopupView?ProductID=" + #item.ProductID + "&ProgramID=" + Model.ProgramID + "&Status=" + item.ProductStatus + "&ProductRequestID=" + ViewBag.ProductRequestID), null, "Product History", "dialog", "", #Url.Action("ProductProfile"));
});
Controller:
public ActionResult ProductTransactionsPopupView(int ProductID, string ProductStatus, int? ProductRequestID = null)
{
var Program = GetProgram();
var mdl = new ProductTransactionsViewModel { ProgramID = Program.ProgramID, ProductID = ProductID };
try
{
var ProductTransactionResponse = _ServiceProduct.GetProductTransactions(Program.ProgramID, User.Name, ProductID);
mdl.ProductID = ProductTransactionResponse.ProductId;
mdl.Transactions = ProductTransactionResponse.ProductTransactions.ToList();
mdl.ProductName = ProductTransactionResponse.Product != null ? ProductTransactionResponse.Product.ProductName : "";
mdl.ProductStatus = ProductStatus;
}
catch (Exception ex)
{
mdl.ErrorMessage = "An error occured.";
}
ViewBag.ProductRequestID = ProductRequestID;
return View("ProductTransactions", mdl);
}
Model View:
#model Warehouse.Product.ProductTransactionsViewModel
#using Warehouse.Helpers;
#{
ViewBag.Title = "Product Transactions";
ViewBag.ProgramID = Model.ProgramID;
ViewBag.ProductName = Model.ProductName;
ViewBag.ProductID = Model.ProductID;
Layout = "~/Views/Shared/_PRPopupsLayout.cshtml";
var PRID = (int?)ViewBag.ProductRequestID;
}
<div class="DisplayMessage">
</div>
<div class="popupContentContainer">
#Html.Partial("_ProductTransactions")
</div>
<div style="text-align:center">
#if(Model.ProductStatus == "Active")
{
<input type="button" value="Generate Product Document" id="ProductInquiry" name="ProductInquiry" class="grey button" />
}
<input type="button" value="Exit" id="exit" name="exit" class="grey button" />
</div>
I have following view and controller. Problem is that when enabling paging and I click on next page, previous view is gone
#using System
#using System.Web.Helpers
#*#model List<DataTransferObjects.UserClaimHistory>*#
<!DOCTYPE html>
<html lang="en">
<head runat="server">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="~/Content/style.css" rel="stylesheet" type="text/css" />
#*<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>*#
<script src="~/Scripts/jquery-1.7.1.js"></script>
<style>
/*Here I will write some css for looks good*/
th, td {
padding: 5px;
}
th {
background-color: gray;
}
</style>
</head>
#{
ViewBag.Title = "ViewReports";
var grid = new WebGrid(Model, canPage: false, rowsPerPage: 2, selectionFieldName: "selectedRow", ajaxUpdateContainerId: "gridContent", canSort: false);
}
#{
var fromDateVal = (DateTime)ViewBag.fromDate;
var toDateVal = (DateTime)ViewBag.toDate;
}
#using (Html.BeginForm("Index", "ViewReport", FormMethod.Post))
{
<div class="container">
#{
var homeHeader = Html.Partial("_HomeHeader");
}
#homeHeader
<div id="logout-div">
#Html.ActionLink("Log Out", "Logout", "Home", null, null )
</div>
#{
var homeLeftPanel = Html.Partial("_HomeLeftPanel");
}
#homeLeftPanel
<div>
From Date: #Html.TextBox("fromDate", string.Format("{0:yyyy-MM-dd}", fromDateVal), new { #id = "fromDate", #class = "datefield", type = "date" })
To Date: #Html.TextBox("toDate", string.Format("{0:yyyy-MM-dd}", toDateVal), new { #id = "toDate", #class = "datefield", type = "date" })
<input type="submit" value="Search" />
</div>
<div id="main" style="padding: 25px;">
#grid.GetHtml(
htmlAttributes: new { id = "MainGrid", width = "60%" },
tableStyle: "table table-bordered table-responsive",
headerStyle: "header",
alternatingRowStyle: "alt",
selectedRowStyle: "select",
columns: grid.Columns(
grid.Column("UserName", "User Name"),
grid.Column("Email", "Email"),
grid.Column("Claim", "Accessed"),
grid.Column(header: "AccessedOn", format: (item) => string.Format("{0:dd-MM-yyyy}", item.AccessedOn)),
grid.Column(format: (item) =>
{
if (item.Count > 1)
{
var subGrid = new WebGrid(source: item.List, canSort: false);
return subGrid.GetHtml(displayHeader: true,
htmlAttributes: new { id = "SubGrid", width = "100%" },
columns: subGrid.Columns(
subGrid.Column("UserName", "User Name"),
subGrid.Column("Email", "Email"),
subGrid.Column("Claim", "Accessed"),
subGrid.Column("AccessedOn", "AccessedOn")
)
);
}
else
{
return null;
}
})
)
)
<script>
$(document).ready(function () {
var size = $("#main #MainGrid > thead > tr > th").size(); // get total column
$("#main #MainGrid > thead > tr > th").last().remove(); // remove last column
$("#main #MainGrid > thead > tr").prepend("<th></th>"); // add one column at first for collapsible column
$("#main #MainGrid > tbody > tr").each(function (i, el) {
$(this).prepend(
$("<td></td>")
.addClass("expand")
.addClass("hoverEff")
.attr('title', "click for show/hide")
);
//Now get sub table from last column and add this to the next new added row
var table = $("table", this).parent().html();
//
// alert(table);
//add new row with this subtable
// ADD CLICK EVENT FOR MAKE COLLAPSIBLE
if (table !== null) {
$(this).after("<tr><td></td><td style='padding:5px; margin:0px;' colspan='" + (size - 1) + "'>" + table + "</td></tr>");
$("table", this).parent().remove();
$(".hoverEff", this).live("click", function () {
$(this).parent().closest("tr").next().slideToggle(100);
$(this).toggleClass("expand collapse");
});
} else {
$(this).find('td:eq(0)').removeClass();
}
});
//by default make all subgrid in collapse mode
$("#main #MainGrid > tbody > tr td.expand").each(function (i, el) {
$(this).toggleClass("expand collapse");
$(this).parent().closest("tr").next().slideToggle(100);
});
});
</script>
</div>
#if (ViewBag.Count > 0)
{
<div>
#Html.ActionLink("Export", "ExportToExcel", "ViewReport", new { fromDate = fromDateVal, toDate = toDateVal}, null)
</div>
}
#{
var homeFooter = Html.Partial("_HomeFooter");
}
#homeFooter
</div>
}
</html>
And this is the controller:
public ActionResult Index(DateTime? fromDate, DateTime? toDate)
{
if (!fromDate.HasValue)
fromDate = DateTime.Now.Date;
if (!toDate.HasValue)
toDate = fromDate.GetValueOrDefault(DateTime.Now.Date).Date.AddDays(1);
if (toDate < fromDate)
toDate = fromDate.GetValueOrDefault(DateTime.Now.Date).Date.AddDays(1);
ViewBag.fromDate = fromDate;
ViewBag.toDate = toDate;
var userClaims = DbAccessWebApiHandler.GetUserClaimAccesshistory(new DateSelection
{
StartDate = fromDate.Value,
EndDate = toDate.Value
});
if (userClaims != null)
{
ViewBag.Count = userClaims.Count;
var newList = userClaims.GroupBy(x => new { x.UserName, x.Email, x.Claim, x.AccessedOn.Date })
.Select(y => new UserClaimHistoryGroup
{
UserName = y.Key.UserName,
Email = y.Key.Email,
Claim = y.Key.Claim,
AccessedOn = y.Key.Date,
List = y.ToList(),
Count = y.ToList().Count
});
return View(newList);
}
userClaims = new List<UserClaimHistory>();
return View(userClaims);
}
[System.Web.Mvc.HttpGet]
public ActionResult ExportToExcel(DateTime? fromDate, DateTime? toDate)
{
if (!fromDate.HasValue)
fromDate = DateTime.Now.Date;
if (!toDate.HasValue)
toDate = fromDate.GetValueOrDefault(DateTime.Now.Date).Date.AddDays(1);
if (toDate < fromDate)
toDate = fromDate.GetValueOrDefault(DateTime.Now.Date).Date.AddDays(1);
ViewBag.fromDate = fromDate;
ViewBag.toDate = toDate;
var userClaims = DbAccessWebApiHandler.GetUserClaimAccesshistory(new DateSelection
{
StartDate = fromDate.Value,
EndDate = toDate.Value
});
if (userClaims != null)
{
var gv = new GridView();
gv.AutoGenerateColumns = false;
gv.Columns.Add(new BoundField { HeaderText = "UserName", DataField = "UserName" });
gv.Columns.Add(new BoundField { HeaderText = "Email", DataField = "Email" });
gv.Columns.Add(new BoundField { HeaderText = "Accessed", DataField = "Claim" });
gv.Columns.Add(new BoundField { HeaderText = "Date", DataField = "AccessedOn" });
var dt = new DataTable();
dt.Columns.Add("UserName");
dt.Columns.Add("Email");
dt.Columns.Add("Claim");
dt.Columns.Add("AccessedOn");
foreach (var item in userClaims)
{
dt.Rows.Add(item.UserName, item.Email, item.Claim, item.AccessedOn);
}
gv.DataSource = dt;
gv.DataBind();
for (var i = 0; i < userClaims.Count; i++)
{
gv.Rows[i].Height = 40;
}
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=Reports.xls");
Response.ContentType = "application/ms-excel";
Response.Charset = "";
var sw = new StringWriter();
var htw = new HtmlTextWriter(sw);
gv.RenderControl(htw);
Response.Output.Write(sw.ToString());
Response.Flush();
Response.End();
}
return View("Index");
}
Have able to work via following script
var links = $('a[href*=page], a[href*=sort]'), form = $('form');
links.click(function () {
form.attr("action", this.href);
$(this).attr("href","javascript:");
form.submit();
});
as mentioned in How do I get my WebGrid to POST instead of GET during a sort or paging operation in my MVC4 site?
Is it possible to refresh a #Html.DropDownList based on value from an input field on the same form?
For example, I have a field #Html.TextBoxFor(m => m.CustomerFunds) to which a value such as 50 would be entered, as soon as the user exits the field such as TAB for example, a function would be initiated to populate the DropDownList.
HomeController.cs
public ViewResult Index()
{
var productList = new List<WebApplication1.Product>
{
new WebApplication1.Product{ProductName = "Please select a Product", ProductId = 0}
};
productList.AddRange(_repository.GetAllProducts());
ViewBag.ProductList = new SelectList(productList, "ProductId", "ProductName", null);
return View();
}
public SelectList GetProducts(int customerFunds)
{
var productList = new List<WebApplication1.Product>
{
new WebApplication1.Product {ProductName = "Please select a Product", ProductId = 0}
};
productList.AddRange(_repository.GetProducts(customerFunds));
return new SelectList(productList, "ProductId", "ProductName", null);
}
Index.cshtml
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { role = "form" }))
{
#Html.TextBoxFor(m => m.CustomerFunds)
#Html.DropDownList("ProductId", ViewBag.ProductList as SelectList)
}
Updated
I have changed the function GetProducts as follows:
public ActionResult GetProducts(decimal customerFunds)
{
var products = _repository.GetProducts(customerFunds).Select(p => new { p.ProductId, p.ProductName }).OrderBy(p => p.ProductName);
return Json(products, JsonRequestBehavior.AllowGet);
}
The Index.cshtml is now as follows:
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { role = "form" }))
{
#Html.TextBoxFor(m => m.CustomerFunds)
<select id="ProductId">
<option value="0">Please select a Product</option>
</select>
}
<script type="text/javascript">
$(document).ready(function () {
$('#ProductId').hide();
$('#CustomerFunds').blur(function () {
var customerFunds = $(this).val();
if (propertyValue.length > 0) {
$.getJSON('/Home/GetProducts', { customerFunds: customerFunds }, function (data) {
$('#ProductId').show();
$('#ProductId option').remove();
$('#ProductId').append('<option value="0">Please select a Product</option');
for (var i = 0; i < data.length; i++) {
$('#ProductId').append('<option value="' + data[i].ProductID + '">' + data[i].ProductName + '</option');
}
}).fail(function () {
debugger;
alert('Error getting Products');
});
}
else {
$('#ProductId option').remove();
$('#ProductId').append('<option value="0">Please select a Product</option');
}
});
});
</script>
Once data has been entered into CustomerFunds and the TAB key is pressed, the dropdown appears and is populated.
However, when viewing the source HTML of the page once the dropdown is populated, the actual select list only shows:
<select id="ProductId">
<option value="0">Please select a Product</option>
</select>
Despite the page actually rendering the list, the selected value of the dropdown is NOT passed into the model and therefor the Model Validation fails and I have no idea why.
Updated
Thanks to markpsmith the select for ProductId should be as follows:
<select id="ProductId" name="ProductId">
<option value="0">Please select a Product</option>
</select>
In a view I'm using 3 dropdownlist strongly-typed to a model like this:
#using (Html.BeginForm())
{
<p>Filter by rarity: #Html.DropDownListFor(_item => _item.mRarity, Model.mRarityList, new {#id = "cardRarity"})
Filter by type: #Html.DropDownListFor(_item => _item.mType, Model.mTypeList, new {#id = "cardType"})
Filter by color: #Html.DropDownListFor(_item => _item.mColor, Model.mColorList, new {#id = "cardColor"})
</p>
}
Here's the view in which the thing is displayed:
#model PagedList.IPagedList<MvcMagicAdmin.Utilities.CardDisplay>
#{
ViewBag.Title = "Cards Display Results";
}
<h2>
Cards Display Results
</h2>
<script type="text/javascript">
$(document).ready(function () {
$('#cardRarity').change(function () {
var showCardRarity = $(this).val();
alert(showCardRarity);
var showCardType = $('#cardType').val();
var showCardColor = $('#cardColor').val();
refreshResults(showCardRarity, showCardType, showCardColor);
});
$('#cardType').change(function () {
var showCardType = $(this).val();
alert(showCardType);
var showCardRarity = $('#cardRarity').val();
var showCardColor = $('#cardColor').val();
refreshResults(showCardRarity, showCardType, showCardColor);
});
$('#cardColor').change(function () {
var showCardColor = $(this).val();
alert(showCardColor);
var showCardRarity = $('#cardRarity').val();
var showCardType = $('#cardType').val();
refreshResults(showCardRarity, showCardType, showCardColor);
});
function refreshResults(rarity, type, color) {
$.get("#Url.Action("DisplayCardsResults", "Card")", {
_page: 1,
_sortOrder: "#ViewBag._sortOrder",
_rarity: rarity,
_type: type,
_color: color,
}, function(data) {
$("#resultsDiv").html(data);
});
}
});
</script>
<div>
<div class="float-left">
<p>#Html.ActionLink("Make a new search", "SearchCardsAdvanced")</p>
</div>
<div class="float-right">
<p><span class="bold baseFontSize">Legend: </span>Details #Html.Image("~\\Images\\Functional\\Icons\\detailsIcon.jpg", "details", new { #class = "centerVert" } )
Edit #Html.Image("~\\Images\\Functional\\Icons\\editIcon.png", "edit", new {#class = "centerVert"} )
Delete #Html.Image("~\\Images\\Functional\\Icons\\trashIcon.png", "delete", new {#class = "centerVert"} )</p>
</div>
<div class="clear"></div>
</div>
#{
Html.RenderAction("FilterCardsResults", "PartialViews");
}
<div id="resultsDiv">
#{
Html.RenderPartial("ResultsTable", Model);
}
</div>
So, yes, I am calling a partial view from another controller because I pass a model which is not included in the Original List of models.
The view is generated like this:
private static readonly CardsFilters mCardsFilters = new CardsFilters();
public ActionResult FilterCardsResults()
{
return PartialView("Filters/FilterCardsResults", mCardsFilters);
}
Here's the model on which the data is built:
public class CardsFilters
{
public string mRarity { get; set; }
public IEnumerable<SelectListItem> mRarityList { get; set; }
public string mType { get; set; }
public IEnumerable<SelectListItem> mTypeList { get; set; }
public string mColor { get; set; }
public IEnumerable<SelectListItem> mColorList { get; set; }
public CardsFilters()
{
List<SelectListItem> items = new List<SelectListItem>
{
new SelectListItem() {Value = "All", Text = "All"},
new SelectListItem() {Value = "Land", Text = "Land"},
new SelectListItem() {Value = "Common", Text = "Common"},
new SelectListItem() {Value = "Uncommon", Text = "Uncommon"},
new SelectListItem() {Value = "Rare", Text = "Rare"},
new SelectListItem() {Value = "Mythic Rare", Text = "Mythic Rare"},
new SelectListItem() {Value = "Special", Text = "Special"}
};
mRarityList = new SelectList(items, "Value", "Text");
items = new List<SelectListItem>
{
new SelectListItem(){ Value = "All", Text = "All"},
new SelectListItem(){ Value = "Artifact", Text = "Artifact"},
new SelectListItem(){ Value = "Instant", Text = "Instant"},
new SelectListItem(){ Value = "Creature", Text = "Creature"},
new SelectListItem(){ Value = "Land", Text = "Land"},
new SelectListItem(){ Value = "Planeswalker", Text = "Planeswalker"},
new SelectListItem(){ Value = "Enchantment", Text = "Enchantment"},
new SelectListItem(){ Value = "Sorcery", Text = "Sorcery"},
new SelectListItem(){ Value = "Tribal", Text = "Tribal"},
};
mTypeList = new SelectList(items, "Value", "Text");
items = new List<SelectListItem>
{
new SelectListItem(){ Value = "All", Text = "All"},
new SelectListItem(){ Value = "White", Text = "White"},
new SelectListItem(){ Value = "Red", Text = "Red"},
new SelectListItem(){ Value = "Green", Text = "Green"},
new SelectListItem(){ Value = "Blue", Text = "Blue"},
new SelectListItem(){ Value = "Black", Text = "Black"},
new SelectListItem(){ Value = "Gold", Text = "Gold"},
new SelectListItem(){ Value = "Colorless", Text = "Colorless"},
};
mColorList = new SelectList(items, "Value", "Text");
}
}
And, finally, the post method called in the controller:
public ActionResult DisplayCardsResults(int? _page, string _sortOrder, string _rarity = "", string _type = "", string _color = "")
{
ViewBag._rarity = _rarity;
ViewBag._color = _color;
ViewBag._type = _type;
if (Request.HttpMethod != "GET")
{
_page = 1;
}
if (mListCards.Count == 0)
{
TempData[MessageDomain.Tags.TEMPDATA_MESSAGE_ERROR] = NODATAFILTERERRORMESSAGE;
}
int pageNumber = (_page ?? 1);
if (Request.IsAjaxRequest())
{
mListCardsToShow = GetListCardsToShow(_rarity, _color, _type);
return PartialView("ResultsTable", mListCardsToShow.ToPagedList(pageNumber, ValueDomain.PAGE_SIZE));
}
if (mListCardsToShow.Count > 0)
{
mListCardsToShow = SortListOrder(_sortOrder, mListCardsToShow);
return View(mListCardsToShow.ToPagedList(pageNumber, ValueDomain.PAGE_SIZE));
}
if (mListCards.Count > 0)
{
mListCards = SortListOrder(_sortOrder, mListCards);
}
return View(mListCards.ToPagedList(pageNumber, ValueDomain.PAGE_SIZE));
}
The dropdownlist works very fine, except for one reason. When I post back the form, all the values selected in the dropdownlist resets to "All", and I'd like to keep them selected. How might I do this?
You must make shure that you are correctly binding your return model into the view.
I took your example and included it into a simple project, that is working ok:
The controller with a simple POST:
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
var model = new CardsFiltersViewModel();
return View(model);
}
[HttpPost]
public ActionResult Index(CardsFiltersViewModel model)
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View(model);
}
public ActionResult About()
{
return View();
}
}
It returns the object the you presented above.
The View is the exact same as your code.
#using (Html.BeginForm())
{
<p>
Filter by rarity: #Html.DropDownListFor(_item => _item.mRarity, Model.mRarityList, new { #id = "cardRarity" })
Filter by type: #Html.DropDownListFor(_item => _item.mType, Model.mTypeList, new { #id = "cardType" })
Filter by color: #Html.DropDownListFor(_item => _item.mColor, Model.mColorList, new { #id = "cardColor" })
</p>
<input type="submit" name="name" value=" " />
}
With the reference to the model class object (
#model MvcApplication7.Controllers.CardsFiltersViewModel
)