how i can add second model to this view? [duplicate] - c#

This question already has answers here:
Multiple models in a view
(12 answers)
Closed 5 years ago.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
view:
#model PagedList.IPagedList<ForumIT.ViewModels.Lista>
#using ForumIT;
#using PagedList.Mvc;
#{
ViewBag.Title = "Materiały";
}
<div class="jumbotron">
<h1>Forum Dyskusyjne IT</h1><br />
<p class="lead">Forum poświęcone jest szeroko rozwiniętej dziedzinie informatyki. Przedstaw swój problem w temacie i przedyskutuj go z dużym gronem użytkowników służących pomocą</p>
</div><br /><br />
<div class="row">
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading"><h3>Tematy</h3></div>
</div>
<div class=" panel panel-default" style="padding: 10px">
<hr />
#foreach (var item in Model)
{
<div class="media">
<div class="media-left" style="padding-right: 30px">
<img class="media-object img-circle"
src="~/Graphics/Users/#((item.Foto!=null)?#item.Foto:"user.png")"
alt="zdjęcie"
width="64">
<h6><b>#item.Autor</b></h6>
</div>
<div class="media-body">
<h4 class="media-heading">
<a title="Czytaj" href="#Url.Action("Details", "Temat", new { id = item.IdTematu })">
<h1 style="margin-top: 0px">#item.Tytul</h1>
</a>
</h4>
<p style="max-width: 600px; max-height: 95px">#item.Tresc</p>
</div>
</div>
<hr />
}
</div>
<div class="row">
Strona #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) z #Model.PageCount
<div class="pull-right">
#Html.PagedListPager(Model, Page => Url.Action("Index", new { strona = Page }))
</div>
</div>
</div>
<div class="col-md-4">
<div class="list-group">
<div class="panel panel-default">
<div class="panel-heading"><h3>Kategorie</h3></div>
</div>
<a href="~/Home/index">
<button type="button" class="list-group-item">Wszystkie Kategorie</button>
</a>
#foreach (var item in Model)
{
<a href="~/Home/index/2">
<button type="button" class="list-group- item">#item.NazwaKategorii</button>
</a>
}
</div>
</div>
</div>
Controller:
using ForumIT.Models;
using ForumIT.ViewModels;
using PagedList;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ForumIT.Controllers
{
public class HomeController : Controller
{
private ForumContext db = new ForumContext();
public ActionResult Index(int? id = 0, int? rozmiar = 5, int? strona = 1)
{
IQueryable<Lista> lista = from t in db.Tematy
orderby t.DataDodania descending
select new Lista()
{
IdTematu = t.IdTematu,
Tytul = t.Tytul,
Tresc = t.Tresc,
Autor = t.Uzytkownik.Imie + " " + t.Uzytkownik.Nazwisko,
Foto = t.Uzytkownik.Foto,
IdKategorii = t.IdKategorii
};
IQueryable<Lista> lista2 = from k in db.Kategorie
select new Lista()
{
NazwaKategorii = k.NazwaKategorii,
Ikona = k.Ikona,
IdKategoriiK = k.IdKategorii
};
if (id != 0)
{
lista = lista.Where(l => l.IdKategorii == id);
}
return View(lista.ToPagedList((int)strona, (int)rozmiar));
}
i add class lista
namespace ForumIT.ViewModels
{
public class Lista
{
public int IdTematu { get; set; }
public string Tytul { get; set; }
public string Tresc { get; set; }
public string Autor { get; set; }
public string Foto { get; set; }
public int IdKategorii { get; set; }
public string NazwaKategorii { get; set; }
public string Ikona { get; set; }
public int IdKategoriiK { get; set; }
}
}

Add an additional view model like
public class MyViewModel
{
public PagedList.IPagedList<ForumIT.ViewModels.Lista> PagedList { get; set; }
public Models.SecondModel SecondModel { get; set; }
}
and then you can pass MyViewModel containing both the PagedList and the SecondModel to the view like
return View(new MyViewModel {PagedList = lista.ToPagedList((int)strona, (int)rozmiar),
SecondModel = new SecondModel()};
and in the view you would write something like
#model MyViewModel
#Model.PagedList.Count
#Model.SecondModel.YourProperty

You should merge the lists into a model class;
var indexModel = new IndexModel()
{
ListA = lista,
ListB = listb
};
return View(indexModel);
Index model;
public class IndexModel
{
public PagedList.IPagedList<ForumIT.ViewModels.Lista> ListA { get; set; }
public PagedList.IPagedList<ForumIT.ViewModels.Lista> ListB { get; set; }
}
Then change view model;
#model IndexModel

Related

The model item passed into the ViewDataDictionary is of type Error

My app may be bad I'm trying to learn
What is the solution for this error?
The error i got
Controller
I do not know exactly how to make the list, the examples I tried did not work
I guess I need to make a list somehow
public IActionResult Rooms()
{
using (var db = new HotelWebContext())
{
var roomList = db.Rooms.Where(z => z.OtherTypeId == z.OtherType.OtherTypeId && z.RoomTypeId == z.RoomType.RoomTypeId && z.StatusId == z.Status.RoomStatusId).Select(r => new { r.RoomId, r.OtherType.OtherTypeName, r.OtherType.BasePrice, r.OtherType.Capacity, r.OtherType.BedType, r.OtherType.Services, r.RoomType.RoomTypeName, r.Status.RoomStatusName }).ToList();
return View(roomList);
}
}
Model
I created it automatically with the entity framework
public partial class Room
{
public Room()
{
Reservations = new HashSet<Reservation>();
}
public int RoomId { get; set; }
public int? RoomTypeId { get; set; }
public int? OtherTypeId { get; set; }
public int? StatusId { get; set; }
public virtual OtherType OtherType { get; set; }
public virtual RoomType RoomType { get; set; }
public virtual RoomStatus Status { get; set; }
public virtual ICollection<Reservation> Reservations { get; set; }
}
Rooms.cshtml have a foreach loop
#model IEnumerable<WebApplication3.Models.Room>
#{
ViewData["Title"] = "Odalarımız";
ViewData["Dark"] = "text-dark";
ViewData["Info"] = "text-info";
}
<div class="odafiyatlari mx-auto">
<div class="odaimg">
<div class="container">
<h1 style="margin-top: 200px; margin-bottom: 200px;font-family: 'Playfair Display', serif;" class="text-center text-dark ">ODALARIMIZ</h1>
<div class="row">
<!-- #for (int i = 0; i < 0; i++)
{
<div class="col-xl-4 py-4">
<div style="border-radius: 10px;" class="card mx-auto" style="width: 18rem;">
<img class="card-img-top " src="~/images/oda1.jpg" alt="Card image cap">
<div class="card-body">
<h6 class="card-text">Durum:Uygun</h6><br>
<h5 class="card-title">İki Kişilik İkiz Yataklı Oda</h5>
<h5 class="card-title">Oda Tipi:Aile</h5>
<h6 class="card-text">399₺ / Gecelik</h6><br>
<h6 class="card-text">Kapasite: İki Kişilik</h6><br>
<h6 class="card-text">Yatak: Kral Yatak</h6><br>
<h6 class="card-text">Servis: İnternet, Televizyon, Duş</h6><br>
Odayı Seç
</div>
</div>
</div>
}-->
#foreach (var item in Model)
{
<div class="col-xl-4 py-4">
<div style="border-radius: 10px;" class="card mx-auto" style="width: 18rem;">
<img class="card-img-top " src="~/images/oda1.jpg" alt="Card image cap">
<div class="card-body">
<h6 class="card-text">Durum:#item.Status.RoomStatusName</h6><br>
<h5 class="card-title">#item.OtherType.OtherTypeName</h5>
<h5 class="card-title">Oda Tipi:#item.RoomType.RoomTypeName</h5>
<h6 class="card-text">#item.OtherType.BasePrice₺ / Gecelik</h6><br>
<h6 class="card-text">Kapasite: #item.OtherType.Capacity</h6><br>
<h6 class="card-text">Yatak: #item.OtherType.BedType</h6><br>
<h6 class="card-text">Servis: #item.OtherType.Services</h6><br>
Odayı Seç
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
<!--ODA BİTİŞ-->
Model
Your are projecting your Rooms into a new anonymous object with values by calling
.Select(r => new { r.RoomId, r.OtherType.OtherTypeName, r.OtherType.BasePrice, r.OtherType.Capacity, r.OtherType.BedType, r.OtherType.Services, r.RoomType.RoomTypeName, r.Status.RoomStatusName })
So now you got an IEnumerable of anonymous type.
But the action expects to return an IEnumerable of Rooms.
Just remove the select you should be good, since you are retrieving from rooms table.
You need use .Include() method to include the related models like below:
var model = db.Rooms
.Where(z => z.OtherTypeId == z.OtherType.OtherTypeId && z.RoomTypeId == z.RoomType.RoomTypeId && z.StatusId == z.Status.RoomStatusId)
.Include(r=>r.OtherType)
.Include(r=>r.RoomType)
.Include(r=>r.Status)
.ToList();
The List you are passing to view that should be type of Room Class.

C# MVC ViewModel One Posted Result Binds Whilst Others Are Null

I have a number of awards in my view and within each award there is a corresponding list of qualifications. I have created a ViewModel to display each award and with a click of a button a modal should appear with its relevant qualifications which can be marked as completed/updated by the user. However on the Post of the data only my first Award will bind in my controller method.The rest will comeback as Null when I debug in VS. The data is appearing in my view as expected with each Award only showing its relevant qualifications. Thanks in advance for helping with this.
ViewModel
public class CandidateExtended
{
public CandidateExtended()
{
this.Qualifications = new List<Qualification_Extended>();
}
public int AwardID { get; set; }
public int FrameworkID { get; set; }
public string ULN { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string TitleShort { get; set; }
public string TitleFull { get; set; }
public DateTime DOB { get; set; }
public string Award { get; set; }
public int AwardLevel { get; set; }
public string Status { get; set; }
public string Completion { get; set; }
public string SelectedRoute { get; set; }
public List<Qualification_Extended> Qualifications { get; set; }
public void addQualification(Qualification_Extended qualification)
{
Qualifications.Add(qualification);
}
}
Controller
[HttpGet]
public ActionResult Index()
{
var awardDetails = (from award in db.award
join candidate in db.candidate
on award.ULN equals candidate.ULN
join framework in db.framework
on award.QAN equals framework.QAN
where award.OrganisationIdentityID == organisationID
select new AwardDetails_Extended
{
AwardID = award.AwardID,
ULN = award.ULN,
AwardStatus = award.AwardStatus,
Forename = candidate.Forename,
Surname = candidate.Surname,
DOB = candidate.DOB,
FrameworkID = framework.FrameworkID,
TitleFull = framework.TitleFull,
TitleShort = framework.TitleShort,
AwardLevel = framework.AwardLevel,
Award = framework.Award,
Completion = framework.Completion
}).ToList();
var qualificationDetails = (from candidateQualification in db.candidateQualification
join qualification in db.qualification
on candidateQualification.QualificationID equals qualification.QualificationID
select new Qualification_Extended
{
ID = candidateQualification.ID,
QualificationID = candidateQualification.QualificationID,
ULN = candidateQualification.ULN,
FrameworkID = candidateQualification.FrameworkID,
Achieved = candidateQualification.Achieved,
DateAchieved = candidateQualification.DateAchieved
}).ToList();
List<CandidateExtended> candidateVM = new List<CandidateExtended>();
foreach (var item in awardDetails)
{
CandidateExtended vm = new CandidateExtended();
vm.AwardID = item.AwardID;
vm.FrameworkID = item.FrameworkID;
vm.ULN = item.ULN;
vm.Forename = item.Forename;
vm.Surname = item.Surname;
vm.DOB = item.DOB;
vm.TitleShort = item.TitleShort;
vm.TitleFull = item.TitleFull;
vm.Award = item.Award;
vm.AwardLevel = item.AwardLevel;
vm.Status = item.AwardStatus;
vm.Completion = item.Completion;
vm.SelectedRoute = item.SelectedRoute;
foreach (var qualification in qualificationDetails)
{
if (qualification.ULN == item.ULN && qualification.FrameworkID == item.FrameworkID)
{
vm.addQualification(qualification);
}
}
candidateVM.Add(vm);
}
return View(candidateVM);
}
View
#model List<Apprenticeship_SingleAward.ViewModels.CandidateExtended>
#{
ViewBag.Title = "Single Award Apprenticeships";
Layout = "~/Views/Shared/_Organisation.cshtml";
}
<div class="application-table table-responsive">
<table class="table table-striped administration-table">
<thead>
<tr class="admin-table-heading">
<th>ULN</th>
<th>First Name</th>
<th>Last Name</th>
<th>Title</th>
<th>Award</th>
<th>Level</th>
<th>Qualifications</th>
<th>Status</th>
</tr>
</thead>
<tbody>
#for (int j = 0; j < Model.Count(); j++)
{
var award = Model[j];
<tr>
<td>#award.ULN</td>
<td>#award.Forename</td>
<td>#award.Surname</td>
<td>#award.TitleShort</td>
<td>#award.Award</td>
<td>#award.AwardLevel</td>
<td>
<button class="btn qualificationbutton" data-toggle="modal" data-target="##qualificationModal">#displayQualTotal<i class="glyphicon glyphicon-pencil org-edit-icon"></i></button>
#using (Html.BeginForm("UpdateAward", "Organisation", FormMethod.Post, new { id = award.AwardID}))
{
#Html.HiddenFor(a => Model[j].AwardID)
<div id="#qualificationModal" class="modal fade" role="dialog">
<div class="modal-dialog organisationmodal">
<div class="modal-content">
<div class="modal-body">
<h4 class="org-modal-subheading">#award.TitleShort</h4>
<br />
<div class="row">
<div class="col-md-12">
<div class="row org-row-main">
<div class="col-md-7"><h4 class="org-type">Qualification</h4></div>
<div class="col-md-2"><h5 class="org-completed">Completed</h5></div>
<div class="col-md-3"><h5 class="org-date">Date</h5></div>
</div>
<hr class="org-hr"/>
#for (int i = 0; i < Model[j].Qualifications.Count(); i++)
{
<div class="row org-row">
<div class="col-md-7">
#Html.HiddenFor(a => Model[j].Qualifications[i].ID)
</div>
<div class="col-md-2">
#Html.CheckBoxFor(a => Model[j].Qualifications[i].Achieved)
</div>
<div class="col-md-3"
>#Html.TextBoxFor(a => Model[j].Qualifications[i].DateAchieved, "{0:dd/MM/yyyy}")
</div>
</div>
}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn ccea-signout" data-dismiss="modal">Close</button>
<button type="submit" class="btn admin-button" style="margin-top: 0;">Save</button>
</div>
</div>
</div>
</div>
}
</td>
<td>
#{
var status = award.Status;
if (status == "In Progress")
{
<button class="btn progressbutton" style="margin: 0;">#status</button>
}
}
</td>
</tr>
}
</tbody>
</table>
UpdateAward
[HttpPost]
public ActionResult UpdateAward(List<CandidateExtended> Model)
{
return RedirectToAction("Index", "Login");
}
The way it is set up now (with BeginForm inside the #for, and a Submit button for every 'mini'-Form), every submit will do a Form Post containing exactly one item from the list.
If that is how you want it to work (edit one item at a time), then you may keep it. Do keep in mind however (add a comment?) that even though the Post Action method is ready to receive a List, there never will be multiple items in the List because each 'mini'-Form contains just one item.
If on the other hand you want to be able to save multiple items at once, then move the BeginForm outside the #for, and use just one Submit button at the end of the Form, e.g. just before the closing }.

Controller not able to read model returned from View in MVC

I am using MVC framework in my project and using model binding to fill a view and then retrieve the values from the view using two controllers.
I am able to fill the view with the model properties but when i am trying to retrieve the values on click of a submit button. The model returns null properties.
Here is the ViewModels:
public partial class QuestionAnswer
{
public string QuestionText { get; set; }
public string QuestionId { get; set; }
public string AnswerText { get; set; }
public string SectionName { get; set; }
public bool IsChecked { get; set; }
}
public partial class pluralQuestionAnswer
{
public Dictionary<int, QuestionAnswer> QnAs { get; set; }
public Dictionary<string, int> SectionNameWithRank { get; set; }
public Dictionary<string, int> SectionNameWithQuestionCount { get; set; }
}
Here are the controllers:
namespace Temp.Controllers
{
public partial class AIPController : Controller
{
public ActionResult FirstInitiative()
{
pluralQuestionAnswer ViewModel = new pluralQuestionAnswer();
//code to fill the model ViewModel
return View(ViewModel);
}
[HttpPost]
public ActionResult SaveSelectedInitiatives(pluralQuestionAnswer ViewModel, string Save)
{
//some code that uses ViewModel
//this is where ViewModel shows all properties as null
return View();
}
}
}
FirstInitiative is used to generate the view by passing a viewModel and SaveSelectedInitiatives is used to get value from the viewModel retrieved from the view.
Here is the View:
#using Models;
#model pluralQuestionAnswer
#{
ViewBag.Title = "FirstInitiative";
int sectionIterator;
int sectionPracticeIterator;
int totalPracticeIterator = 1;
}
<header></header>
<section>
<header>
<h1>First Initiative</h1>
</header>
#using (Html.BeginForm("SaveSelectedInitiatives", "AIP", FormMethod.Post))
{
<div class="inititive-table" style="overflow:auto">
<div class="inititive-table-header">
<div class="initiative-questioncolumn">
Common Minimum Practices
</div>
<div class="initiative-answercolumn">
Your response
</div>
</div>
#for (sectionIterator = 1; sectionIterator <= Model.SectionNameWithRank.Count; sectionIterator++)
{
<div class="initiative-section">
<div class="initiative-section-name">
<span>#Model.SectionNameWithRank.Keys.ElementAt(sectionIterator - 1)</span>
</div>
#for (sectionPracticeIterator = 1; sectionPracticeIterator <= Model.SectionNameWithQuestionCount[Model.SectionNameWithRank.Keys.ElementAt(sectionIterator - 1)]; sectionPracticeIterator++)
{
<div class="initiative-section-question initiative-questioncolumn">
<label>
#*model binding*#
#Html.HiddenFor(x => x.QnAs[totalPracticeIterator].QuestionId)
<span style="width: 20px; float:left">#Html.CheckBoxFor(x => x.QnAs[totalPracticeIterator].IsChecked)</span>
<span style="display: block; margin-left: 20px">#Html.Raw(Model.QnAs[totalPracticeIterator].QuestionText)</span>
</label><br />
</div>
<div class="initiative-section-answers initiative-answercolumn">
#Model.QnAs[totalPracticeIterator].AnswerText
</div>
{totalPracticeIterator += 1;}
}
</div>
}
</div>
<div>
<input type="submit" class="zs-left zs-button zs-button-action zs-atp-button" name="Save" value="Save" />
</div>
}
</section>
In your Dictionary objects, change the key from int type to string type and this should work.
You may want to rename your inputs to match the KeyValuePair schema of your model, so replace below:
#Html.HiddenFor(x => x.QnAs[totalPracticeIterator].QuestionId)
With
#Html.Hidden(string.Format("QnAs[{0}].Key", i), /*<You Need Key's value here> Like: (_kvp.Key) */)
#Html.Hidden(string.Format("QnAs[{0}].Value.QuestionId", i), x.QnAs[/*<You Need Key's value here> Like: (_kvp.Key) */].QuestionId)
You may try, below code to get KeyValuePair:
var _kvp = Model.QnAs.ElementAt(totalPracticeIterator)
So, the posted data from browser would look like:
QnAs[0].Key = 1
QnAs[0].Value.QuestionId = 123
QnAs[1].Key = 32
QnAs[1].Value.QuestionId = 55

Validate Partial View in mvc 4

I have been trying using Data annonations to validate form on my partial view which i am showing on bootstrap modal dialog. Following is code
Partial View
#model JoyRydeStoreWebPortal.Models.tbl_user
<div class="modal fade" id="createLoginModal" aria-hidden="false" role="dialog" tabindex="-1">
<div class="modal-dialog">
<form class="modal-content" method="post" action="#Url.Action("Index","Index", new{ Area = "Admin" })">
<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="createLoginTitle">Create Login</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-lg-4 form-group">
#Html.TextBoxFor(modal => modal.TXT_USER_ID, new { placeholder = "UserID", id="userID" , #class="form-control"})
</div>
<div class="col-lg-4 form-group">
#Html.TextBoxFor(modal => modal.TXT_USER_PWD, new {type="Password", placeholder = "Password", id = "userPwd", #class = "form-control" })
</div>
<div class="col-sm-12 pull-right">
<button class="btn btn-primary btn-outline" type="submit">Create</button>
</div>
</div>
</div>
</form>
</div>
Index View where i am rendering partial view
#model List<JoyRydeStoreWebPortal.Models.tbl_store>
#using GridMvc.Html;
#{
ViewBag.Title = "Index";
Layout = "~/Areas/Admin/Views/Shared/_layoutAdmin.cshtml";
}
<div class="page">
<div class="page-content padding-30 container-fluid">
#Html.Grid(Model).Columns(columns =>
{
columns.Add(foo => foo.LNG_STORE_ID,true).Sortable(true);
columns.Add(foo => foo.TXT_STORE_NAME).Titled("Store Name").SetWidth(110).Sortable(true).Filterable(true);
columns.Add(foo => foo.TXT_STORE_CONTACT).Titled("Phone Number").SetWidth(110).Sortable(true).Filterable(true);
columns.Add() .Encoded(false).Sanitized(false).SetWidth(30).RenderValueAs(o => #Create Login);
columns.Add().Encoded(false).Sanitized(false).SetWidth(30).RenderValueAs(o => #Detail);
}).WithPaging(20)
</div>
<div>
#{Html.RenderPartial("Partial_CreateLogin", new JoyRydeStoreWebPortal.Models.tbl_user());}
</div>
Following is my Modal Class for TBL_USER create by Entity Framework
namespace JoyRydeStoreWebPortal.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
[MetadataType(typeof(tbl_userMetaData))]
public partial class tbl_user
{
public long LNG_USER_ID { get; set; }
public string TXT_USER_ID { get; set; }
public string TXT_USER_PWD { get; set; }
public long LNG_STORE_ID { get; set; }
public virtual tbl_store tbl_store { get; set; }
}
}
tbl_userMetaData class
public class tbl_userMetaData
{
[Required(ErrorMessage = "User ID is required")]
public string TXT_USER_ID { get; set; }
[Required(ErrorMessage = "User Password is required")]
public string TXT_USER_PWD { get; set; }
}
Index Controller
[HttpGet]
public ActionResult Index()
{
using (joyryde_storeEntities context = new joyryde_storeEntities())
{
var items = context.tbl_store.ToList();
return View(items);
}
}
[HttpPost]
public ActionResult Index(FormCollection frm)
{
if (ModelState.IsValid)
{
RedirectToAction("Index", new { Area = "Admin" });
}
return View();
}
Here ModalState.IsValid always return true. and modal dialog does not validate.
What causing the behaviour ?
Do not use FormCollection on your post
try this:
[HttpPost]
public ActionResult Index([Bind(Include="ITXT_USER_ID ,TXT_USER_PWD ")]tbl_userMetaData userMetaData)
{
if (ModelState.IsValid)
{
RedirectToAction("Index", new { Area = "Admin" });
}
return View();
}
It is good practice to specify the properties to be binded.

MVC 5 ASP.NET Entity Framework Collect Form Data through Range Input

So I am creating a survey monkey, a Survey Has 4 categories, and each category has 5 questions, the HomeController Index passes on the 20 questions from the Questions entity and each Questions must have a Range Slider with values from one to 5, the form values must be collected into a method in the controller, then accumulated into the QuestionResults table and processed, then they must be passed onto the CategoryResults and each Category, out of the 4, must have an accumulated score, they must then be compared to the CategoryFeedback(which is static) table and display the correct information. The code for my HomeController and it's index is as below.
The main issue that I am having, is that since I am passing on the form values through as a parameter of FormCollection, I am struggling to keep the relationship of a Question belonging to a Category and then passing these all onto the CategoryResult table for processing.
Any help will be greatly appreciated
Models:
Question
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace STRA.Models
{
public class Question
{
public int Id { get; set; }
public string Title { get; set; }
public string CreatedBy { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public virtual Category Category { get; set; }
public int CategoryId { get; set; }
public virtual ICollection<QuestionResult> QuestionResult { get; set; }
public virtual ICollection<QuestionFeedback> QuestionFeedback { get; set; }
}
}
QuestionResult
using IdentitySample.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace STRA.Models
{
public class QuestionResult
{
public int Id { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public int QuestionScore { get; set; }
//navigation properties
public virtual ApplicationUser User { get; set; }
public ICollection<CategoryResult> CategoryResult { get; set; }
public virtual Question Question { get; set; }
public int QuestionId { get; set; }
}
}
CategoryResult
using IdentitySample.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace STRA.Models
{
public class CategoryResult
{
public int Id { get; set; }
public int CategoryScore {get;set;}
//navigation properties
public virtual QuestionResult QuestionResult { get; set; }
public int QuestionResultId { get; set; }
}
}
Any help will be greatly appreciated.
HomeController Index
#model IEnumerable<STRA.Models.Question>
#{
//ViewBag.Question.Title = "Survey";
Layout = "~/Views/Shared/_QuizLayout.cshtml";
}
<div class="hr hr-18 hr-double dotted"></div>
<div class="widget-box">
<div class="widget-header widget-header-blue widget-header-flat">
<h4 class="widget-title lighter">STRA</h4>
#*<div class="widget-toolbar">
<label>
<small class="green">
<b>Validation</b>
</small>
<input id="skip-validation" type="checkbox" class="ace ace-switch ace-switch-4" />
<span class="lbl middle"></span>
</label>
</div>*#
</div>
#*"Create","Home"*#
#using (Html.BeginForm("Create", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="widget-body">
<div class="widget-main">
<!-- #section:plugins/fuelux.wizard -->
<div id="fuelux-wizard-container">
<div class="col-md-12 center">
<div class="easy-pie-chart percentage" data-percent="25" data-color="#2679b5">
#*<span class="percent">20</span>%*#
</div>
</div>
<div style="display:none;">
<!-- #section:plugins/fuelux.wizard.steps -->
<ul class="steps">
<li data-step="1" class="active">
<span class="step">1</span>
<span class="Question.Title">Validation states</span>
</li>
<li data-step="2">
<span class="step">2</span>
<span class="Question.Title">Alerts</span>
</li>
<li data-step="3">
<span class="step">3</span>
<span class="Question.Title">Payment Info</span>
</li>
<li data-step="4">
<span class="step">4</span>
<span class="Question.Title">Other Info</span>
</li>
</ul>
<!-- /section:plugins/fuelux.wizard.steps -->
</div>
<hr />
<!-- #section:plugins/fuelux.wizard.container -->
<div class="step-content pos-rel">
<div class="step-pane" data-step="1">
#{
foreach (var item in Model.Take(5))
{
<div class="col-md-12">
<h4>#Html.DisplayFor(modelItem => item.Title)</h4>
<div id="slider-eq">
<h5 class="pull-left">Strongly Disagree</h5>
<h5 class="pull-right">Strongly Agree</h5>
<span id="q_#Html.DisplayFor(modelItem => item.Id)" class="ui-slider-purple">3</span>
<input type="hidden" id="question_#item.Id" name="question_#item.Id" value="3" />
</div>
</div>
}
//Model.Skip(5);
}
</div>
<div class="step-pane" data-step="2">
#*<div class="center">
<h3 class="blue lighter">This is step 2</h3>
</div>*#
#{
foreach (var item in Model.Skip(5).Take(5))
{
<div class="col-md-12">
<h4>#Html.DisplayFor(modelItem => item.Title)</h4>
<div id="slider-eq">
<h5 class="pull-left">Strongly Disagree</h5>
<h5 class="pull-right">Strongly Agree</h5>
<span id="q_#Html.DisplayFor(modelItem => item.Id)" class="ui-slider-purple">3</span>
<input type="hidden" id="question_value" name="question_value" value="3" />
<input type="hidden" id="questonId" name="questonId" value="#item.Id" />
#*<span class="ui-slider-red">55</span>
*#></div>
</div>
}
}
</div>
<div class="step-pane" data-step="3">
#*<div class="center">
<h3 class="blue lighter">This is step 3</h3>
</div>*#
#{
foreach (var item in Model.Skip(10).Take(5))
{
<div class="col-md-12">
<h4>#Html.DisplayFor(modelItem => item.Title)</h4>
<div id="slider-eq">
<h5 class="pull-left">Strongly Disagree</h5>
<h5 class="pull-right">Strongly Agree</h5>
<span id="q_#Html.DisplayFor(modelItem => item.Id)" class="ui-slider-purple">3</span>
<input type="hidden" id="question_#item.Id" name="question_#item.Id" value="3" />
#*<span class="ui-slider-red">55</span>
*#
</div>
</div>
}
}
</div>
<div class="step-pane" data-step="4">
#*<div class="center">
<h3 class="blue lighter">This is step 4</h3>
</div>*#
#{
foreach (var item in Model.Skip(15).Take(5))
{
<div class="col-md-12">
<h4>#Html.DisplayFor(modelItem => item.Title)</h4>
<div id="slider-eq">
<h5 class="pull-left">Strongly Disagree</h5>
<h5 class="pull-right">Strongly Agree</h5>
<span id="q_#Html.DisplayFor(modelItem => item.Id)" class="ui-slider-purple">3</span>
<input type="hidden" id="question_#item.Id" name="question_#item.Id" value="3" />
#*<span class="ui-slider-red">55</span>
*#
</div>
</div>
}
}
</div>
</div>
<!-- /section:plugins/fuelux.wizard.container -->
</div>
<hr />
<div class="wizard-actions">
<!-- #section:plugins/fuelux.wizard.buttons -->
<button type="button" id="previous" class="btn btn-prev">
<i class="ace-icon fa fa-arrow-left"></i>
Prev
</button>
<button type="button" id="next" class="btn btn-success btn-next" #*data-last="Finish"*#>
Next
<i class="ace-icon fa fa-arrow-right icon-on-right"></i>
</button>
<button id="finish" class="btn btn-success" type="submit">
Submit
<i class="ace-icon fa fa-arrow-right icon-on-right"></i>
</button>
<!-- /section:plugins/fuelux.wizard.buttons -->
</div>
<!-- /section:plugins/fuelux.wizard -->
</div><!-- /.widget-main -->
</div>
<!-- /.widget-body -->
}
</div>
HomeController
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using IdentitySample.Models;
using STRA.Models;
using System.Collections.Generic;
using System.Diagnostics;
using System;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
namespace IdentitySample.Controllers
{
[Authorize]
public class HomeController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
//public ActionResult Index()
public ActionResult Index()
{
if (User.IsInRole("Admin"))
{
return RedirectToAction("Index", "Dashboard");
}
if (User.IsInRole("Sales Consultant"))
{
return RedirectToAction("Index", "Reports");
}
//loads all questions in
//var questions = db.Questions.Include(s => s.Survey).Include(c => c.Category);
var questions = db.Questions.Include(c => c.Category);
return View(questions.ToList());
//var questionResults = db.QuestionResults.Include(c => c.Question);
//return View(questionResults.ToList());
//viewmodel attempt
//var viewModel = new SurveyViewModels();
//viewModel.Questions = db.Questions
// .Include(i =>)
}
[HttpPost]
public ActionResult Index(FormCollection result)
{
List<QuestionResult> info = new List<QuestionResult>();
QuestionResult newResult = new QuestionResult();
var appUser = new ApplicationUserManager(new UserStore<ApplicationUser>(db));
ApplicationUser user = appUser.FindById(User.Identity.GetUserId());
foreach (var key in result.AllKeys.Where(k => k.Contains("question")).ToArray<string>())
{
string[] keys = key.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
if (key.Count() > 1)
{
QuestionResult re = new QuestionResult();
re.QuestionScore = Convert.ToInt32(result[key]);
re.QuestionId = Convert.ToInt32(keys[1]);
re.User = user;
db.QuestionResults.Add(re);
}
}
db.SaveChanges();
Debug.WriteLine(result[0]);
return View();
}
}
}
jQuery UI Slider Plugin
$("#slider-eq > span").css({ width: '100%', 'float': 'left', margin: '15px' }).each(function () {
// read initial values from markup and remove that
var value = parseInt($(this).text(), 10);
$(this).empty().slider({
value: value,
min: 1,
max: 5,
range: "min",
animate: true,
change: function (event, ui) {
//alert(ui.value);
$(this).next("[id^=question_]").val(ui.value);
//$(this > ).slider("values", $this.data("index"), $this.val());
}
});
});
I would in your RazorTemplate add the question category as a prefix to the question_id or question_name which is what comes through via the FormCollection
<input type="hidden" id="#(item.category_id)_question_#item.Id" name="#(item.category_id)_question_#item.Id" value="3" />
Then in your controller action, just pull out the category_id from the start of the name, so you know what category you are currently iterating through.
Your view code is creating form controls which have no relationship to your models. Instead create view models representing what you need to display/edit in the view, use strongly typed helpers to give you 2-way model binding and post back your view model.
View models
public class SurveyVM
{
public List<CategoryVM> Categories { get; set; }
// add any other properties of Survey you need to display/edit (e.g. ID, Title etc)
}
public class CategoryVM
{
public List<QuestionVM> Questions { get; set; }
// add any other properties of Category you need to display/edit (e.g. ID, Title etc)
}
public class QuestionVM
{
public int Id { get; set; }
public string Title { get; set; }
public int Score { get; set; }
// Do not include properties such as DateCreated, User etc
}
Controller
public ActionResult Index()
{
SurveyVM model = new SurveyVM();
// populate the categories and for each category, populate the associated questions
return View(model);
}
[HttpPost]
public ActionResult Index(SurveyVM model)
{
// loop through each Category, and foreach category loop through each Question to build your `List<QuestionResult>`
}
View
#model yourAssembly.SurveyVM
#using (Html.BeginForm())
{
// add elements for properties of SurveyVM (ID, Title etc)
for(int i = 0; i < Model.Categories.Count; i++)
{
<div class="category">
// add elements for properties of each CategoryVM (ID, Title etc)
#for (int j = 0; j < Model.Categories[i].Questions.Count; j++)
{
<div class="question">
#Html.HiddenFor(m => m.Categories[i].Questions[j].Id)
#Html.DisplayFor(m => m.Categories[i].Questions[j].Title)
#Html.TextBoxFor(m => m.Categories[i].Questions[j].Score)
</div>
}
</div>
}
<input type="submit" .../>
}

Categories