I am trying to use an ActionLink to pass an instance of a ViewModel from my view to a controller. However, the ViewModel is always null when it reaches the controller.
ActionLink:
#Html.ActionLink("Begin Test", "TakeTest", new { vm = Model }, new { #class = "btn btn-default" })
Controller:
public ActionResult TakeTest(QuizViewModel vm) {
ViewBag.Title = vm.vmTest.TestName;
string userId = User.Identity.GetUserId();
vm.Student = db.Users.SingleOrDefault(s => s.Id == userId);
vm.Attempt = db.Attempts.SingleOrDefault(a => a.Student == vm.Student && a.Test == vm.vmTest);
if (vm.vmTest.AttemptsAllowed > 0 && vm.Attempt.Count >= vm.vmTest.AttemptsAllowed) {
return View();
}
vm.Attempt.Count++;
if (vm.QuestionList == null) {
vm.QuestionList = db.Questions.Where(q => q.TID == vm.vmTest.ID).ToList();
}
Random r = new Random();
int randQid = r.Next(0, vm.QuestionList.Count - 1);
vm.ShowQuestion = vm.QuestionList[randQid];
vm.QuestionList.Remove(vm.ShowQuestion);
vm.Asets = db.AnswerSets.Where(a => a.Question == vm.ShowQuestion).ToList();
return View(vm);
}
Related
I'm experiencing an odd issue .
I got both a text input search field, and a dropdown list.
I've set that with every change on the select menu it will submit said form with the values .
It does bind the values but it bypasses the OnSuccess function and then basically things fall apart
Relevant Code:
#Html.EnumDropDownListFor(x => x.AreaCodes, "בחר אזור", new
{
#class = "select_field w-select",
onchange = "this.form.submit()"
})
ReloadLocations = () => {
$.ajax({
url:`#Url.Action("LocationsList","Locations")`,
method: 'POST',
dataType: 'html',
contentType: 'charset=utf-8',
success: function (data) {
$("#LocationList").empty();
$("#LocationList").append(data);
},
In this version it submits the form, However it goes straight to the function without actually going into the "success" part of the ajax call,
Just returns a view.
which results in me getting a partial view back.
How can I fix this?
Edit:
Full Controller Methode:
{
public ActionResult LocationsList(SearchLocationVM searchVm)
var locationsVM = new List<LocationVM>();
var locations = new List<Locations>();
var searchTerm = searchVm.SearchTerm;
var searchArea = (int)searchVm.AreaCodes;
using (var unitOfWork = new UnitOfWork(new FriendsEntities()))
{
if (searchVm.AreaCodes == 0 && string.IsNullOrWhiteSpace(searchVm.SearchTerm))
{
locations = unitOfWork.Locations.Find(x => x.Visibility).OrderBy(x => x.Order).ToList();
locationsVM = locations.Select(x => new LocationVM()
{
ActivityHours = x.location_open_time ?? string.Empty,
ContactName = x.location_contact_name ?? string.Empty,
FirstPHone = x.first_phone_number ?? string.Empty,
SecondPHone = x.second_phone_number ?? string.Empty,
IsRefrigirated = x.location_refrigerated_medication,
LocationAdress = x.location_address ?? string.Empty,
LocationAreaName = x.location_general_area ?? string.Empty,
WhatsappNumber = x.location_whatsapp ?? string.Empty,
Logo = x.location_logo ?? string.Empty,
Id = x.Id,
}).ToList().ToList();
}
else
{
if (!string.IsNullOrWhiteSpace(searchTerm) && searchArea == 0)
{
locations = unitOfWork.Locations.Find(x => x.Visibility
|| x.location_name.Contains(searchTerm)
|| x.location_address.Contains(searchTerm)
|| x.location_general_area.Contains(searchTerm))
.OrderBy(x => x.Order)
.ToList();
}
if (string.IsNullOrWhiteSpace(searchTerm) && searchArea != 0)
{
locations = unitOfWork.Locations.Find(x => x.Visibility && x.location_area == searchArea).OrderBy(x => x.Order).ToList();
}
if (!string.IsNullOrWhiteSpace(searchTerm) && searchArea != 0)
{
locations = unitOfWork.Locations.Find(x => x.Visibility && x.location_area == searchArea
|| x.location_name.Contains(searchTerm)
|| x.location_address.Contains(searchTerm)
|| x.location_general_area.Contains(searchTerm))
.OrderBy(x => x.Order)
.ToList();
}
locationsVM = locations
.Select(x => new LocationVM()
{
ActivityHours = x.location_open_time ?? string.Empty,
ContactName = x.location_contact_name ?? string.Empty,
FirstPHone = x.first_phone_number ?? string.Empty,
SecondPHone = x.second_phone_number ?? string.Empty,
IsRefrigirated = x.location_refrigerated_medication,
LocationAdress = x.location_address ?? string.Empty,
LocationAreaName = x.location_general_area ?? string.Empty,
WhatsappNumber = x.location_whatsapp ?? string.Empty,
Logo = x.location_logo ?? string.Empty,
Id = x.Id,
}).ToList()
.ToList();
}
For loop post to db works fine. Retrieving value from bool property saved in model works as well. However, when user goes to edit, the view is not showing saved values in the array. So the issue is binding the saved boolean values to the array.
#for (var i = 0; i < Model.Questions.Count; i++)
{
#Html.HiddenFor(m => m.Answers[i].QuestionID, new { id = Model.Questions[i].QuestionID })
#Html.HiddenFor(m => m.Answers[i].ApplicationID, new { id = Model.ApplicationID })
#Html.HiddenFor(m => m.Answers[i].QuestionText, new { id = Model.Questions[i].QuestionText })
#Html.HiddenFor(m => m.Answers[i].QuestionCategoryID, new { id = Model.Questions[i].QuestionCategoryID })
#Html.RadioButtonFor(model => model.Answers[i].ResponseBool, true) Yes
#Html.RadioButtonFor(model => model.Answers[i].ResponseBool, false) No
#Html.DisplayFor(model => model.Questions[i].QuestionText, new { #class = "col-md-2" })
}
I am accessing the questions and answer repos through my viewmodel:
Questions = new QuestionRepository().GetStepOneQuestions();
Answers = new ResponseRepository().GetStepOneResponses(stepOneSaved.ApplicationID)
.Select(k => new Response()
{
ApplicationID = stepOneSaved.ApplicationID,
QuestionID = k.QuestionID,
QuestionCategoryID = k.QuestionCategoryID,
QuestionText = k.QuestionText,
ResponseBool = k.ResponseBool
})
.ToList();
Controller:
public ActionResult StepOne(int id)
{
var application = _applicationData.GetByID(id);
var form = _eduInfoData.GetByEdID(id);
var vm = new StepOneViewModel(application, form);
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult StepOne( StepOneViewModel form)
{
try
{
var item = form.toEduInfo();
if (ModelState.IsValid && _eduInfoData.TrySave(item))
{
for (int i = 0; i < form.Answers.Count; i++)
{
_responseData.TrySave(form.ApplicationID, form.Answers[i]);
}
return RedirectToAction("StepTwo", new { id = item.ApplicationID });
}
}
catch (DataException /* dex */)
{
ModelState.AddModelError(string.Empty, "Unable to save changes. Try again, and if the problem persists contact your system administrator.");
}
return View(form);
}
Solved! problem was I not pulling back the responses correctly.To fix I passed in the appId and questionId into my response model,and set the values there.
still needs some re-factoring but here's the gist of it:
public Response(int id, int qID)
{
this.ResponseBool = new ResponseRepository().GetResponse(id).Where(m => m.QuestionID == qID).Select(m => m.ResponseBool).FirstOrDefault();
}
Answers = Questions
.Select(k => new Response(stepOneSaved.ApplicationID, k.QuestionID)
{
ApplicationID = stepOneSaved.ApplicationID,
QuestionID = k.QuestionID,
QuestionCategoryID = k.QuestionCategoryID,
QuestionText = k.QuestionText,
})
.ToList();
I did check all issues about that but I couldn't figure out how to solve it. I need to your help guys.
Here is my code about dropdownlist. When I post the page I got the error message which I mentioned above.
.cshtml
<div class="editor-label">
#Html.LabelFor(model => model.Department, new { #style = " margin-top:12px;display:block;text-align:center" })
</div>
<div class="editor-field">
#Html.DropDownList("Department",(SelectList) ViewBag.Department, new { id = "Department", #class = "form-control", #style = "width:250px; margin-top:5px;margin-left: auto;margin-right:auto; text-align:center;" })
#Html.ValidationMessageFor(model => model.Department.Name)
</div>
model
public ActionResult Index()
{
IEnumerable<SelectListItem> items = db.Department
.Select(c => new SelectListItem
{
Value = c.ID.ToString(),
Text = c.Name
});
var selectList = new SelectList(items,"Value","Text");
ViewBag.Department = selectList;
return View();
}
[HttpPost]
public ActionResult Index(Person model, HttpPostedFileBase photo)
{
if (ModelState.IsValid)
{
Person Person = new Person();
Person.DeparmentID = model.Department.ID;
Person.FirmID = model.Firm.ID;
Person.GraduationDate = model.GraduationDate;
Person.HomeTel = model.HomeTel;
Person.MobileTel = model.MobileTel;
Person.Mail = model.Mail;
Person.Name = model.Name;
Person.Surname = model.Surname;
Person.Position = model.Position;
Person.WorkingSituation = model.WorkingSituation;
if (photo != null && photo.ContentLength > 0)
{
if (photo.ContentLength > 10240)
{
ModelState.AddModelError("photo", "Resim boyutu 10 KB'ı aşamaz.");
return View();
}
var supportedTypes = new[] { "jpg", "jpeg", "png" };
var fileExt = System.IO.Path.GetExtension(photo.FileName).Substring(1);
if (!supportedTypes.Contains(fileExt))
{
ModelState.AddModelError("photo", "Yalnızca jpg, jpeg, png veri tipleri desteklenmektedir.");
return View();
}
var fileName = Path.GetFileName(photo.FileName);
photo.SaveAs(Server.MapPath("~/Upload/") + photo.FileName);
Person.Img = fileName;
}
db.Person.Add(Person);
db.SaveChanges();
ViewBag.ShowConfirmation = "The item was created.";
return RedirectToAction("Index");
}
else
{
return View(model);
}
}
Maybe if you use DropDownListFor instead of DropDownList? You would need to include the listitems in your viewmodel instead of in a viewbag.
Along these lines
#Html.DropDownListFor(m => m.Department, new SelectList(Model.Departments, "Value", "Text", Model.Department), new { #style = "..." })
The second and third parameter of the SelectList constructor define the names of the Value and Text parameters in your SelectListItem list.
I'm implementing a simple paged list Index using the example at http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
My problem is that the search string is 'lost' when I page to the second page, so instead of a filtered set of results, I'm shown all the records.
My index.cshtml:
#using (Html.BeginForm("Index", "", FormMethod.Get))
{
<p>
#Html.TextBox("searchString", ViewBag.currentFilter as string, new { #placeholder = "Search by title or author" })
<input type="submit" value="Search" />
</p>
}
#if (Model.PageCount > 1)
{
#Html.PagedListPager( Model, page => Url.Action("Index", new { page }) )
}
My controller:
public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
ViewBag.TitleSortParm = sortOrder == "Title" ? "Title desc" : "Title";
ViewBag.AuthorSortParm = sortOrder == "Author" ? "Author desc" : "Author";
ViewBag.DateSortParm = sortOrder == "Date" ? "Date desc" : "Date";
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.currentFilter = searchString;
var Articles = from a in db.Articles
select a;
if (!String.IsNullOrEmpty(searchString))
{
//page = 1;
Insights = Articles.Where(s => s.Title.ToUpper().Contains(searchString.ToUpper())
|| s.Author.ToUpper().Contains(searchString.ToUpper()));
}
switch (sortOrder)
{
case "Author":
Insights = Articles.OrderBy(s => s.Author);
break;
case "Author desc":
Insights = Articles.OrderByDescending(s => s.Author);
break;
case "Title":
Insights = Articles.OrderBy(s => s.Title);
break;
case "Title desc":
Insights = Articles.OrderByDescending(s => s.Title);
break;
case "Date":
Insights = Articles.OrderBy(s => s.DatePublished);
break;
default:
Insights = Articles.OrderByDescending(s => s.DatePublished);
break;
}
int pageSize = 3;
int pageNumber = (page ?? 1);
return View(Articles.ToPagedList(pageNumber, pageSize));
}
When I go to Page 2 as an example, all my variables, sortOrder, currentFilter and searchString are all null.
Robbie
The problem is your PagedList entry doesn't include your sort order nor your current filter.
In addition to adding ViewBag.CurrentSort as suggested by Vasanth, you also need to change your PagedListPager to:
#Html.PagedListPager( Model, page => Url.Action("Index", new { page, currentFilter=ViewBag.CurrentFilter, sortOrder = ViewBag.sortOrder}) )
Hello I figured this out, Use a Tempdata to hold the search parameters. When the search method is called with some values, store the values in a tempdata. When the page list calls the method for page 2, collect the Search parameters from the TempData.
See this:
if (SearchParameter != null)
{
TempData["HoldSearch"] = SearchParameter;
TempData.Keep();
}
else
{
SearchParameter = (CastBacktoType)TempData["HoldSearch"];
TempData.Keep();
}
Have tried this, it works well
If you have a complex search/filtering section with more than one field, you might need to use something like :
<div class="pagedList">
#Html.PagedListPager(Model, page => Url.Action("Index", new {
page, sortOrder = ViewBag.CurrentSort,
currentFilter = ViewBag.CurrentFilter,
filter2= Request.QueryString["filter2"],
filter3= Request.QueryString["filter3"],
filter4= Request.QueryString["filter4"],
filter5= Request.QueryString["filter5"] }))
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
</div>
This worked for me and now I can use complex filtering and view the results on multiple pages.
To filter the data by applying multiple filters we can use ViewBag like this in View.
For example if we want to apply filter for three fields(i.e EmpFirstName, EmpLastName, EmpLocation).
#Html.PagedListPager(Model, page => Url.Action("Index", new {
page,
sortOrder = ViewBag.sortOrder,
currentFilter1 =ViewBag.CurrentFilterForEmpFirstName,
currentFilter2 =ViewBag.CurrentFilterForEmpLastName,
currentFilter3 =ViewBag.CurrentFilterForEmpLocation}))
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
In controller i wroted code like this:
public ActionResult Index( int ?page, string currentFilter1, string currentFilter2, string currentFilter3,
string searchEmpFirstName , string searchEmpLastName, string searchEmpLocation)
int pageSize = 10;
int pageNumber = (page??1);
var emp_master = db.Emp_Master.Include(l => l.Emp_Location);
if (searchEmpFirstName != null || searchEmpLastName != null || searchEmpLocation != null)
{
page = 1;
}
else
{
searchEmpFirstName = currentFilter1;
searchEmpLastName = currentFilter2;
searchEmpLocation = currentFilter3;
}
ViewBag.CurrentFilterForEmpFirstName = searchEmpFirstName;
ViewBag.CurrentFilterForEmpLastName = searchEmpLastName;
ViewBag.CurrentFilterForEmpLocation = searchEmpLocation;
if(!String.IsNullOrEmpty(searchEmpFirstName))
{
emp = emp.Where(s => s.ModelName == searchEmpFirstName)
}
if(!String.IsNullOrEmpty(searchEmpLastName))
{
emp = emp.Where(s => s.ModelName == searchEmpLastName)
}
if(!String.IsNullOrEmpty(searchEmpLocation))
{
emp = emp.Where(s => s.ModelName == searchEmpLocation)
}
I've created a dropdown to filter results. This works great the 1st time, but if the user selects another option it filters on the filtered results. Is there a way to clear the results before it filters again?
RAZOR
#using (Html.BeginForm("Index", "Admin", FormMethod.Get))
{
#Html.DropDownList("category", (SelectList)ViewBag.Categories, "--Select One--")
<input type="submit" value="Filter" />
}
Server code
public ViewResult Index(string category, int page = 1)
{
var categoryList = categoriesRepository.Categories.Select(c => c.CategoryName).Distinct();
ViewBag.Categories = new SelectList(categoryList.AsEnumerable());
var viewModel = new ProductsListViewModel
{
Products = repository.Products
.Where(p => category == null || p.Category == category)
.OrderBy(p => p.ProductID)
.Skip((page - 1) * PageSize)
.Take(PageSize),
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = category == null
? repository.Products.Count()
: repository.Products.Where(e => e.Category == category).Count()
},
CurrentCategory = category
};
return View(viewModel);
}