On my view, I am using a Viewmodel, and I have a form that has only one textbox that accepts dates (not a part of the viewmodel) and 3 tables. By default on page load.. the tables are populated with data based on today's date (you can see that in the controller code below), but if a user selects a date and clicks the search button then I want the tables data to be changed without a page refresh based on the date they selected.
@using (Html.BeginForm())
{
<div class="form-group mb-3 mt-3" style="margin-right: -1.3%;">
<div class="input-group col-md-3 offset-md-9">
@Html.TextBox("detailsDate", null, new { id = "Details-Date", @class = "form-control datetimepicker" })
<div class="input-group-append">
<button id="Details-Date-Btn" type="submit" class="btn btn-outline-primary"><span class="fa fa-search"></span></button>
</div>
</div>
</div>
}
What I am trying to do is if a user selects and date and hits the search button.. I would like the page to not refresh and the tables data have been changed based on the date. As of right now I am getting:
A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.tbl_WeighAssc_8AA7AB5F9DAB261D5142F1D5F5BA6705A588A5AAD2D369FBD4B4BC1BBE0487D4'.
Viewmodel
public class PersonnelDetailsVm
{
private static ConnectionString db = new ConnectionString();
public PersonnelDetailsVm()
{
CurrentWeekDates = new List<DateTime>();
WeighAssociations = new List<tbl_WeighAssc>();
ArrestAssociations = new List<tbl_TEUArrestAssc>();
InspectionAssociations = new List<tblTEUInspectionAssc>();
}
public string IBM { get; set; }
[Display(Name = "Name")]
public string UserName { get; set; }
public bool Active { get; set; }
public List<DateTime> CurrentWeekDates { get; set; }
public List<tbl_WeighAssc> WeighAssociations { get; set; }
public List<tbl_TEUArrestAssc> ArrestAssociations { get; set; }
public List<tblTEUInspectionAssc> InspectionAssociations { get; set; }
public List<code_WeighLocation> WeighLocations => db.code_WeighLocation.ToList();
public List<code_ArrestType> ArrestTypes => db.code_ArrestType.ToList();
public List<code_InspectionLevel> InspectionLevels => db.code_InspectionLevel.ToList();
}
Ajax:
// Submission
//var redirectUrl = '@Url.Action("Index", "Personnels")';
var settings = {};
settings.baseUri = '@Request.ApplicationPath';
var infoGetUrl = "";
if (settings.baseUri === "/AppName") {
infoGetUrl = settings.baseUri + "/Personnels/Details/";
} else {
infoGetUrl = settings.baseUri + "Personnels/Details/";
}
$("#Details-Date-Btn").click(function() {
$.ajax({
url: infoGetUrl,
method: "POST",
data: $("form").serialize(),
success: function(response) {
console.log("success");
$("body").html(response);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
}
});
});
Controller:
public ActionResult Details(string id, string detailsDate)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
tblPersonnel tblPersonnel = db.tblPersonnels.Find(id);
if (tblPersonnel == null)
{
return HttpNotFound();
}
Mapper.Initialize(config => config.CreateMap<tblPersonnel, PersonnelDetailsVm>());
PersonnelDetailsVm person = Mapper.Map<tblPersonnel, PersonnelDetailsVm>(tblPersonnel);
var employeeData = EmployeeData.GetEmployee(person.IBM);
person.UserName =
$"{ConvertRankAbbr.Conversion(employeeData.Rank_Position)} {employeeData.FirstName} {employeeData.LastName}";
if (string.IsNullOrWhiteSpace(detailsDate))
{
var startOfWeek = DateTime.Today.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
(int)DateTime.Today.DayOfWeek);
person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
var teuFormIds = db.tbl_TEUForm
.Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.InspectionAssociations =
db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
return View(person);
}
else
{
var paramDate = DateTime.ParseExact(detailsDate, "MM/dd/yyyy", CultureInfo.CurrentCulture);
var startOfWeek = paramDate.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
(int)paramDate.DayOfWeek);
person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
var teuFormIds = db.tbl_TEUForm
.Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.InspectionAssociations =
db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
return Json(person, JsonRequestBehavior.AllowGet);
}
}
So, if the actionresult's paramets detailsDate is not null, then it goes into the else statement which returns a JSON object. When debugging this goes through and when the view is returned I am receiving the error I posted above.
Is there a way to replace the model in the view with what I'm returning from the ajax call so the tables can be based on the right date without a page refresh?
Any help is greatly appreciated.
UPDATE
Based on answer's below I have edited the else statement in my controller method to:
Controller
else
{
var paramDate = DateTime.ParseExact(detailsDate, "MM/dd/yyyy", CultureInfo.CurrentCulture);
var startOfWeek = paramDate.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
(int)paramDate.DayOfWeek);
person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
var teuFormIds = db.tbl_TEUForm
.Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.InspectionAssociations =
db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
PreserveReferencesHandling = PreserveReferencesHandling.All,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var jsonStr = JsonConvert.SerializeObject(person);
return Json(jsonStr, "text/plain");
}
My jQuery/Ajax is still the same:
$("#Details-Date-Btn").click(function() {
$.ajax({
url: infoGetUrl,
data: $("form").serialize(),
success: function(response) {
console.log("success");
console.log(response);
$("body").html(response);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
}
});
});
But now, when the date is selected I am being returned to a page that shows the Json like a plain text file and losing the HTML and CSS like a normal view.
Here is what I am being returned when a date is selected and the button is clicked.

Also, when I check the console when I select a date and click the button for that date to be sent to the controller I am seeing this:

UPDATE 2
Here is one of my tables.. the other ones are the same setup:
<table class="table table-bordered">
<thead>
<tr>
<th></th>
@foreach (var date in Model.CurrentWeekDates)
{
<th class="text-center">@date.ToString("ddd") <br /> @date.ToShortDateString()</th>
}
<th class="text-center table-success">Total For Week</th>
</tr>
</thead>
<tbody>
@foreach (var weighLocation in Model.WeighLocations)
{
<tr class="text-center">
<td class="table-dark">@weighLocation.Weigh_Location</td>
@foreach (var date in Model.CurrentWeekDates)
{
if (Model.WeighAssociations.Any(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID))
{
<td>@Model.WeighAssociations.Single(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID).OccurenceCount</td>
}
else
{
<td>0</td>
}
}
<td class="table-success font-weight-bold">@Model.WeighAssociations.Where(x => x.WeighLocationId == weighLocation.ID).Sum(x => x.OccurenceCount)</td>
</tr>
}
</tbody>
</table>
As far as I can see from your problem, to fix it you can do following steps:
1- View
Add a partial view (_Detail.cshtml)
You need a partial view like _Detail that includes your table like this:
@model PersonnelDetailsVm
<table class="table table-bordered">
<thead>
<tr>
<th></th>
@foreach (var date in Model.CurrentWeekDates)
{
<th class="text-center">@date.ToString("ddd") <br /> @date.ToShortDateString()</th>
}
<th class="text-center table-success">Total For Week</th>
</tr>
</thead>
<tbody>
@foreach (var weighLocation in Model.WeighLocations)
{
<tr class="text-center">
<td class="table-dark">@weighLocation.Weigh_Location</td>
@foreach (var date in Model.CurrentWeekDates)
{
if (Model.WeighAssociations.Any(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID))
{
<td>@Model.WeighAssociations.Single(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID).OccurenceCount</td>
}
else
{
<td>0</td>
}
}
<td class="table-success font-weight-bold">@Model.WeighAssociations.Where(x => x.WeighLocationId == weighLocation.ID).Sum(x => x.OccurenceCount)</td>
</tr>
}
</tbody>
</table>
2- Controller
Return the partial view
You should fill the model in your controller and pass it to the partial view.
public ActionResult Details(string id, string detailsDate)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
tblPersonnel tblPersonnel = db.tblPersonnels.Find(id);
if (tblPersonnel == null)
{
return HttpNotFound();
}
Mapper.Initialize(config => config.CreateMap<tblPersonnel, PersonnelDetailsVm>());
PersonnelDetailsVm person = Mapper.Map<tblPersonnel, PersonnelDetailsVm>(tblPersonnel);
var employeeData = EmployeeData.GetEmployee(person.IBM);
person.UserName =
$"{ConvertRankAbbr.Conversion(employeeData.Rank_Position)} {employeeData.FirstName} {employeeData.LastName}";
if (string.IsNullOrWhiteSpace(detailsDate))
{
var startOfWeek = DateTime.Today.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
(int)DateTime.Today.DayOfWeek);
person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
var teuFormIds = db.tbl_TEUForm
.Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.InspectionAssociations =
db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
// return View(person);
}
else
{
var paramDate = DateTime.ParseExact(detailsDate, "MM/dd/yyyy", CultureInfo.CurrentCulture);
var startOfWeek = paramDate.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
(int)paramDate.DayOfWeek);
person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
var teuFormIds = db.tbl_TEUForm
.Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
person.InspectionAssociations =
db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
// return Json(person, JsonRequestBehavior.AllowGet);
}
// return PartialView with the person model
return PartialView("_Detail", person);
}
As you can see in the above code, you should comment the two lines in your code:
// return View(person);
// return Json(person, JsonRequestBehavior.AllowGet);
3- Ajax call
Get the partial view and fill form by it
You don't any changes in ajax call and you can do it like this:
$("#Details-Date-Btn").click(function() {
$.ajax({
url: infoGetUrl,
method: "POST",
data: $("form").serialize(),
success: function(response) {
console.log("success");
$("body").html(response);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
}
});
});
response in this way is a html that comes from partial view and it has all classes as you designed it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With