Displaying a Single Field from Model - c#

public class StudentViewModel
{
public Student studentVm { get; set; }
public StudentAdditionalInfo studentAdditionalInfoVm { get; set; }
public int rcImgToProcess { get; set; }
}
studentVm and studentAdditionalInfoVm stores the data of my 2 Tables Student and StudentAdditionalInfo, these contains multiple records
rcImgToProcess store the data of the record count that I passed from my controller, so it is only a single data (I can use ViewBag but for some reason I prefer passing it to Model)
<div>
I want the value of [rcImgToProcess] here
</div>
#foreach (var item in Model)
{
<tr>
<td>#item.studentVm.Id </td>
<td>#item.studentVm.StudentCourse</td>
<td>#item.studentAdditionalInfoVm.MotherName</td>
<td>#item.studentAdditionalInfoVm.FatherName</td>
</tr>
}
Controller
int rcImgToProcess = "0";
rcImgToProcess= 1001;
var studentList = from s in student
join st in studentAdditionalInfo on s.Id equals st.Id into st2
from st in st2.DefaultIfEmpty()
select new StudentViewModel {
studentVm = s,
studentAdditionalInfoVm = st,
rcImgToProcess = rcImgToProcess
};
return View(studentList);
How can I call rcImgToProcess to display on the header part of the page

are you referencing the StudentViewModel in the view correctly?
you should have #model <namespaceForStudentViewModel>.StudentViewModel at the top of the file.
eg #model SampleApplication.ViewModels.StudentViewModel
then you can use <div>#Model.rcImgToProcess</div> anywhere in the view

Related

foreach statement cannot operate on variables of type 'Customers' because no a public instance definition for 'GetEnumerator'

I am trying to send a enumerable customer object in ViewResult to Index view of customers. but i am not able to use foreach with Model on the view page.
The error associated with model says -
"foreach statement cannot operate on variables of type 'Customers' because 'Customers' does not contain a public instance definition for 'GetEnumerator'"
i tried to switch the code with an array but the problem remains
public class Customers
{
public int Id { get; set; }
public string Name { get; set; }
}
//Customer Controller
public class CustomersController : Controller
{
public IActionResult Index()
{
var customers = GetCustomers();
return View(customers));
}
public IActionResult Details(int id)
{
var customer = GetCustomers().SingleOrDefault(c => c.Id == id);
return View(customer);
}
private IEnumerable<Customers> GetCustomers()
{
var customer = new List<Customers>
{
new Customers { Id = 1, Name = "John Smith"},
new Customers { Id = 2, Name = "Mary Williams"}
};
return customer;
}
}
//View page Index
#foreach (var customer in Model)
{
<tr>
<td><a asp-area="" asp-controller="Customers" asp-action="Details">#customer.Name</a></td>
</tr>
}
The error displayed Under Model
when the foreach statements executes, the it should output the name of the customers accordingly
In view you describe model as single object Customer.
Change your view:
#model IEnumerable<Vidly.Model.Customer>
Or:
#model List<Vidly.Model.Customer>

How can I add another value in ModelView and pass it from my Action

In my Products PartiallView table
#model IEnumerable<Products.Models.ProductModelView>
I'am trying (hide) not showing some buttons if user departmentId is not the same as product departmentId
<table class="table table-responsive table-hover table-striped">
<tr>
<th>Product type</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProductName)
</td>
// I want to hide if current inlogged userDepartmentId is not the same as product departmentId
// Like #if(#item.ProductDeptId == userDepartmentId) {
<td>
<Button class="btn btn-success glyphicon btn-xs glyphicon-plus" onclick="return EditDelete(#(item.ProductId) )">Edit/Delete</Button>
</td>
}
</tr>
}
Here is my Class, ViewModel and Action that I'am trying to create but don't know how to pass to my PartielView
public class Product
{
public int ProductId { get; set; }
public string productName { get; set; }
public int DepartmentId { get; set; }
}
public class ProductModelView
{
public int ProductId { get; set; }
public string productName { get; set; }
public int DepartmentId { get; set; }
public int UserDepartmentId { get; set; }
}
[HttpGet]
public ActionResult Lager()
{
using (context)
{
string user = User.Identity.Name;
int deptId = context.Users.Where(u => u.UserName == user).Select(d => d.DepartmentId).SingleOrDefault();
// Here I don't know how to continue ... I try like this
Product pr = new Product();
ProductModelView prModel = new ProductModelView();
prModel.ProductId = pr.ProductId;
prModel.productName = pr.productName ;
prModel.DepartmentId= pr.DepartmentId;
prModel.UserDepartmentId = DeptId;
// And then, how to return and what to return?
return PartialView("_ProductList", prModel); // Is this right? Returning prModel?
}
Can anyone please help me to formulate my Class, ViewModel and my Action?
Create a "composite" object and pass it instead (as per #Uwe):
public class ProductListViewModel
{
public IEnumerable<ProductModelView> Products { get; set; }
}
and change #model accordingly:
#model ProductListViewModel
Or construct and pass IEnumerable<ProductModelView> products to return PertialView():
// IQueryable<Product>
var products = from p in context.Products
where p.DepartmentId == depId // aware! would cause 2 queries to db, shall be rewritten
select p;
var prModels = from p in products.AsEnumerable() // 'memorize' db query into in-memory objects
select new ProductViewModel
{
ProductId = p.ProductId,
ProductName = p.productName,
DepartmentId = p.DepartmentId;
UserDepartmentId = deptId;
};
return return PartialView("_ProductList", prModels);
How to rewrite:
Either configure a navigation property (recommended):
public class Product
{
public User { get; set; }
}
Or perform a direct join:
var products = from p in context.Products
join u in context.User on p.UserDepartmentId = u.UserDepartmentId // or whatever it is
where u.UserName == userName // it's better to use userId which is likely the primary key
select p;

Set razor view variable according to checkbox checked

I am working on an online library using ASP.NET MVC.
This is my view model for the library management page:
public class ManageViewModel
{
public IPagedList<ManageBookViewModel> WholeInventory;
public IPagedList<ManageBookViewModel> CurrentInventory;
public bool OldInventoryIsShown { get; set; } = false;
}
In the corresponding view I have a checkbox for whether or not to show the old inventory and a local variable modelList, which I would like to set to Model.WholeInventory if the checkbox is checked and to Model.CurrentInventory otherwise. I use modelList to display a table with all the books and I would need its value to be reset every time I (un)check the checkbox in order for the list to be properly displayed.
Is this possible? How would I go about doing this?
In my view I currently have:
<label class="switch">
<input id="OldInventoryIsShown" name="OldInventoryIsShown" type="checkbox" />
<span class="slider round"></span>
</label>
#{
var modelList = Model.OldInventoryIsShown ? Model.WholeInventory : Model.CurrentInventory;
}
#using (Html.BeginForm())
{
<table id="bookInventory" class="table table-hover">
<thead>
<tr>
<th>Author</th>
<th>Title</th>
....
</tr>
</thead>
#foreach (var entry in modelList)
{
<tr>
<td>#Html.DisplayFor(modelItem => entry.Author)</td>
<td>#Html.DisplayFor(modelItem => entry.Title)</td>
....
</tr>
}
</table>
<p>Page #(modelList.PageCount < modelList.PageNumber ? 0 : modelList.PageNumber) of #modelList.PageCount</p>
#Html.PagedListPager(modelList, page => Url.Action("Manage", page }))
}
The controller action:
public ActionResult Manage(int? page)
{
var wholeInventory = _bookService.GetBooksIncludingDisabled().Select(b => Mapper.Map<Book, ManageBookViewModel>(b));
var currentInventory = _bookService.GetBooks().Select(b => Mapper.Map<Book, ManageBookViewModel>(b));
int pageSize = 3;
int pageNumber = page ?? 1;
var model = new ManageViewModel
{
WholeInventory = wholeInventory.ToPagedList(pageNumber, pageSize),
CurrentInventory = currentInventory.ToPagedList(pageNumber, pageSize)
};
return View(model);
}
Models:
Book.cs
public class Book
{
public int BookId { get; set; }
[Required]
[MinLength(1)]
public string Title { get; set; }
[Required]
[MinLength(1)]
public string Author { get; set; }
....
public bool IsDisabled { get; set; } = false;
public virtual ICollection<UserBook> UserBooks { get; set; }
}
ManageBookViewModel.cs
public class ManageBookViewModel
{
public int BookId { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Enter the book title")]
public string Title { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Enter the book author.")]
public string Author { get; set; }
....
public bool IsDisabled { get; set; }
}
Your ManageViewModel needs to include only one property for the paged list and it should be IPagedList<Book> (see explanation below)
public class ManageViewModel
{
public IPagedList<Book> Inventory;
[Display(Name = "Include old inventory")]
public bool OldInventoryIsShown { get; set; }
... // any other search/filter properties
}
and your view needs to include the checkbox inside the <form> element, and the form should be making a GET to your controller method. Then you also need to include the current value of OldInventoryIsShown as a route value in the #Html.PagedListPager() method so that the current filter is retained when paging.
#model ManageViewModel
...
#using (Html.BeginForm("Manage", "ControllerName", FormMethod.Get))
{
#Html.CheckBoxFor(m => m.OldInventoryIsShown)
#Html.LabelFor(m => m.OldInventoryIsShown)
... // any other search/filter properties
<input type="submit" value="search" />
}
<table id="bookInventory" class="table table-hover">
....
</table>
<p>Page #(modelList.PageCount < modelList.PageNumber ? 0 : modelList.PageNumber) of #modelList.PageCount</p>
#Html.PagedListPager(modelList, page =>
Url.Action("Manage", new { page = page, oldInventoryIsShown = Model.OldInventoryIsShown })) // plus any other search/filter properties
Finally in the controller method you need a parameter for the value of the bool property an modify your query based on that value.
public ActionResult Manage(int? page, bool oldInventoryIsShown)
{
int pageSize = 3;
int pageNumber = page ?? 1;
IQueryable<Book> inventory = db.Books;
if (!oldInventoryIsShown)
{
inventory = inventory.Where(x => !x.IsDisabled);
}
ManageViewModel model = new ManageViewModel
{
Inventory = inventory.ToPagedList(pageNumber, pageSize),
OldInventoryIsShown = oldInventoryIsShown
};
return View(model);
}
You current controller code is terribly inefficient. Lets assume your table has 10,000 Book records, and 5,000 of those are 'disabled' (archived). You current code first gets all 10,0000 records and adds them to memory. Then you map all then to a view model. Then you call another query to get another 5,0000 records (which are just duplicates of what you already have), which you add to memory and map to a view model. But all you want in the view is 3 records (the value of pageSize) so you have done thousands of times of extra unnecessary processing.
In your case, there is no need for a view model (although if you did need one, you would use the StaticPagedList methods - refer this answer for an example). Your query should be using your db context to generate an IQueryable<Book> so that only the results you need are returned from the database (internally the ToPagedList() method uses .Skip() and .Take() on IQueryable<T>)

When should I use ViewBag/model?

I think that using ViewBag is faster than model.
My example is:
In the action:
public ActionResult MyAction()
{
ViewBag.Data = (from m in myDatabase.myTable select m).ToList();
}
In the view:
#foreach(var item in ViewBag.Data)
{
<tr>
<td>#item.myColumn</td>
</tr>
}
By using model:
[Table("tbl_mytable")]
public class MyTable()
{
public int Id { get; set; }
public int Column2 { get; set; }
public int Column3 { get; set; }
// ...
public IEnumerable<MyTable> Data { get; set; }
}
in the model:
public class MainClass
{
public List<MyTable> MyMethod()
{
List<MyTable> list = new List<MyTable>();
// code logic to find data in database and add to list
list.Add(new MyTable
{
Column2 = ...
Column3 = ...
});
return list;
}
}
in the action:
public ActionResult MyAction()
{
MainClass mc = new MainClass();
MyTable model = new MyTable();
model.Data = mc.MyMethod();
return View(model);
}
in the view:
#using MyProjectName.Models
#model MyProjectName.Models.MyTable
#foreach(MyTable item in Model.Data)
{
<tr>
<td>#item.Column1</td>
</tr>
}
Both of them are working, and ViewBag is easier than model.
So, can you tell me: When should I use ViewBag/model?
ViewBag is not faster. In both cases your creating a model of List<MyTable>. All the code you have show for creating your 'MyTable' model is pointless - your just creating a new collection containing duplicates from the existing collection. In the controller it just needs to be
public ActionResult MyAction()
{
var model = (from m in myDatabase.myTable select m).ToList();
return View(model);
}
and in the view
#model List<MyProjectName.Models.MyTable> // a using statement is not required when you use the fully qualified name
#foreach(var item in Model)
{
<tr>
<td>#item.myColumn</td>
</tr>
}
And your MyTable model should not have a property public IEnumerable<MyTable> Data { get; set; } unless your creating a hierarchical model.
Always use models (preferably view model) in you view so you can take advantage of strong typing (vs ViewBag which is dynamic)
use model if you want strongly-typed add Messages to your View Model. Otherwise, stick with ViewBag.

How to bind Model from get to post method MVC 4

I am currently stuck at some point of my implementation where I use a ViewModel class to display data, but I need to post values from other object which are equal to given values in the ViewModel. Here are both model classes
ViewModel.cs
public class ViewModel
{
public IList<Answer> Answers { get; set; }
public Question Questions { get; set; }
}
UserScore.cs
public partial class UserScore
{
public int ScoreID { get; set; }
public int U_Id { get; set; }
public int A_Id { get; set; }
public bool CorrectAnswer { get; set; }
public int Q_Id { get; set; }
public virtual Answer Answer { get; set; }
public virtual Member Member { get; set; }
public virtual Question Question { get; set; }
}
So far so good. I am using an object of Question and List of Answers to display the data I need in my Controller
Controller.cs
public ActionResult TakeTest(int id=0)
{
ViewModel vm = new ViewModel();
Test t = db.Tests.Find(id);
if (t == null)
{
return HttpNotFound();
}
vm.Questions = (from q in db.Questions
join tt in db.Tests on q.BelongToTest equals tt.TestId
where q.BelongToTest == id
select q).FirstOrDefault();
vm.Answers = new List<Answer>(from a in db.Answers
join q in db.Questions on a.BelongToQuestion equals q.QuestionId
join tt in db.Tests on q.BelongToTest equals tt.TestId
where q.BelongToTest == id &&
a.BelongToQuestion == vm.Questions.QuestionId
select a).ToList();
foreach (var i in vm.Answers)
{
i.CorrectOrNot = false;
}
return View(vm);
}
View.cshtml
#model MvcTestApplication.Models.ViewModel
#using MvcTestApplication.Models
#{
ViewBag.Title = "TakeTest";
}
<h2>TakeTest</h2>
#using (Html.BeginForm()) {
<table>
<tr>
<th>Question Name</th>
</tr>
<tr>
<td>#Html.DisplayFor(model => model.Questions.Question_Text)</td>
</tr>
</table>
<table id="dataTable">
<tr>
<th>Correct?</th>
<th>Answer text</th>
<th>Open Answer</th>
</tr>
#for(int i = 0; i < Model.Answers.Count; i++)
{
<tr>
<td>#Html.CheckBoxFor(m => m.Answers[i].CorrectOrNot)</td>
<td>#Html.DisplayFor(m => m.Answers[i].AnswerText)</td>
<td>#Html.EditorFor(m => m.Answers[i].OpenAnswerText)</td>
</tr>
}
</table>
if(ViewBag.Message != null)
{
<script>
$(document).ready(function(){
alert('#ViewBag.Message');
});
</script>
}
<input type="submit" value="Next Question" />
}
Now in my post method I need to get the value of vm.Question.QuestionId and AnswerId of the Answer list, set them to be equal to UserScore.Q_Id and UserScore.A_Id. How can I do that ? I tried many ways but with no success.
Controller.cs
[HttpPost]
[Authorize]
public ActionResult TakeTest(ViewModel vm)
{
if (ModelState.IsValid)
{
UserScore us = new UserScore();
us.U_Id = (from m in db.Members
where m.UserID == WebSecurity.CurrentUserId
select m.MemberId).FirstOrDefault();
us.A_Id = 49;
//us.A_Id = vm.Questions.QuestionID returns NULL
us.Q_Id = 150;
db.UserScores.Add(us);
db.SaveChanges();
}
return View(vm);
}
In general I need to know how to bind this vm.something to us.something because Question appears to be null all the time.
These values are null, because they are not present in your view. You will need to keep them in your View in the form of a hidden control. The ViewModel that you receive in the post can only construct the ViewModel using values present in the View. Since there is no ID maintained in the View, the constructed ViewModel has a null ID.
You can use
#Html.HiddenFor(model => model.Questions.ID)
and for your answer ID
#Html.HiddenFor(m => m.Answers[i].ID)
vm.Questions.QuestionID returns NULL because u haven't used that on the view anywhere. A easy hack would be to use a hidden field to capture the value or you should be initializing your viewmodel again and follow the logic in the post method.
You should use an hiddenfor helpers in your view and try something like that.
#Html.hiddenfor(m=>vm.Questions.QuestionId)
Give it a try : Html.HiddenFor value property not getting set

Categories

Resources