I have a mvc web application which contains chart and table data.
Scenario:
I am populating data in the Index method and return the model to view for binding. In view, table bind with the data. I also want to bind the chart with same data. Chart bind with child action. I set TempData[] object in the Index method and retrieve the same in Chart action.
Code:
Controller
public ActionResult Index()
{
var data = new List<MyModel>()
{
new MyModel { Text = "Name1", Value = 123 },
new MyModel { Text = "Name2", Value = 24 },
};
TempData["data"] = data;
return View(data);
}
public FileContentResult Chart()
{
List<MyModel> data = TempData["data"] as List<MyModel>;
var chart = new Chart
{
Width = 300,
Height = 450,
};
if (data != null)
{
chart.ChartAreas.Add("");
chart.Series.Add("");
chart.Series[0].ChartType = SeriesChartType.Column;
foreach (var q in data)
{
chart.Series[0].Points.AddXY(q.Text, Convert.ToDouble(q.Value));
}
}
using (var chartimage = new MemoryStream())
{
chart.SaveImage(chartimage, ChartImageFormat.Png);
return File(chartimage.GetBuffer(), #"image/png");
}
}
public async Task<ActionResult> Export()
{
var converter = new HtmlToPdf();
var baseAddress = new Uri("http://localhost:4545/");
var cookieContainer = new System.Net.CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (HttpClient client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var result = await client.GetAsync("/Home/Index");
var htmlString = await result.Content.ReadAsStringAsync();
var doc = converter.ConvertHtmlString(htmlString, baseAddress.ToString());
doc.Save(System.Web.HttpContext.Current.Response, true, "test.pdf");
doc.Close();
}
return null;
}
View:
<div class="row">
#using (Html.BeginForm("Index", "Home", FormMethod.Get))
{
<div class="col-md-12">
<table>
#{
foreach (var item in Model)
{
<tr>
<td>
#item.Text
</td>
<td>
#item.Value
</td>
</tr>
}
}
</table>
</div>
<div class="col-md-12">
<img src="#Url.Action("Chart")" />
<input type="submit" value="Filter" />
</div>
}
<div class="col-md-12">
#using (Html.BeginForm("Export", "Home", FormMethod.Post))
{
<input type="submit" value="Export" />
}
</div>
Problem:
Here i am using SelectPdf to export the web page to pdf. When i click Export button, it takes the content of web page so that again Index and Chart rendered. But here i didn't get tempdata[] values. It shows as null. So chart data not getting in pdf
Please help me to solve this issue
Please Note :
TempData in ASP.NET MVC can be used to store temporary data which can be used in the subsequent request. TempData will be cleared out after the completion of a subsequent request.
So to retain the values of TempData in subsequent request you need to call either TempData.Keep() or Peek("tempdata name").
Keep Syntax:
String data = TempData["myData"] as string;
TempData.Keep();
Peek Syntax:
String data = TempData.Peek("myData");
Try this
List<MyModel> data = (List<MyModel>)TempData.Peek("data");
Related
I am working with Jira Rest Api and I am trying to create a form that will include a dropdown with all the users from certain project, so I could assign them while creating a ticket.
My form works But unfortunnetly Users have to be hardcoded at the moment.
I am a novice programmer and my problem begins here: I am usign HttpPost to submit form and pass that values to Api, but before I do that I need to do HttpGet to populate one of the form dropdowns. This is confusing for me and I am not able to do that.
My Form
#using (Html.BeginForm("Index", "Ticket", FormMethod.Post))
{
<div>
<br />
<div style="background-color:#1976D2; color: white; padding: 3px; border-radius:3px; font-weight: 300;">
<a>Create Issue</a>
</div>
<br />
<form>
<span style="font-size: 0.9em">Project</span> #Html.DropDownListFor(m => model.fields.project.key, new List<SelectListItem> { new SelectListItem { Text = "Jira Test Board", Value = "JATP" }, }, new { #class = "form-control input-background" })
<br />
<span style="font-size: 0.9em">Issue type</span> #Html.DropDownListFor(m => model.fields.issuetype.name, new List<SelectListItem> { new SelectListItem { Text = "Sales", Value = "Sales" }, new SelectListItem { Text = "Bug", Value = "Bug" }, new SelectListItem { Text = "Feature", Value = "Feature" }, new SelectListItem { Text = "Task", Value = "Task" }, }, new { #class = "form-control input-background" })
<br />
<span style="font-size: 0.9em">Assign<sup class="star">*</sup></span> #Html.DropDownListFor(m => model.fields.assignee.name, new List<SelectListItem> { new SelectListItem { Text = "Jacob Zielinski", Value = "<someId>" }, }, new { #class = "form-control input-background" })
<br />
<span style="font-size: 0.9em">Summary<sup class="star">*</sup></span> #Html.TextBoxFor(m => model.fields.summary, new { #class = "form-control my-size-text-area input-background" })
<br />
<div class="form-group">
<span style="font-size: 0.9em">Description<sup class="star">*</sup></span> #Html.TextAreaFor(m => model.fields.description, 5, 60, new { #class = "form-control my-size-text-area input-background" })
</div>
<br />
<input onclick="loadingOverlay()" id="Submit" class="btn btn-primary float-right" type="submit" value="Create" />
</form>
</div>
}
Ticket Controller
public class TicketController : Controller
{
[HttpPost]
public async Task<ActionResult> Index(TokenRequestBody model)
{
var submitForm = new TokenRequestBody()
{
fields = new TokenRequestField()
{
project = model.fields.project,
description = model.fields.description,
summary = model.fields.summary,
issuetype = model.fields.issuetype,
assignee = model.fields.assignee
},
};
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
$"login:password")));
var httpRequestMessage = new HttpRequestMessage();
httpRequestMessage.Method = HttpMethod.Post;
httpRequestMessage.RequestUri = new Uri("<company>atlassian.net/rest/api/2/issue/");
httpRequestMessage.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(submitForm), Encoding.UTF8, "application/json");
var response = httpClient.SendAsync(httpRequestMessage).Result;
string responseBody = await response.Content.ReadAsStringAsync();
var jiraResponse = JsonConvert.DeserializeObject<TicketResponseBody>(responseBody);
TempData["Message"] = "Ticked Created";
TempData["Id"] = jiraResponse.Id;
TempData["Key"] = jiraResponse.Key;
TempData["Self"] = jiraResponse.Self;
return RedirectToAction("Index", "Home");
}
}
[HttpGet]
public async Task<ActionResult> GetUserToAssign()
{
using (var httpClient = new HttpClient())
{
var formatters = new List<MediaTypeFormatter>() {
new JsonMediaTypeFormatter(),
new XmlMediaTypeFormatter()
};
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
$"login:password")));
var httpRequestMessage = new HttpRequestMessage();
httpRequestMessage.Method = HttpMethod.Get;
var content = await httpClient.GetAsync("<company>atlassian.net/rest/api/2/user/assignable/search?project=HOP");
string responseBody = await content.Content.ReadAsStringAsync();
var assigneBodyResponse = new List<AssigneeRequestBody>();
var allUsersFromJira = await content.Content.ReadAsAsync<IEnumerable<AssigneeRequestBody>>(formatters);
var resultsJira = allUsersFromJira.Cast<AssigneeRequestBody>().ToList();
return View();
}
Home Controller
public ActionResult Index(LogFilterModelVm filterModel)
{
if (filterModel == null || filterModel.ResultCount == 0)
{
filterModel = new LogFilterModelVm() { CurrentPage = 0, ResultCount = 50, FromDate = DateTime.Now.AddDays(-7), ToDate = DateTime.Now };
}
using (var repositoryCollection = new repositoryCollection())
{
var logsFromDb = repositoryCollection.ErrorLogsRepository.AllErrorLogs(filterModel.CurrentPage, filterModel.ResultCount, filterModel.Filter_Source, filterModel.Filter_Type, filterModel.Filter_User, filterModel.Filter_Host, filterModel.Filter_SearchBar, filterModel.FromDate , filterModel.ToDate);
var chartCount = new List<int>();
var chartNames = new List<string>();
foreach(var item in logsFromDb.ChartData)
{
chartCount.Add(item.Count);
chartNames.Add(item.Source);
}
var viewModel = new LogPackageVm()
{
ChartCount = chartCount,
ChartNames = chartNames,
LogItems = logsFromDb.LogItems,
FilterModel = new LogFilterModelVm(),
Distinct_SourceLog = logsFromDb.Distinct_SourceLog,
Distinct_TypeLog = logsFromDb.Distinct_TypeLog,
Distinct_UserLog = logsFromDb.Distinct_UserLog,
Distinct_HostLog = logsFromDb.Distinct_HostLog,
Filter_SearchBar = logsFromDb.Filter_SearchBar,
};
return View(viewModel);
}
}
I have tried to return Get results to View Model but I have failed.
Above picture shows what is my expected result
Thanks to user #codein I have manage to do this.
I have call the Method within my HomeController
var users = await new TicketController().GetUserToAssign();
Created a ViewBag with SelectList
ViewBag.Users = new SelectList(users, "accountId", "displayName");
And called it on my View
#Html.DropDownListFor(m => model.fields.assignee.name, (IEnumerable<SelectListItem>)ViewBag.Users)
That works great for me.
As a newbie in ASP.NET Core, this is my first time trying to make an ajax call to asp.net controller method with jquery and I am finding it difficult. Below is my view form, my javascript file and my controller method;
The view form
<form id="components-form">
#Html.AntiForgeryToken();
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="entryformLabel">Payment Entries</h4>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped" id="list-table">
<thead>
<tr>
<th>Entry</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
#foreach (var ent in ViewBag.staffEntries)
{
<tr>
<th>#ent.EntryLabel</th>
<th><input type="text" class="form-control entry" name="component[#ent.EntryId]" id="#ent.EntryId" value="#ent.EntryValue" /></th>
</tr>
}
</tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" id="update-entries-btn" class="btn btn-success"><span class="fa fa-check"></span> Update Entries</button>
</div>
</form>
The Javascript file
$(document).ready(function ()
{
var updateBtn = $("#update-entries-btn").click(function ()
{
$("#update-entries-btn").click(function () {
var token = $("[name=__RequestVerificationToken").val();
var postedValues = new FormData();
postedValues.append("__RequestVerificationToken", token);
$(".entry").each(function () {
var id = this.id;
var val = this.val;
postedValues.append(id,val);
});
var postUrl = "/staff/updatecomponents";
$.post(postUrl, postedValues, function (result) {
alert(result);
});
})
})
}
);
The controller method. I'm actually lost on how to handle the request at this point. Doint this returns null.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult updatecomponents(string posted)
{
return Json(posted);
}
I will appreciate a guide to get this working.
Thank you
After some more research, I solved this thus:
The Javascript code
$(document).ready(function ()
{
$("#update-components-btn").click(function ()
{
var token = $("[name=__RequestVerificationToken").val();
var staffId = $("[name=staffId").val();
var postedValues = {};
postedValues["__RequestVerificationToken"] = token;
postedValues.StaffId = staffId;
postedValues.StaffComponents = [];
$(".entry").each(function ()
{
var component = {};
component.StaffId = staffId;
component.EntryId = $(this).attr('id');
component.ValueAmount = Number($(this).val());
postedValues.StaffComponents.push(component);
});
var postUrl = "/staff/updatecomponents";
$.post(postUrl, postedValues, function (result)
{
var report = JSON.parse(JSON.stringify(result));
if (report.status)
{
swal("<span class=fa fa-thumbs-up", report.message, "success");
setInterval(function () { window.location.reload(true); }, 5000);
}
else
{
swal("<span class=fa fa-thumbs-down", report.message, "error");
}
});
});
}
);
I had to create a model that would emulate the expected object
public class StaffEntryUpdateModel
{
public string RequestToken { get; set; }
public string StaffId { get; set; }
public List<StaffEntry> StaffComponents { get; set; }
}
And finally the server side endpoint that receives and processes the ajax post
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult updatecomponents(StaffEntryUpdateModel postedData)
{
try
{
if (postedData.StaffComponents.Any())
{
ApplicationUser Staff = db.Users.FirstOrDefault(s => s.Id == postedData.StaffId);
if (Staff == null)
{
return new JsonResult(new { Status = false, Message = "Unknown staff" });
}
db.StaffEntries.Where(se => se.StaffId == postedData.StaffId).Delete();
foreach (var c in postedData.StaffComponents)
{
db.StaffEntries.Add(c);
}
int inserted = db.SaveChanges();
return new JsonResult(new { Status = (inserted > 0) ? true : false, Message = inserted + " components updated for staff" });
}
else
{
return new JsonResult(new { Status = false, Message = "No component sent for update for staff" });
}
}
catch (Exception e)
{
return new JsonResult(new {Status=false,Message=e.Message.ToString() });
}
}
In the process of working and reviewing the code, I had to change some items from the way it appeared in the original question but its basically the same.
I hope this helps someone looking for such solution anytime.
Thank you #Chetan Ranpariya for your attempt to help
I have written some code based on some tutorials to update an existing word document with data from my database tables.
I keep getting the program crashing and advising that I may have an infinite loop, however I am using a for each statement and when I debug it tells me i only have one record. Cannot understand where the problem is.
If someone can assist that would be greatly appreciated. Code below
Controller
using System.Web.Mvc;
using Mojito.Models;
namespace Mojito.Controllers
{
public class KronosDesignDocumentController : Controller
{
private MojitoContext _db = new MojitoContext();
//
// GET: /KronosDesignDocument/
public ActionResult Index()
{
ViewBag.CustomerId = new SelectList(_db.Customers, "CustomerId", "CustomerName");
return View();
}
[HttpPost]
public ActionResult Load(int customerId)
{
var kronosDesignTemplate = new KronosDesignDocument.CreateDesignDoc(#"C:\Users\Craig Cocker\Documents\XML Files\Test_Design_Template.docx");
kronosDesignTemplate.CustomerDesignDocument();
ViewBag.CustomerId = new SelectList(_db.Customers, "CustomerId", "CustomerName");
ViewBag.Message = "Configuration has been loaded successfully";
return View("Index");
}
}
}
Model
using System.Collections.Generic;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Linq;
namespace Mojito.Models
{
public class KronosDesignDocument
{
public static MojitoContext _db = new MojitoContext();
public class CreateDesignDoc
{
private readonly string _xmlPath;
//private readonly int _customerId;
public CreateDesignDoc(string pathToXmlFiles)
{
_xmlPath = pathToXmlFiles;
}
public IEnumerable<Customer> CustomerDesignDocument()
{
WordprocessingDocument myDoc = WordprocessingDocument.Open(_xmlPath, true);
var docPart = myDoc.MainDocumentPart;
var doc = docPart.Document;
var table = new Table();
var tb = new TopBorder();
tb.Val = BorderValues.DashDotStroked;
tb.Size = 12;
var borders = new TableBorders();
borders.TopBorder = tb;
borders.LeftBorder = new LeftBorder() {Val = BorderValues.Single, Size = 12};
borders.RightBorder = new RightBorder() {Val = BorderValues.Single};
borders.BottomBorder = new BottomBorder() {Val = BorderValues.Single};
borders.InsideHorizontalBorder = new InsideHorizontalBorder() {Val = BorderValues.Single};
borders.InsideVerticalBorder = new InsideVerticalBorder() {Val = BorderValues.Single};
var props = new TableProperties();
props.Append(borders);
table.Append(props);
var customers = _db.Customers.ToList();
var customerCollection = new List<Customer>();
foreach (var c in customers)
{
var tr = new TableRow();
var customerName = c.CustomerName;
var tc = new TableCell();
var runProp = new RunProperties();
runProp.Append(new Bold());
runProp.Append(new Color() {Val = "FF0000"});
var run = new Run();
run.Append(runProp);
var t = new Text(customerName);
run.Append(t);
var justification = new Justification();
justification.Val = JustificationValues.Center;
var paraProps = new ParagraphProperties(justification);
var p = new Paragraph();
p.Append(paraProps);
p.Append(run);
tc.Append(p);
var tcp = new TableCellProperties();
var tcw = new TableCellWidth();
tcw.Type = TableWidthUnitValues.Dxa;
tcw.Width = "2000";
tcp.Append(tcw);
tcp.Append(tcp);
tr.Append(tc);
table.Append(tr);
}
doc.Body.Append(table);
doc.Save();
return customerCollection;
}
}
}
}
View
#model Mojito.Models.KronosDesignDocument
#{
ViewBag.Title = "Kronos Design Document";
}
<h1>Load Kronos Data</h1>
<h2>#ViewBag.Message</h2>
#using (Html.BeginForm("Load", "KronosDesignDocument", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
<div>#Html.Partial("~/Views/Shared/_Customer.cshtml")</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<input type="submit" value="Create Design Document" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
In your method to create your document you have this line:
tcp.Append(tcp);
that basically appends a reference to its self. I assume the OpenXML stuff expects you to take care of peventing such self-references and if you don't it's only way it has left is break with an StackOverflow exception.
If you fix that line, to
tc.Append(tcp);
all is good...
I'm kinda new at JQuery and are stuck atm. I have an MVC application that draws charts from Google API. I'm working on a UI that alows the user to select a item from a DropDownList, click Run and the charts will load. My current problem is the charts are run directly when i go to the view. The JQuery function that draws the charts implements the GetData ActionResult in GAStatisticsController.
I have a dropDownList with selectable items from a model class and a button ("GAStatisticsReport-Submit"). I just need t check if item "Visitors" is selected in the DropDownList, if that's the case i can click run and the Charts will display the data with visitors. How could i archive this?
The controller has a method called CreateGAStatisticsReport wich returns data to the view for the charts to display. This method has an ActionResult. However when the function draws the charts it draws them from GetData ActionResult and not GAStatistics.
Here is the view:
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", { packages: ["corechart"] });
google.load("visualization", "1", { packages: ["treemap"] });
google.setOnLoadCallback(drawChart);
function drawChart() {
$.get('/GAStatistics/GetData', {}, <--- here's GetData ActionResult in the Controller
function (data) {
var tdata = new google.visualization.DataTable();
tdata.addColumn('date', 'Datum');
tdata.addColumn('number', 'Besökare');
for (var i = 0; i < data.length; i++) {
var dateStr = data[i].Date.substr(0, 4) + "-" + data[i].Date.substr(4, 2) + "-" + data[i].Date.substr(6, 2);
tdata.addRow([new Date(dateStr), parseInt(data[i].Visitors)]);
}
var options = {
title: "Number of unique visitors"
};
var chart1 = new google.visualization.AreaChart(document.getElementById('chart_div1'));
var chart2 = new google.visualization.LineChart(document.getElementById('chart_div2'));
var chart4 = new google.visualization.ColumnChart(document.getElementById('chart_div4'));
chart1.draw(tdata, options);
chart2.draw(tdata, options);
chart4.draw(tdata, options);
});
}
</script>
<table class="adminContent">
<tr>
<td class="adminTitle">
#Html.NopLabelFor(model => model.StartDate):
</td>
<td class="adminData">
#Html.EditorFor(model => model.StartDate)
</td>
</tr>
<tr>
<td class="adminTitle">
#Html.NopLabelFor(model => model.EndDate):
</td>
<td class="adminData">
#Html.EditorFor(model => model.EndDate)
</td>
</tr>
<tr>
<td class="adminTitle">
#Html.NopLabelFor(model => model.GAStatisticsId ):
</td>
<td class="adminData">
#Html.DropDownList("GAStatisticsId", Model.AvailableGAStatistics)
<input type="button" id="GAStatisticsReport-Submit" class="t-button" value="#T("Run")" />
</tr>
</table>
My ViewModel (note: When SelectListItem "Visitors is selected and the user has clicked the "Run" button it should execute and draw the charts):
public class GAStatisticsListModel : BaseNopModel
{
public GAStatisticsListModel()
{
AvailableGAStatistics = new List<SelectListItem>();
SelectListItem Visitors = new SelectListItem() { Text = "Besökare", Value = "1", Selected = false };
SelectListItem PercentNewVisitors = new SelectListItem() { Text = "Nya Besökare (Procent)", Value = "2", Selected = false };
SelectListItem ConversionRate = new SelectListItem() { Text = "Konverteringsgrad", Value = "3", Selected = false };
AvailableGAStatistics.Add(Visitors);
AvailableGAStatistics.Add(PercentNewVisitors);
AvailableGAStatistics.Add(ConversionRate);
}
[NopResourceDisplayName("Admin.ShopStatistics.List.StartDate")]
[UIHint("DateNullable")]
public DateTime? StartDate { get; set; }
[NopResourceDisplayName("Admin.ShopStatistics.List.EndDate")]
[UIHint("DateNullable")]
public DateTime? EndDate { get; set; }
[NopResourceDisplayName("Admin.GAStatistics.GAStatistics.GAStatisticsList")]
public int GAStatisticsId { get; set; }
public List<SelectListItem> AvailableGAStatistics { get; set; }
}
}
The Controller (GetData passes data to the JQuery code in the view from CreateGAStatisticsReport for the charts to display):
public class GAStatisticsController : Controller
{
//GET: /ShopStatistics/
[HttpPost]
public ActionResult GetData()
{
return Json(CreateGAStatisticsReport(), JsonRequestBehavior.AllowGet);
}
public ActionResult GAStatistics()
{
return View(new GAStatisticsListModel());
}
private List<GAStatistics> CreateGAStatisticsReport()
{
var serviceAccountEmail = "xxxxxxxxx#developer.gserviceaccount.com";
var certificate = new X509Certificate2(#"C:\Users\Desktop\NopCommerce\Presentation\Nop.Web\key.p12", "notasecret", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { AnalyticsService.Scope.Analytics }
}.FromCertificate(certificate));
// Create the service.
//Twistandtango
var GoogleAnalyticsService = new AnalyticsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyApp",
});
var request = GoogleAnalyticsService.Data.Ga.Get("ga:xxxxxxxx", "2014-01-24", "2014-01-30", "ga:visitors");
//Specify some addition query parameters
request.Dimensions = "ga:date";
request.Sort = "-ga:date";
request.MaxResults = 10000;
//Execute and fetch the results of our query
Google.Apis.Analytics.v3.Data.GaData d = request.Execute();
List<GAStatistics> ListGaVisitors = new List<GAStatistics>();
foreach (var row in d.Rows)
{
GAStatistics GaVisits = new GAStatistics(row[0], row[1]);
ListGaVisitors.Add(GaVisits);
}
return ListGaVisitors;
}
}
For what you want you can't use google.setOnLoadCallback(drawChart) (see this link too understand why). If I understand what you want to do, you must set a event on your button and that event will execute the drawChart() function.
Like this:
$("#GAStatisticsReport-Submit").click(function(){ drawChart() })
So, when you click on that button the chart will be draw.
To draw the chart only if the 'Visitors' is selected you must do something like this:
$("#GAStatisticsReport-Submit").click(function(){
if($("select[name='GAStatisticsId'] option:selected").text()=="Visitors")
drawChart()
})
I have a partial view that has an Ajax.ActionLink that when clicked should replace the view (target DIV) with another partial view that allows a user to upload an image. I have several of these on the page that work, I just can't seem to figure out why I keep getting a 404 for this particular one.
Here's what I have:
MyProfile.cshtml holds all the partials (tenant-reference-photos is update target DIV):
<div class="row-fluid">
<div class="span6 well-border" id="tenant-reference-photos">
#Html.Partial("~/Views/Tenants/_TenantReferencePhotosPartial.cshtml", Model)
</div>
<div class="span6 well-border" id="tenant-viewings">
#Html.Partial("~/Views/Tenants/_TenantViewingsPartial.cshtml", Model)
</div>
</div>
_TenantReferencePhotosPartial.cshtml (ActionLink giving 404 here):
<div class="row-fluid">
#if (Model.ReferencePhotos == null)
{
<h3>You haven't uploaded any references!
#Ajax.ActionLink("Upload now?", // on click 404 returned in developer tools in Chrome
"UploadReference",
new AjaxOptions
{
UpdateTargetId = "tenant-reference-photos",
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET",
LoadingElementId = "ajax-loader"
})
</h3>
}
</div>
Code below returns the above partial:
[HttpGet]
public ActionResult TenantReferencePhotos()
{
var currentTenant = tenantRepository.GetLoggedInTenant();
return PartialView("_TenantReferencePhotosPartial", currentTenant.ReferencePhotos.ToList());
}
The following ActionResult is what's not being invoked in the Ajax.ActionLink and giving the 404 error:
[HttpPost]
public ActionResult UploadReference(HttpPostedFileBase file, Tenant tenant)
{
if (file != null)
{
if (file.ContentLength > 10240)
{
ModelState.AddModelError("file", "The size of the file should not exceed 10 KB");
return View();
}
var supportedTypes = new[] { "jpg", "jpeg", "png", "JPG", "JPEG", "PNG" };
var fileExt = System.IO.Path.GetExtension(file.FileName).Substring(1);
if (!supportedTypes.Contains(fileExt))
{
ModelState.AddModelError("photo", "Invalid type. Only the following types (jpg, jpeg, png) are supported.");
return View();
}
using (var db = new LetLordContext())
{
var reference = db.Image.Create<ReferencePhoto>();
// Convert HttpPostedFileBase to byte array
MemoryStream target = new MemoryStream();
file.InputStream.CopyTo(target);
byte[] photo = target.ToArray();
reference.File = photo;
reference.Format = fileExt;
reference.DateUploaded = DateTime.Now.Date;
reference.Description = "";
reference.Name = "";
db.Image.Add(reference);
db.SaveChanges();
return PartialView("_TenantReferencePhotosPartial", file);
}
}
else
{
return View();
}
}
For completeness, here's the partial view where an image can be uploaded:
<div>
#using (Ajax.BeginForm("UploadReference", "Tenants", FormMethod.Post,
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "tenant-reference-photos"
}))
{
#Html.ValidationSummary(true)
#Html.AntiForgeryToken()
<div>
Select a file:
<input type="file" name="file" />
<input type="submit" value="UploadReference" />
</div>
}
</div>
All scripts in MyProfile.cshtml are referenced. Does unobtrusive-ajax.js need to be included as a script in all partial views even if it's referenced in Layout.cshtml and/or MyProfile.cshmtml?
Can anyone spot why I'm getting the error above?
In your code UploadReference is decorated with HttpPost attribute so it is accessible only when you make POST. In your view you have configured HttpMethod to GET. When you change it to POST it should work:
#Ajax.ActionLink("Upload now?",
"UploadReference",
new AjaxOptions
{
UpdateTargetId = "tenant-reference-photos",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
LoadingElementId = "ajax-loader"
})