Pass ViewModel to view twice - c#

I have the following index-method in my homecontroller:
var homeIndexModel = new HomeIndexModel()
{
ActiveTasks = tasks.Where(
task =>
task.TaskStatus != TaskStatusEnum.Deferred &&
task.TaskStatus != TaskStatusEnum.Verified && task.TaskStatus != TaskStatusEnum.Resolved),
ClosedTasks = tasks.Where(
task =>
task.TaskStatus == TaskStatusEnum.Resolved),
DeferredTasks = tasks.Where(
task =>
task.TaskStatus == TaskStatusEnum.Verified ||
task.TaskStatus == TaskStatusEnum.Deferred),
Rules = m_errandSvc.GetAllRules(),
Sources =
Enum.GetValues(typeof(TaskSourceEnum)).Cast<TaskSourceEnum>().AsEnumerable().OrderBy(taskSource => taskSource.AsString()),
Types =
Enum.GetValues(typeof(TaskTypeEnum)).Cast<TaskTypeEnum>().AsEnumerable().OrderBy(taskSource => taskSource.AsString()),
Counties = counties,
Reports = null,
};
return this.View(homeIndexModel);
This homeIndexModel Is passed to the view when you visit the firstpage. As you can see, I assaign a Report-object to null.
I want to use thise Report-property of homeIndexModel when I do a search On the firstpage. When I hit "Search", a modal should appear and the search result printed out.
Here Is my search-method in the controller:
[HttpPost]
public ActionResult SearchReport(string searchVal, string searchParam)
{
var reports = m_errandSvc.GetReportSearch(searchVal, searchParam).ToList();
var homeIndexModel = new HomeIndexModel()
{
Reports = reports
};
return this.View(homeIndexModel);
}
As you can see, I assaign the Report-property with the result of GetReportSearch. I want to loop through this object below:
<!-- Modal -->
<div class="modal" id="myModalSearch" aria-hidden="true" data-keyboard="false" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="panel panel-default">
<div class="panel-heading">
<h4>FISH</h4>
#if (Model.Reports != null)
{
}
</div>
</div>
</div>
</div>
</div>
</div>
The problem I have is that when I add a foreach, like this below, my debug-mode quits.
#if (Model.Reports != null)
{
foreach(var itm in Model.Reports)
{
<div>#itm.Report_id</div>
<div>#itm.ReportSource</div>
}
}
How can I solve this whole thing with homeIndexViewModel and print out my search-result as I want to?
Herer is my jQuery that I use to post to the search-method:
$('#searchReports').click(function () {
var searchVal = $('#searchVal').val();
$.ajax({
contentType: "application/json; charset=utf-8",
dataType: "json",
type: "POST",
url: DataReview.BASE + "/Home/SearchReport",
data: JSON.stringify(
{
'searchVal': searchVal,
'searchParam': searchParam
}
)
}).done(function (data) {
console.log("YES");
}).fail(function(data) {
console.log("Fail " + data);
});
});

Pass back the view model again on search and then assign the report to it this way.
[HttpPost]
public ActionResult SearchReport(string searchVal, string searchParam, HomeIndexModel homeIndexModel )
{
var reports = m_errandSvc.GetReportSearch(searchVal, searchParam).ToList();
homeIndexModel.Reports = reports
return this.View(homeIndexModel);
}
Or the best practice is you can do a Ajax call and then get only the reports data and update your View page. But this requires Jquery, let me know if you want help on implementing this.
EDIT 1: Making small change to your code to get this job done by ajax.
$.ajax({
contentType: "application/json; charset=utf-8",
dataType: "json",
type: "POST",
url: DataReview.BASE + "/Home/SearchReport",
data: JSON.stringify(
{
'searchVal': searchVal,
'searchParam': searchParam
}
)
})
.done(function (reportData ) {
var $panelHeading = $('#myModalSearch .panel-heading');
$('#myModalSearch .panel-heading').contents(':not(h4)').remove(); //remove previous search results
$.each(reportData, function(i,v){
$panelHeading.append("<div>"+this.Report_id+"</div<div>"+this.ReportSource+"</div>"); //append new result
});
})
Your controller must return JSON rather than a view, So change the code to below one.
[HttpPost]
public ActionResult SearchReport(string searchVal, string searchParam)
{
var reports = m_errandSvc.GetReportSearch(searchVal, searchParam).ToList();
return Content( new JavaScriptSerializer().Serialize(reports), "application/json");
}

Related

MVC: 404 not found in ajax

I am showing a number of flights in a view. I have created a button for every flight. On clicking this button I am getting the details of a single flight shown in the view.
here is my view code:
foreach (var item in Model)
{
<div class="toFrom">
<h3 id="FCity_#item.FlightID">#item.FromCity </h3>
<span><i class="fa mx-4 fa-plane"></i></span>
<h3 id="TCity_#item.FlightID">#item.ToCity</h3>
</div>
<div class="info d-flex">
<p class="me-2 " id="DDate_#item.FlightID">#item.DepartureDate.ToShortDateString()</p>
<p class="me-2" id="DTime_#item.FlightID">#item.DepartureTime.ToShortTimeString()</p>
<p class="me-2 " id="ATime_#item.FlightID">#item.ArrivalTime.ToShortTimeString()</p>
<select id="CFare_#item.Fare" class="form-control me-2">
#foreach (var re in ddlcabin)
{
<option value="#re.Fare">#re.CabinName (#re.Fare)</option>
}
</select>
<button class="form-control btn btn-primary" onclick="Save(#item.FlightID,#item.Fare)">select </button>
</div>
}
Now I want to get these values using and pass them to an action method without using a form in the view.
here is my js code:
function Save(id, fare) {
var fct = $("#FCity_" + id).text();
var tct = $("#TCity_" + id).text();
var ddt = $("#DDate_" + id).text();
var dt = $("#DTime_" + id).text();
var at = $("#ATime_" + id).text();
var cf = $("#CFare_" + fare).val();
$.ajax({
method: 'GET',
url: 'Flights/ReserveFlight',
data: { FromCity: fct, ToCity: tct, DepDate: ddt, DepTime: dt, ArrTime: at, CabinFare: cf },
success: function (data) {
console.log("data is inserted")
},
error: function (err) {
console.log(err)
}
});
}
when I click the save button it shows an error in the browser console and doesn't hit the debugger applied to the action method
here is my action method:
public ActionResult ReserveFlight(string FromCity, string ToCity, DateTime DepDate, DateTime DepTime, DateTime ArrTime, int CabinFare)
{
return View();
}
here is the error:
GET
http://localhost:64480/Flights/Flights/ReserveFlight?FromCity=Islamabd%20&ToCity=Karachi&DepDate=5%2F20%2F2022&DepTime=8%3A30%20AM&ArrTime=12%3A00%20AM&CabinFare=4500 404 (Not Found)
Modify the URL in ajax as:
$.ajax({
method: 'GET',
url: '/Flights/ReserveFlight',
data: { FromCity: fct, ToCity: tct, DepDate: ddt, DepTime: dt, ArrTime: at, CabinFare: cf },
success: function (data) {
console.log("data is inserted")
},
error: function (err) {
console.log(err)
}
});
Or work with UrlHelper.
$.ajax({
method: 'GET',
url: '#Url.Action("Flights", "ReserveFlight")',
data: { FromCity: fct, ToCity: tct, DepDate: ddt, DepTime: dt, ArrTime: at, CabinFare: cf },
success: function (data) {
console.log("data is inserted")
},
error: function (err) {
console.log(err)
}
});
Reference: Action(String, String) | UriHelper.Action() Method

Need to simulate an #Html.action() on a button click

I'm having some issues with updating a partial view in my index view. Basically, based on a click, I would like to have updated information.
//controller
public ActionResult Index()
{
var filteredObservations = getFilteredObservationSessions().ToList();
var observationManagementVm = new ObservationManagementVM(filteredObservations);
return View(observationManagementVm);
}
public ActionResult indexPagedSummaries(int? page, List<ObservationSessionModel> data)
{
var alreadyFilteredObservations = data;
int PageSize = 10;
int PageNumber = (page ?? 1);
return PartialView(alreadyFilteredObservations.ToPagedList(PageNumber, PageSize));
}
My main view
//index.cshtml
#model AF.Web.ViewModels.ObservationManagementVM
....
<div id="testsim">
#Html.Action("indexPagedSummaries", new { data = Model.ObservationSessions })
</div>
<input id="new-view" value="Sessions" type="button" />
<script>
$("#new-view").click(function() {
$.ajax({
type: "GET",
data: { data: "#Model.FeedBackSessions" },
url: '#Url.Action("indexPagedSummaries")',
cache: false,
async: true,
success: function (result) {
console.log(result);
$('#testsim').html(result);
$('#testsim').show();
}
});
});
</script>
....
And my partial view
//indexPagedSummaries.cshtml
#model PagedList.IPagedList<AF.Services.Observations.ObservationSessionModel>
#using (Html.BeginForm("indexPagedSummaries"))
{
<ol class="vList vList_md js-filterItems">
#foreach (var item in Model)
{
#Html.DisplayFor(modelItem => item)
}
</ol>
<div>
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index",
new { page }))
</div>
}
Html.Action() returns what I want perfectly, but it doesn't seem to be able to be triggered by a button click.
So, I'm not getting any errors, but the url doesn't give any data back. When I try to run the Observation/indexPagedSummary url without passing in data, I get a System.ArgumentNullException error, so I'm assuming that something is being transferred to the view model. Any help would be so appreciated.
Have not run your code but I believe it is because you are not sending the data along with the #Url.Action
Main View:
//index.cshtml
#model AF.Web.ViewModels.ObservationManagementVM
....
<div id="testsim">
#Html.Action("indexPagedSummaries", new { data = Model.ObservationSessions })
</div>
<input id="new-view" value="Sessions" type="button" />
<script>
$("#new-view").click(function() {
$.ajax({
type: "GET",
data: { data: "#Model.FeedBackSessions" },
url: '#Url.Action("indexPagedSummaries", "[Controller Name]", new { data = Model.ObservationSessions})',
cache: false,
async: true,
success: function (result) {
console.log(result);
$('#testsim').html(result);
$('#testsim').show();
}
});
});
</script>
If that doesn't help I have had issues when I have had a content-type mismatch or a datatype mismatch. You may need to add those to you ajax request.
Change your ajax data line to this:
data: { data: JSON.stringify(#Model.FeedBackSessions) },
You may also need to add these lines to the ajax:
dataType: 'json',
contentType: 'application/json; charset=utf-8',
You can see in one of your comments above that the current URL is being formed with a description of the List Object, rather than the contents of it:
http://localhost:60985/Observation/indexPagedSummaries?data=System.Collections.Generic.List%601%5BAF.Services.Observations.ObservationSessionModel%5D&data=System.Collections.Generic.List%601%5BAF.Services.Observations.ObservationSessionModel%5D&_=1482453264080
I'm not sure if there's a better way, but you may even have to manually get the model data into Javascript before posting it.
eg:
<script>
var temp = [];
#foreach (var item in Model.FeedBackSessions){
#:temp.push(#item);
}
</script>
and then data: { data: JSON.stringify(temp) },

Problems Cascading dropdownlist, generated dropdown isn't posting selected value to server

Here is my view in image
The code is working fine, but...
When i submit the form, it only sends the value of first dropdownlist (I checked on browser network received arguments), also when i view the page source it doesn't show the generated options that I generated using ajax function.
Here is my Code
Action that generate my first dropdownList
public ActionResult TwoDropDownList()
{
HotelContext H = new HotelContext();
ViewBag.DropDownListOne = new SelectList(H.Continent.ToList(), "Id", "Name");
return View();
}
Action that return json of second dropdownlist data
[HttpPost]
public JsonResult UpdateCountryDropDownList(int ContinentId)
{
HotelContext H = new HotelContext();
List<SelectListItem> CountryNames = new List<SelectListItem>();
List<Country> Co = H.Country.Where(x => x.ContinentId == ContinentId).ToList();
Co.ForEach(x =>
{
CountryNames.Add(new SelectListItem { Text = x.Name, Value = x.Id.ToString() });
});
return Json(CountryNames , JsonRequestBehavior.AllowGet);
}
My Ajax call
#model Hotel.Models.Continent
<script>
$(document).ready(function () {
$("#Name").change(function () {
var ContinentoId = $(this).val();
$.ajax({
type: "POST",
dataType: "json",
data: { ContinentId: ContinentoId },
url: '#Url.Action("UpdateCountryDropDownList","Home")',
success: function (result) {
var Country = "<select id='ddlCountry'>";
Country = Country + '<option value="">--Select--</option>';
for (var i = 0; i < result.length; i++) {
Country = Country + '<option value=' + result[i].Value + '>' + result[i].Text + '</option>';
}
Country = Country + '</select>';
$('#Countries').html(Country);
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(arguments)
}
});
});
})
</script>
My View
#using(Html.BeginForm()){
SelectList se = ViewBag.DropDownListOne;
#Html.DropDownListFor(x=>x.Name,se,"--Select--")
<div id ="Countries">
#Html.DropDownList("ddlCountry",new List<SelectListItem>(),"--Select--")
</div>
<input type="submit" value="submit" style="margin-top:100px;" />
}
HTTPPost Action
[HttpPost]
public string TwoDropDownList(string Name, string ddlCountry)
{
if (string.IsNullOrEmpty(Name) || string.IsNullOrEmpty(ddlCountry))
{
return ("you must select Both");
}
else
return ("everything is working fine");
}
You already have a <select> element with name="ddlCountry" (generated by #Html.DropDownList("ddlCountry", new List<SelectListItem>(), "--Select--") but in the ajax call, you overwrite it and create a new <select> element without a name attribute (so its value is not posted back.
In the success callback, you should be creating <option> elements and appending them to the existing <select>
success: function (result) {
var country = $('#ddlCountry); // get the existing element
country.empty().append($('<option></option>').val('').text('--Select--'));
$.each(result, function(index, item) {
country.append($('<option></option>').val(item.Value).text(item.Text));
});
}
Side note: Your methods should be returning a collection of anonymous objects, not SelectListItem There is no point sending extra data (the other properties of SelectListItem) across the wire when you don't use them.
I think you are missing the end tag </div> for the <div id ="Countries">.
Try this:
<div id ="Countries">
#Html.DropDownList("ddlCountry",new List<SelectListItem>(),"--Select--")
</div>

i can not use jquery select2 with json

i MVC4 and i want to add a select box that retrieve data (Product code) from my database the problem is that i have a message from select2.js telling select2 touppercase of undefined.
*all the JS file are uploaded.
here is my Jquery function:
<script>
$(document).ready(function () {
$('#Product_cd').select2({
minimumInputLength: 2,
ajax: {
url: '#Url.Action("AutoComplete")',
dataType: 'json',
data: function (term, page) {
return {
q: term
};
},
results: function (data, page) {
return { results: data };
}
}
});
});
</script>
here is my controller AutoComplete
public JsonResult AutoComplete(string q)
{
Mydb db = new Mydb();
var Code = from c in db.Products
where c.Product_code.Contains(q)
select c.Product_code;
var result = Code.ToList();
return Json(result, JsonRequestBehavior.AllowGet);
}
}
and here is part of the view:
<div class="col-md-2">
<div>#Html.DisplayNameFor(x => x.Product_cd )</div>
<div> #Html.TextBoxFor(x => x.Product_cd)<i class="fa fa-search"></i></div>
</div>
can any one tell me what is the problem

DropDown list doesnt update selected value

I have a dropdownlist:
<div class="a">
#Html.DropDownList("StorageId", null, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.StorageId)
</div>
Html:
<div class="a">
<select class="form-control" id="StorageId" name="StorageId"><option selected="selected" value="1">Brak Brak</option>
<option value="2">First</option>
<option value="23">Second</option>
<option value="24">Third</option>
</select>
<span class="field-validation-valid" data-valmsg-for="StorageId" data-valmsg-replace="true"></span>
</div>
populated with code:
ViewBag.StorageId = new SelectList(unitOfWork.storageRepository.Get(), "Id", "Name", deviceusage.StorageId);
all data is send to controller with this Ajax request:
$.ajax({
url: "/DeviceUsage/Edit",
type: "POST",
contentType: "application/json; charset=utf-8",
headers: {
'RequestVerificationToken': '#TokenHeaderValue()'
},
data: JSON.stringify({
deviceusage: {
DeviceInstanceId: $('.a').children("#DeviceInstanceId").val(),
UserId: $('.a').children('#UserId').val(),
StorageId: $('.a').children('#storageId').val()
}
}),
error: function (data) {
alert("wystąpił nieokreślony błąd " + data);
},
success: function (data) {
if (data.ok) {
$("#Modal").modal('hide');
window.location = data.newurl;
}
else {
$('.modal-body').html(data);
}
}
})
No Matter what I select in this dropdown it's not updated. After changing first selection always first one is send to controller.
#Update:
Here is a controller method I use for handling 'Post` calls:
public ActionResult Edit([Bind(Include="StorageId,UserId,DeviceInstanceId")] DeviceUsage deviceusage)
{
ValidateRequestHeader(Request);
if (deviceusage.UserId == 6 && deviceusage.StorageId == (int)Storage.Biurko)
{
ModelState.AddModelError("", "Zarezerwowane urządzenie nie moze byc przypisane do biurka");
}
if (deviceusage.UserId == 1 && deviceusage.StorageId == (int)Storage.Biurko)
{
ModelState.AddModelError("", "Wolne urządzenie nie może przebywać na jakimś biurku");
}
if ((deviceusage.UserId != 1 & deviceusage.UserId != 6) & deviceusage.StorageId != (int)Storage.Biurko)
{
ModelState.AddModelError("", "Urzązenie przypisane do kogos nie moze przebywac w magazynie");
}
if (ModelState.IsValid)
{
unitOfWork.deviceUsageRepository.Update(deviceusage);
unitOfWork.Save();
return Json(new { ok = true, newurl = Url.Action("Index") });
}
ViewBag.DeviceInstanceId = new SelectList(unitOfWork.deviceInstanceRepository.Get(), "Id", "SerialNo", deviceusage.DeviceInstanceId);
ViewBag.StorageId = new SelectList(unitOfWork.storageRepository.Get(), "Id", "Name", deviceusage.StorageId);
var data = unitOfWork.userRepository.Get()
.Select(s => new
{
Id = s.Id,
Credentials = s.Name + " " + s.Surname
}
);
ViewBag.UserId = new SelectList(data, "Id", "Credentials", deviceusage.UserId);
return PartialView(deviceusage);
}
As you can see its returning a PartialView because dropdown is in modal windows which is updated with a return of Ajax call.
#Update2
During test using browser console with this code:
$('#StorageId').val()
I managed to find that:
its correctly returning values before first send
if the modal is reloaded because of that the data was wrong. Changing selected value using list does not change anything. The value returned with this code is falue send with ajax.
The reason behind the issue that always first value is getting submitted to controller is because of this attr which is set to first option in your dropdown list box,selected="selected".
You could bypass this behaviour with change event call back like this
JQUERY CODE:
$('.a select').on('change',function() {
$(this).find('option:selected').attr("selected","selected");
});
Add the above event listener inside the $(document).ready( function() { ...... }) or onload of the body of your page.
Happy Coding :)
Try:
StorageId: $('.a').children('#StorageId').val()
note uppercase 'S' on #StorageId
Also you could probably just do:
StorageId: $('#StorageId :selected').val();
I've created a jsfiddle to demonstrate: http://jsfiddle.net/2qpBZ/

Categories