Data driven Partial View - asp.net-mvc

I have a view that takes uses a model called newsModels, this uses the IpagedList, however in the same view I have added a partial view that I want to list the 10 most recent news items added to the site, I want this partial view to be included in the newsitems view as well as on other views throughout the site.
What is the best way to do this. I have only succeeded in listing the titles of the newsitems that the IpagedList is showing so not quite right still.
I assume I will need to create a separate controller for the partial view but I just cant find any guidance on how to do this.
can any one offer any advice / guidance
//Models
public class partialNewsMenu
{
public IEnumerable<NewsModels> newsTitle { get; set; }
}
public class NewsModels
{
public int id { get; set; }
public string newsTitle { get; set; }
[AllowHtml]
public string newsDesc { get; set; }
public string imagePath { get; set; }
public string addedBy { get; set; }
public DateTime dateAdded { get; set; }
public bool publishNewsItem { get; set; }
}
//Controller
public ActionResult OpsiumNews(string sortby, int? page)
{
ViewBag.ImageName = "MSLOffice.jpg";
ViewBag.ImageDesc = "Opsium News";
ViewBag.OverlayText = "N/A";
ViewBag.pageTitle = "Opsium News";
ViewBag.Title = "Opsium | News";
if (sortby == null)
{
ViewBag.MostRecent = "Selected";
}
else
{
ViewBag.MostRecent = "";
}
ViewBag.Oldest = "";
ViewBag.PostedBy = "";
ViewBag.ListNewsModels = new SelectList(db.NewsModels, "Id", "newsTitle");
var NewsModelsList = db.NewsModels.Select(s => s.newsTitle);//.Where(s => s.publishNewsItem);
var NewsModels = db.NewsModels.Where(c => c.publishNewsItem);
switch (sortby)
{
case "1":
NewsModels = NewsModels.OrderBy(s => s.dateAdded);
ViewBag.MostRecent = "Selected";
break;
case "2":
NewsModels = NewsModels.OrderByDescending(s => s.dateAdded);
ViewBag.Oldest = "Selected";
break;
case "3":
NewsModels = NewsModels.OrderBy(s => s.addedBy);
ViewBag.PostedBy = "Selected";
break;
default: // Name ascending
NewsModels = NewsModels.OrderBy(s => s.dateAdded);
ViewBag.MostRecent = "Selected";
break;
}
ViewBag.currentsort = sortby;
int pageSize = 1;
int pageNumber = (page ?? 1);
return View("OpsiumNews", NewsModels.ToPagedList(pageNumber, pageSize));
}
//View
#model PagedList.IPagedList<Opsium_website.Models.NewsModels>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
<div class="Sub-content" id="containcontent">
<div class="rightSideHeader">
<div class="container">
<div class="row">
<div class="col-md-15 addBottomMargin">
#using (Html.BeginForm("OpsiumNews", "UsefulInformation", FormMethod.Get))
{
foreach (var item in Model)
{
<p>
Order by
<select name="sortby" id="sortby" onchange="submit();">
<option value="1" #ViewBag.MostRecent>Most Recent</option>
<option value="2" #ViewBag.Oldest>Oldest</option>
<option value="3" #ViewBag.PostedBy>Posted by</option>
</select>
</p>
<div class="col-md-9 addBottomMargin" id="contentText">
<h3>#Html.DisplayFor(model => item.newsTitle)</h3>
<img src="~/Images/NewsImages/#Html.DisplayFor(model => item.imagePath)" alt="#Html.DisplayFor(model => item.newsTitle)" id="newsImage"/>
#MvcHtmlString.Create(item.newsDesc)
<p><b>Date Added:</b>#String.Format("{0:F}", item.dateAdded) - <b>Added By:</b> #Html.DisplayFor(model => item.addedBy)</p>
</div>
}
}
<div class="col-md-2 addBottomMargin" id="contentText">
#{Html.RenderPartial("_NewsTitlesList");}
</div>
<div class="col-md-9 addBottomMargin">
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("OpsiumNews",
new { page, sortby = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
</div>
</div>
</div>
</div>
</div>
</div>
//Partial View
#model IEnumerable<Opsium_website.Models.partialNewsMenu>
#using PagedList.Mvc;
#foreach(var items in Model){
#Html.DisplayFor(model=>items.newsTitle)
}
//error
The model item passed into the dictionary is of type 'PagedList.PagedList1[Opsium_website.Models.NewsModels]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[Opsium_website.Models.partialNewsMenu]'.

Related

Binding in Razor returns null (OnPostAsync)

In the code below, we all values in QuestionViewModel are null. Any ideas what I am doing wrong about binding?
cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using VerityLearn.DataAccess;
using VerityLearn.Domain;
using VerityLearn.DataAccess.UOW;
using VerityLearn.WebUI.ViewModels;
namespace VerityLearn.WebUI.Pages.Questions
{
[Authorize]
public class StudentQuestionsModel : PageModel
{
private readonly SignInManager<VerityUser> _signInManager;
private readonly UserManager<VerityUser> _userManager;
private readonly IStudentQuesionsUOW _studentQuesionsUOW;
private readonly VerityLearn.DataAccess.VerityContext _context;
public StudentQuestionsModel(
VerityContext context,
SignInManager<VerityUser> signInManager,
UserManager<VerityUser> userMrg,
IStudentQuesionsUOW studentQuesionsUOW
)
{
_context = context;
_signInManager = signInManager;
_userManager = userMrg;
_studentQuesionsUOW = studentQuesionsUOW;
} // end public StudentQuestionsModel(VerityContext context, SignInManager<VerityUser> signInManager, UserManager<VerityUser> userMrg)
#region User Properties
public VerityUser VerityUser { get; set; }
//[TempData]
//public string UserId { get; set; }
public Student Student { get; set; }
public Prospect Prospect { get; set; }
public Parent Parent { get; set; }
public ExamUserViewModel ExamUserViewModel { get; set; }
#endregion // User Properties
public DateTime DateStarted { get; set; }
public Exam Exam { get; set; }
[TempData]
public int ExamId { get; set; }
ExamQuestion ExamQuestion { get; set; }
public List<ExamQuestion> ExamQuestions { get; set; }
[TempData]
public int NbrOfExamQuestions { get; set; }
public ExamViewModel ExamViewModel { get; set; }
[TempData]
public int QuestionNdx { get; set; }
[BindProperty]
public QuestionViewModel QuestionViewModel { get; set; }
[ViewData]
public string Message { get; set; }
[BindProperty]
public Question Question { get; set; }
public async Task OnGetAsync(int? examId, int? questionNdx)
{
Message = string.Empty;
if (_signInManager.IsSignedIn(HttpContext.User))
{
string email = HttpContext.User.Identity.Name;
VerityUser = await _studentQuesionsUOW.GetVerityUser(email);
//UserId = VerityUser.Id.ToString();
// TODO: Setup priorities of setting Student, Prospect and Parent properties, might involve Enrollments 4/30/2020
//Student = await _context.Students.Where(s => s.UserId == VerityUser.Id).FirstOrDefaultAsync<Student>();
//Prospect = await _context.Prospects.Where(p => p.UserId == VerityUser.Id).FirstOrDefaultAsync<Prospect>();
//Parent = await _context.Parents.Where(p => p.UserId == VerityUser.Id).FirstOrDefaultAsync<Parent>();
DateStarted = DateTime.Now;
if ((examId != null) && (examId.Value > 0))
{
ExamId = examId.Value;
Exam = await _context.Exams.Where(e => e.ExamId == examId)
.Include(e => e.Course).ThenInclude(c => c.Subject).FirstOrDefaultAsync<Exam>();
if (Exam != null)
{
ExamUserViewModel = new ExamUserViewModel
{
ExamUserId = 0,
ExamId = Exam.ExamId,
TimeStarted = DateTime.Now,
Status = ExamUserStatus.InProgress,
StudentId = VerityUser.StudentId,
ProspectId = VerityUser.ProspectId,
ParentId = VerityUser.ParentId
};
// TODO: If this is a new ExamUser, we must insert it to VerityLearnDB2.ExamUsers
if (NbrOfExamQuestions == 0)
{
ExamQuestions = await _context.ExamQuestions
.Where(eq => eq.ExamId == examId)
.ToListAsync<ExamQuestion>();
NbrOfExamQuestions = ExamQuestions.Count;
TempData.Keep("NbrOfExamQuestions");
} // endif (NbrOfExamQuestions == 0)
if ((questionNdx == null) || (questionNdx.Value == 0))
{
questionNdx = 1;
} // endif ((questionNdx == null) || (questionNdx.Value == 0))
QuestionNdx = questionNdx.Value;
TempData.Keep("QuestionNdx");
ExamQuestion = await _context.ExamQuestions
.Include(eq => eq.Question)
.ThenInclude(q => q.Options)
.Where(eq => eq.ExamQuestionOrder == questionNdx)
.FirstOrDefaultAsync<ExamQuestion>();
QuestionViewModel = new QuestionViewModel
{
QuestionId = ExamQuestion.QuestionId,
ExamQuestionOrder = ExamQuestion.ExamQuestionOrder,
QuestionText = ExamQuestion.Question.QuestionText,
IsSingleSelection = ExamQuestion.Question.IsSingleSelection,
Options = new List<OptionViewModel>()
};
ExamViewModel = new ExamViewModel
{
ExamId = Exam.ExamId,
ExamName = Exam.ExamName,
Questions = new List<QuestionViewModel>()
};
ExamViewModel.Questions.Add(QuestionViewModel);
ExamViewModel.ExamUserViewModel = ExamUserViewModel;
List<AnswerOption> answerOptions = _context.AnswerOptions
.Where(ao => ao.QuestionId == ExamQuestion.QuestionId)
.ToList<AnswerOption>();
foreach (AnswerOption ao in answerOptions)
{
OptionViewModel ovm = new OptionViewModel
{
OptionId = ao.OptionId,
OptionText = ao.OptionText,
IsCorrect = ao.IsCorrect
};
ovm.UserExamOptionViewModel = new UserExamOptionViewModel
{
UserExamOptionId = ExamUserViewModel.ExamUserId,
UserExamId = 0,
OptionId = ao.OptionId,
IsSelected = false
};
QuestionViewModel.Options.Add(ovm);
}
}
else
{
Message = String.Format("Error: Exam with Identifier, {0}, was not found.", examId);
}
}
else
{
Message = String.Format("Error: Exam with Identifier, {0}, was not found.", examId);
}
}
else
{
Message = "Error: Login is required.";
}
}
public async Task<IActionResult> OnPostAsync(QuestionViewModel QuestionViewModel)
{
var t = QuestionViewModel;
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Question).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
}
return RedirectToPage("./Index");
}
}
}
cshtml file:
#page "{examId:int?}"
#model VerityLearn.WebUI.Pages.Questions.StudentQuestionsModel
#{
ViewData["Title"] = "StudentQuestions";
}
#if (String.IsNullOrEmpty(#Model.Message))
{
<div class="row" style="background-color: #5D2685; color: #FFFF80;">
<div class="col-md-6">
<h4>Exam: #Html.DisplayFor(model => model.Exam.ExamName)</h4>
</div>
<div class="col-md-6">
<h4>Course: #Html.DisplayFor(model => model.Exam.Course.CourseName)</h4>
</div>
</div>
<br />
<br />
<div>
<h4>Question</h4>
<hr />
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Question.QuestionId" />
<div class="form-group">
<label asp-for="Question.QuestionText" class="control-label"></label>
<input asp-for="Question.QuestionText" class="form-control" />
<span asp-validation-for="Question.QuestionText" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Question.KeyToAnswer" class="control-label"></label>
<input asp-for="Question.KeyToAnswer" class="form-control" />
<span asp-validation-for="Question.KeyToAnswer" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Question.IsSingleSelection" class="control-label"></label>
<input asp-for="Question.IsSingleSelection" class="form-control" />
<span asp-validation-for="Question.IsSingleSelection" class="text-danger"></span>
</div>
<label asp-for="QuestionViewModel.QuestionText" class="control-label"></label>
#if (Model.QuestionViewModel.IsSingleSelection.Value)
{
<p>Select the correct option.</p>
#foreach (OptionViewModel opt in Model.QuestionViewModel.Options)
{
<input type="radio" name="option" value="#opt.UserExamOptionViewModel.IsSelected"><label for=" #opt.OptionText"> #opt.OptionText </label><br />
}
}
else
{
<p>Select the correct options (More than one).</p>
#foreach (OptionViewModel opt in Model.QuestionViewModel.Options)
{
<input type="checkbox" name="option" value="#opt.UserExamOptionViewModel.IsSelected"><label for=" #opt.OptionText"> #opt.OptionText </label><br />
}
}
#{
var prevDisabled = (Model.QuestionNdx <= 1) ? "disabled" : "";
var nextDisabled = (Model.QuestionNdx >= Model.NbrOfExamQuestions) ? "disabled" : "";
}
<button type="submit" asp-route-questionIndex="#(Model.QuestionNdx - 1)" class="btn btn-primary #prevDisabled">Previous</button>
<button type="submit" asp-route-questionIndex="#(Model.QuestionNdx + 1)" class="btn btn-primary #nextDisabled">Next</button>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
}
else
{
<div class="row" style="background-color: #5D2685; color: #FFFF80;">
<div class="col-md-6">
<h4>#Model.Message</h4>
</div>
</div>
}
UPDATE (5/11/2020):
I have simplified the view like this:
#foreach(OptionViewModel opt in Model.QuestionViewModel.Options)
{
optionIndex++;
#Html.RadioButtonFor(model => model.QuestionViewModel.Options[optionIndex].OptionText, #opt.OptionText);
#opt.OptionText<br />
}
I see 4 options but all of them are selected. I would expect only one radio button to be selected at a time. I click Next anyway
I now see the option texts are bound. Question: How to figure out which one is selected?
The problem is you are using a complex model, but your HTML does not indicate that the model is complex. I have created a demo to highlight the issue:
Here Student contains Address and List<Subject> (it is complex model)
public class Subject
{
public string SubjectName { get; set; }
}
public class Address
{
public string StreetAddress { get; set; }
}
public class Student
{
public string Name { get; set; }
public Address HomeAddress { get; set; }
public List<Subject> Subjects { get; set; }
}
When displaying a complex model in a form, you need to use the entire model in the html input tag, this way ASP.NET MVC ModelBinder knows how to bind your HTML inputs to your server-side model.
The above demo has 3 inputs, I am using HTML.TextBoxFor which is the older equivalent of asp-for Tag Helper.
Input 1:
#Html.TextBoxFor(model => model.Name)
Generates the following HTML:
<input id="Name" name="Name" type="text" value="John Smith">
Model binder uses name and binds the above input to Student.Name
Input 2
#Html.TextBoxFor(model => model.HomeAddress.StreetAddress)
Generates the following HTML:
<input id="HomeAddress_StreetAddress" name="HomeAddress.StreetAddress" type="text" value="some address">
Here Model binder knows that this input should be bound to Student.HomeAddress.StreetAddress because that's what the input name indicates
Input 3
#Html.TextBoxFor(model => model.Subjects[0].SubjectName)
Generates the following HTML:
<input id="Subjects_0__SubjectName" name="Subjects[0].SubjectName" type="text" value="Math">
Model binder will bind the above input to Student.Subjects[0].SubjectName
See this article for more info.
In your example, Model Binder has no way to know that option belongs to QuestionViewModel.Options because you are not indicating it in the input name:
<input type="checkbox" name="option" value="#opt.UserExamOptionViewModel.IsSelected">
Make sure you're using [BindProperty] attribute.

How can i take many textboxes' value on Post in MVC

i have a problem about MVC, but first I am sorry for my english :D .
Now i am trying to make a form for users and i have a critical issue when i want connect to values with database.
My Form is like this : https://i.hizliresim.com/vJ6r2p.png
Models :
[Table("Testers")]
public class Testers
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[StringLength(50),Required]
public string testerName { get; set; }
public ICollection<Scores> Scores { get; set; }
}
[Table("Technologies")]
public class Technologies
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[StringLength(50)]
public string technologyName { get; set; }
[StringLength(50)]
public string type { get; set; }
}
[Table("Scores")]
public class Scores
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[DefaultValue(0)]
public int score { get; set; }
public virtual Testers tester { get; set; }
public virtual Technologies technology { get; set; }
}
ViewModels:
public class TechnologiesView
{
public List<Technologies> Technologies { get; set; }
public Scores Scores { get; set; }
}
Controller :
public ActionResult Page2()
{
TechnologiesView allTechs = new TechnologiesView();
allTechs.Technologies = db.Technologies.ToList();
return View(allTechs);
}
View:
#model TechnologiesView
#{
ViewBag.Title = "Page2";
}
<style>
#lang {
font-size: 15px;
color: gray;
}
#tech {
font-size: 13px;
color: gray;
}
</style>
<div class="container">
<div class="row col-xs-12 bilgi" style="color:black">
#HelperMethods.Title("Kendini Skorla!")
<br />
<i>Bilgi Düzeyini 0 ile 5 puan arasında notlar mısın? (0=Hiç 5= İleri Seviye)</i>
</div>
</div>
<hr />
#using (Html.BeginForm())
{
<div class="container-fluid" style="padding-left:50px; margin:0px">
<div class="row" id="lang">
#foreach (Technologies techs in Model.Technologies)
{
if (techs.type == "lang")
{
<div class="col-md-1 col-sm-2 col-xs-6">
#(techs.technologyName)
</div>
<div class="col-md-1 col-sm-2 col-xs-6">
(#(Html.TextBoxFor(x => x.Scores.score, new
{
id = techs.ID,
name = "techID",
style = "display:inline; width:20px; height:20px; font-size:smaller; padding:0px; text-align:center",
#class = "form-control"
})))
</div>
}
}
</div>
<hr style="color:black" />
<div class="row" id="tech">
#foreach (Technologies techs in Model.Technologies)
{
if (techs.type == "tech")
{
<div class="col-md-1 col-sm-2 col-xs-6" id="tech">
#(techs.technologyName)
</div>
<div class="col-md-1 col-sm-2 col-xs-6">
#Html.HiddenFor(x=>techs.ID)
(#(Html.TextBoxFor(x => x.Scores.score, new
{
id = techs.ID,
name = "techID",
style = "display:inline; width:20px; height:20px; font-size:smaller; padding:0px; text-align:center",
#class = "form-control"
})))
</div>
}
}
</div>
<hr />
<div class="row col-xs-12" id="lang">
<span>Kullandığınız IDE’ler (yazınız)</span>
<br />
<div style="margin-bottom:10px; text-align:center">
#HelperMethods.TextArea("Ide", 3)
</div>
</div>
<div style="text-align:right; margin-bottom:10px">
#HelperMethods.Button("btnPage2")
</div>
</div>
}
Now user has to give a score to him/herself for every technologies or languages and after this i want to when user click to button "Follow the next page(it's turkish)" i will select the last saved user from maxID value in Testers and i have to connect scores with technologies and testers but i don't know how can i get textboxes' values and which technology's value is this value on post :D
You generating form controls which have no relationship at all to your model (which is also wrong anyway). Never attempt to change the name attribute when using the HtmlHelper methods (and there is no reason to change the id attribute either)
Next, you cannot use a foreach loop to generate form controls for a collection. You need a for loop or EditorTemplate to generate the correct name attributes with indexers. Refer this answer for a detailed explanation.
Then you cannot use a if block inside the loop (unless you include a hidden input for the collection indexer), because by default the DefaultModelBinder required collection indexers to start at zero and be consecutive.
First start by creating view models to represent what your want to display/edit in the view.
public class ScoreVM
{
public int ID { get; set; }
public string Name { get; set; }
public int Score { get; set; }
}
public class TechnologiesVM
{
public List<ScoreVM> Languages { get; set; }
public List<ScoreVM> Technologies { get; set; }
public string Notes { get; set; } // for your textarea control
}
Note you will probably want to add validation attributes such as a [Range] attribute for the Score property
In the GET method, initialize and populate your view model and pass it to the view
public ActionResult Page2()
{
IEnumerable<Technologies> technologies = db.Technologies;
TechnologiesVM model = new TechnologiesVM
{
Languages = technologies.Where(x => x.type == "lang")
.Select(x => new ScoreVM{ ID = x.ID, Name = x.technologyName }).ToList(),
Technologies = technologies.Where(x => x.type == "tech")
.Select(x => new ScoreVM{ ID = x.ID, Name = x.technologyName }).ToList(),
};
return View(model);
}
and in the view
#model TechnologiesVM
....
#using (Html.BeginForm())
{
....
#for (int i = 0; i < Model.Languages.Count; i++)
{
#Html.HiddenFor(m => m.Languages[i].ID)
#Html.HiddenFor(m => m.Languages[i].Name)
#Html.LabelFor(m => m.Languages[i].Score, Model.Languages[i].Name)
#Html.TextBoxFor(m => m.Languages[i].Score)
#Html.ValidationMessageFor(m => m.Languages[i].Score)
}
#for (int i = 0; i < Model.Languages.Count; i++)
{
.... // repeat above
}
#Html.LabelFor(m => m.Notes)
#Html.TextAreaFor(m => m.Notes)
#Html.ValidationMessageFor(m => m.Notes)
<input type="submit" />
}
and the POST method will be
public ActionResult Page2(TechnologiesVM model)
{
if (!ModelState.IsValid)
{
return View(model);
}
... // save the data and redirect
}

#Html.DropDownListFor and #HtmlPagedListPager

I've created an MVC website using VS2013. My view contains a a dropdownlist for "Import Status" and a paging control as shown below:
My view is as follows:
#model PagedList.IPagedList<ESBAMPortal.Models.SupplierStockUpdateViewModel>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet"
type="text/css" />
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
SelectList itemsPerPageList = ESBAMPortal.Helpers.DefaultValues.ItemsPerPageList;
}
<h2>Stock Updates</h2>
<div class="container-fluid">
<div class="row">
<div id="instruction" class="col-md-6 pull-left">
<h5>Click the 'Process Start' datetime to see a copy of the file received</h5>
</div>
</div>
<div class="row" id="filters">
<div id="filtersDropdown" class="col-md-6 pull-right">
#using (Html.BeginForm("Index", "SupplierStockUpdate", FormMethod.Get, new { #class = "pull-right" }))
{
{
<span>
#Html.Label("Import Status:")
#Html.DropDownListFor(m => m.FirstOrDefault().SelectedStatusId, Model.FirstOrDefault().StatusItems)
</span>
<span>
#Html.Label("Items per page:")
#Html.DropDownList("ItemsPerPage", itemsPerPageList,
new { #id = "ItemsPerPageList" })
</span>
}
<input type="submit" value="Refresh" />
}
</div>
</div>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().ReceivedFilename)</th>
<th>#Html.ActionLink("Proces Start", "Index", new { sortOrder = ViewBag.TimeReceivedSort, itemsPerPage = itemsPerPageList.SelectedValue })</th>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().TimeProductLookupResponse)</th>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().TimeInsertResponse)</th>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().ImportStatus)</th>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().ImportErrors)</th>
<th>#Html.ActionLink("Supplier", "Index", new { sortOrder = ViewBag.SupplierSort })</th>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().RowsInserted)</th>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().TimeOfExceptionString)</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(model => item.ReceivedFilename)</td>
<td>
#Html.ActionLink(item.TimeReceived.ToString(), "Index", "ArchivedMsg",
new { interchangeId = item.InterchangeId }, null)
</td>
<td>#Html.DisplayFor(model => item.TimeProductLookupResponse)</td>
<td>#Html.DisplayFor(model => item.TimeInsertResponse)</td>
<td>#Html.DisplayFor(model => item.ImportStatus)</td>
<td>#Html.DisplayFor(model => item.ImportErrors)</td>
<td>#Html.DisplayFor(model => item.SupplierCode)</td>
<td>#Html.DisplayFor(model => item.RowsInserted)</td>
#{
if (item.TimeOfExceptionString.IsDateTime())
{
<td>#Html.ActionLink(item.TimeOfExceptionString, "IndexForInterchangeId", "Fault", new { interchangeId = item.InterchangeId }, null) </td>
}
else
{
<td>NA</td>
}
}
</tr>
}
</tbody>
</table>
<div id="pageControllFooter" class="container-fluid">
<div class="row">
<div id="pageButtons" class="col-md-2">
#Html.PagedListPager(Model, page => Url.Action("Index", new { page, itemsPerPage = ViewBag.CurrentItemsPerPage }))
</div>
</div>
<div class="row">
<div id="pageDesc" class="col-md-2">
#if (Model != null
&& Model.PageCount > 0)
{
<div>
Page #(Model.PageCount < Model.PageNumber
? 0 : Model.PageNumber)
of #Model.PageCount
</div>
}
</div>
</div>
</div>
Model:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ESBAMPortal.Models
{
public class SupplierStockUpdateViewModel
{
public string ActivityID { get; set; }
public string InterchangeId { get; set; }
[DisplayName("Received")]
public DateTime? TimeReceived { get; set; }
[DisplayName("DW Product Requested")]
public DateTime? TimeProductLookupRequested { get; set; }
[DisplayName("DW Product Response")]
public DateTime? TimeProductLookupResponse { get; set; }
[DisplayName("CIMS Insert Requested")]
public DateTime? TimeInsertRequested { get; set; }
[DisplayName("CIMS Insert Response")]
public DateTime? TimeInsertResponse { get; set; }
[DisplayName("Supplier Code")]
public string SupplierCode { get; set; }
[DisplayName("CIMS Records Updated")]
public int? RowsInserted { get; set; }
public string ReceivedFilename { get; set; }
public DateTime? TimeOfException { get; set; }
public string TimeOfExceptionString { get; set; }
public double TotalDuration { get; set; }
public string ImportStatus { get; set; }
public int? ImportErrors { get; set; }
public DateTime LastModified { get; set; }
//constructor
public SupplierStockUpdateViewModel()
{
_statuses = new List<Status>();
_statuses.Add(new Status()
{
Id = 1,
Name = "All"
});
_statuses.Add(new Status()
{
Id = 2,
Name = "Pending"
});
_statuses.Add(new Status()
{
Id = 3,
Name = "Complete"
});
}
private readonly List<Status> _statuses;
public class Status
{
public int Id { get; set; }
public string Name { get; set; }
}
[Display(Name = "Status")]
public int SelectedStatusId { get; set; }
//our VM has a select list
public IEnumerable<SelectListItem> StatusItems
{
get { return new SelectList(_statuses, "Id", "Name"); }
}
}
}
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ESBAMPortal.DataLayer;
using ESBAMPortal.Models;
using PagedList;
using ESBAMPortal.DomainClasses.BAM;
using System.IO;
namespace ESBAMPortal.Controllers
{
public class SupplierStockUpdateController : Controller
{
private IRepository<SupplierStockUpdate> SupplierStockUpdateRepository;
public SupplierStockUpdateController(BAMContext context)
{
this.SupplierStockUpdateRepository = new EFRepository<SupplierStockUpdate>(context);
}
private string TranslateStatusFilter(int status)
{
string ret = "";
switch (status)
{
case 2:
ret = "Pending";
break;
case 3:
ret = "Complete";
break;
}
return ret;
}
// GET: /SupplierStock/
public ActionResult Index(string sortOrder, int? page, int? itemsPerPage, SupplierStockUpdateViewModel vm)
{
string statusFilter = TranslateStatusFilter(vm.SelectedStatusId);
ViewBag.CurrentItemsPerPage = itemsPerPage;
ViewBag.TimeReceivedSort = String.IsNullOrEmpty(sortOrder) ? "timeReceived" : "";
ViewBag.SupplierSort = sortOrder == "supplier" ? "supplier_desc" : "supplier";
var query = this.SupplierStockUpdateRepository.GetAll();
switch (sortOrder)
{
case "timeReceived":
query = query.OrderBy(f => f.TimeReceived);
break;
case "supplier":
query = query.OrderBy(f => f.SupplierCode);
break;
case "supplier_desc":
query = query.OrderByDescending(f => f.SupplierCode);
break;
default:
query = query.OrderByDescending(f => f.TimeReceived);
break;
}
if (statusFilter == "Pending" || statusFilter == "Complete")
{
query = query.Where(x => x.ImportStatus == statusFilter);
}
//shove results into view model
List<SupplierStockUpdateViewModel> SupplierStockUpdatesVM = new List<SupplierStockUpdateViewModel>();
DateTime start = new DateTime();
DateTime end = new DateTime();
foreach (var item in query.ToList())
{
SupplierStockUpdateViewModel SupplierStockUpdateVM = new SupplierStockUpdateViewModel();
SupplierStockUpdateVM.ActivityID = item.ActivityID;
SupplierStockUpdateVM.InterchangeId = item.InterchangeId;
SupplierStockUpdateVM.TimeReceived = item.TimeReceived;
SupplierStockUpdateVM.TimeProductLookupRequested = item.TimeProductLookupRequested;
SupplierStockUpdateVM.TimeProductLookupResponse = item.TimeProductLookupResponse;
SupplierStockUpdateVM.TimeInsertRequested = item.TimeInsertRequested;
SupplierStockUpdateVM.TimeInsertResponse = item.TimeInsertResponse;
SupplierStockUpdateVM.SupplierCode = item.SupplierCode;
SupplierStockUpdateVM.RowsInserted = item.RowsInserted;
SupplierStockUpdateVM.TimeOfException = item.TimeOfException;
SupplierStockUpdateVM.ReceivedFilename = item.ReceivedFilename;
SupplierStockUpdateVM.ImportStatus = item.ImportStatus;
SupplierStockUpdateVM.ImportErrors = item.ImportErrors;
start = (item.TimeReceived == null) ? DateTime.MinValue : (System.DateTime)item.TimeReceived;
if (item.TimeOfException == null)
{
SupplierStockUpdateVM.TimeOfExceptionString = "NA";
if (item.TimeInsertResponse != null)
{
end = (System.DateTime)item.TimeInsertResponse;
}
else
{
//no exception but process still running so give a duration of 0
end = start;
}
}
else
{
SupplierStockUpdateVM.TimeOfExceptionString = item.TimeOfException.ToString();
end = (System.DateTime)item.TimeOfException;
}
if (start == DateTime.MinValue)
{
SupplierStockUpdateVM.TotalDuration = 0;
}
else
{
SupplierStockUpdateVM.TotalDuration = (end - start).TotalSeconds;
}
SupplierStockUpdatesVM.Add(SupplierStockUpdateVM);
}
int pageSize = (itemsPerPage ?? 10);
int pageNumber = (page ?? 1);
return View(SupplierStockUpdatesVM.ToPagedList(pageNumber, pageSize));
}
}
}
On clicking the "Refesh" button all works ok, the filtered Import Status is passed to the controller. My problem is, when paging by clicking the boxes of the page controls, the value 0 is always passed in the VM.SelectedStatusId field.
I've tried changing the view's call to explicitly pass the SelectedStatusId as follows:
#Html.PagedListPager(Model, page => Url.Action("Index", new { page, itemsPerPage = ViewBag.CurrentItemsPerPage, Model.FirstOrDefault().SelectedStatusId }))
...and adding a corrsponding int param on the controller action but still this was coming through as 0.
Could anyone let me know where I'm going wrong? Thanks.
Upon first look, it seems you have coded the following line wrong.
#Html.PagedListPager(Model, page => Url.Action("Index", new { page, itemsPerPage = ViewBag.CurrentItemsPerPage, Model.FirstOrDefault().SelectedStatusId }))
You have forgotten the return parameter for the last parameter in you expression. Try the following
#Html.PagedListPager(Model, page => Url.Action("Index", new { page, itemsPerPage = ViewBag.CurrentItemsPerPage, vm = Model.FirstOrDefault().SelectedStatusId }))
note the "vm = "
Let me know if that works!
The vm.SelectedStatusId is passed into the action when the user clicks the "Refresh" button on the view.
I assign the selected status to a viewbag property in the Index action of the controller:
ViewBag.StatusId = vm.SelectedStatusId;
When the user later pages through the results, I pass in the previously selected status filter, from the viewbag:
#Html.PagedListPager(Model, page => Url.Action("Index", new { page, itemsPerPage = ViewBag.CurrentItemsPerPage, selectedStatusId = ViewBag.StatusId }))

IEnumerable Property can't return the value

I have ViewModel
public class Magazine_ViewModel
{
public int MagId { get; set; }
public string MagNo { get; set; }
public IEnumerable<Titles_ViewModel> Titles { get; set; }
}
public class Titles_ViewModel
{
public int TitleId { get; set; }
public string TitleName { get; set; }
public int pos { get; set; }
}
in Controller i do like this
var viewModel = new Magazine_ViewModel
{
Titles = numberTitles
.Select(c => new Titles_ViewModel
{
TitleId = c.TitleId,
TitleName = c.Title.TitleText,
pos=c.position
}).ToList()
};
viewModel.MagNo = magazine.MagNo.ToString();
viewModel.MagId = magazine.Id;
when i check viewModel.Titles has n records which is right.
now in the view part
<div class="editor-label">
#Html.LabelFor(model => model.MagNo)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MagNo)
</div>
<div class="editor-field">
#Html.ListBox("wholeTitles")
<input type="button" name="add" id="add" value="add" onclick="addValue()" /><input type="button" name="remove" id="remove" value="remove" onclick="removeValue()"/>
#Html.ListBoxFor(model => model.Titles, new SelectList(Model.Titles, "TitleId", "TitleName"))
</div>
<p>
<input type="submit" value="Save" />
</p>
I add new Titles from first ListBox(wholeTitles) to second ListBox(Titles). Now the submit button is press and i want to add the new Titles to the database.
This is what i do in Post Action
[HttpPost]
public ActionResult EditTitle(Magazine_ViewModel magazineViewModel)
{
if (ModelState.IsValid)
{
var magazineTitles = new Magazine
{
Id = magazineViewModel.MagId,
NumberTitles = new List<NumberTitle>()
};
foreach (var numberTitle in magazineViewModel.Titles)
{
NumberTitle newNumberTitle = new NumberTitle();
newNumberTitle.MagazineId = magazineViewModel.MagId;
newNumberTitle.TitleId = numberTitle.TitleId;
newNumberTitle.position = 0;
unitOfWork.NumberTitleRepository.Insert(newNumberTitle);
}
}
return View();
}
but magazineViewModel.Titles shows null, I don't know what should I check to see why it is null value.
Your values not get posted back to the server. Use below in your View. This should post the titles back to the Server within the same ViewModel
for (var i = 0; i < Model.Titles.Count(); i++)
{
#Html.HiddenFor(m => m.Titles[i].TitleId)
#Html.HiddenFor(m => m.Titles[i].TitleName)
}

MVC 4 Model Binding to Radio button list on Submit

My project is MVC 4 with jquery mobile. I'm trying to figure out how to fill my model with data on submit with the following:
From a hidden value that will be populated on the get request
Checked Radio button value from a list on the view
Here is my Model:
public class ResultsModel
{
[Display(Name = "PatientFirstName")]
public string PatientFirstName { get; set; }
[Display(Name = "PatientLastName")]
public string PatientLastName { get; set; }
[Display(Name = "PatientMI")]
public string PatientMI { get; set; }
public List<QuestionModel> QuestionList = new List<QuestionModel>();
}
public class QuestionModel
{
public string Question { get; set; }
public int QuestionID { get; set; }
public int AnswerID { get; set; }
}
It has a collection of questions that is filled with data on the get request. Here is the controller code:
public class ResultsController : Controller
{
//
// GET: /Results/
public ActionResult Index()
{
if (Request.IsAuthenticated)
{
ResultsModel resultsModel = new ResultsModel();
//Get data from webservice
myWebService.TestForm inrform;
var service = new myWebService.myService();
testform = service.TestForm(id);
if (testform != null)
{
//Render the data into results data model
int count = 1;
string text = string.Empty;
foreach (myWebService.Question questiontext in testform.QuestionList)
{
QuestionModel newquestion = new QuestionModel();
text = "Question " + count + ": " + questiontext.text;
if (questiontext.text != null)
{
newquestion.Question = text;
newquestion.QuestionID = questiontext.id;
}
resultsModel.QuestionList.Add(newquestion);
count += 1;
}
}
else
{
//Error
}
return View(resultsModel);
}
// Error
return View();
}
[AllowAnonymous]
[HttpPost]
public ActionResult Index(ResultsModel model,FormCollection fc)
{
if (fc["Cancel"] != null)
{
return RedirectToAction("Index", "Home");
}
if (ModelState.IsValid)
{
in the post action, the model.QuestionList is always empty. Here is my View:
#model Models.ResultsModel
#{
ViewBag.Title = Resources.Account.Results.Title;
}
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<li data-role="fieldcontain">
#Html.LabelFor(m => m.INRTestDate)
#Html.EditorFor(m => m.INRTestDate)
#Html.ValidationMessageFor(model => model.INRTestDate)
</li>
<li data-role="fieldcontain">
#Html.LabelFor(m => m.INRValue)
#Html.TextBoxFor(m => m.INRValue)
</li>
<li>
#for (int i = 0; i < Model.QuestionList.Count; i++)
{
<div data-role="label" name="question" >
#Model.QuestionList[i].Question</div>
#Html.HiddenFor(m => m.QuestionList[i].QuestionID)
<div data-role="fieldcontain">
<fieldset data-role="controlgroup" data-type="horizontal" data-role="fieldcontain" >
<input id="capture_type_yes" name="answer_type" type="radio" data-theme="c" value="1" />
<label for="capture_type_yes" >
Yes</label>
<input id="capture_type_no" name="answer_type" type="radio" data-theme="c" value="0" />
<label for="capture_type_no">
No</label>
<input id="capture_type_na" name="answer_type" type="radio" data-theme="c" value="2" />
<label for="capture_type_na">
Not Applicable</label>
</fieldset>
</div> }
<label for="textarea-a">
Comments</label>
<textarea name="textarea" id="textarea-a"> </textarea>
<fieldset class="ui-grid-a">
<div class="ui-block-a">
<button type="submit" name="Submit" data-theme="c">Submit</button></div>
<div class="ui-block-b">
<button type="submit" name="Cancel" data-theme="b" class="cancel">Cancel</button></div>
</fieldset>
</li>
In the for each code above, my model.Questionlist collection is not being updated. I also need to figure out how I can tie the radio button click (Yes,No or Not Applicable) to the AnswerID property of my model.Questionlist collection
It actually ended up being this line:
public List<QuestionModel> QuestionList = new List<QuestionModel>();
I needed the get/set to initialize
public List<QuestionModel> QuestionList { get; set; }
Please Can You Add Code after
[AllowAnonymous]
[HttpPost]
public ActionResult Index(ResultsModel model,FormCollection fc)
{
if (fc["Cancel"] != null)
{
return RedirectToAction("Index", "Home");
}
if (ModelState.IsValid)
{
This would be a good post if you finish your code.
MVC5 Bind a LIST for Radio Button with Razor
Create a class RadioList anywhere in the program
public class RadioList
{
public int Value { get; set; }
public string Text { get; set; }
public RadioList(int Value, string Text)
{
this.Value = Value;
this.Text = Text;
}
}
In your Controller
List<RadioList> Sexes = new List<RadioList>();
Sexes.Add(new RadioList(1, "Male"));
Sexes.Add(new RadioList(2, "Female"));
Sexes.Add(new RadioList(3, "Other"));
ViewBag.SexeListe = Sexes;
In the Razor view (replace model.Sexe by the value in your database/model field
#foreach (RadioList radioitem in ViewBag.SexeListe) {
#Html.RadioButtonFor(model => model.Sexe, #radioitem.Value) #Html.Label(#radioitem.Text)
}

Resources