MVC 4, Model and model render differently - asp.net-mvc-4

I'm not sure why i get this behavior, happy if anyone could pointing me to right source, as i'm not sure what need to google.
View Model
public class GeneralDay
{
public byte tintWeekDay { get; set; }
public string nvarDayName { get; set; }
public bool Assigned { get; set; }
}
Controller
[ChildActionOnly]
public PartialViewResult TargetDay(MODELS.ViewModels.Promotion promotion) {
var daylist = gd.GeneralDayList();
foreach (var day in daylist)
{
promotion.targetDay.Add(new MODELS.ViewModels.GeneralDay
{
Assigned = promotion.targetDay.FirstOrDefault(x => x.tintWeekDay == day.tintWeekDay) != null,
nvarDayName = day.nvarDayName,
tintWeekDay = day.tintWeekDay
});
}
ModelState.Clear();
return PartialView(promotion);
}
View
#model GeneralDay
#using XXX.ViewModels;
<fieldset>
//First Part
#(Model.tintWeekDay)
#(Model.nvarDayName)
#(Model.Assigned)
//Second Part
#Html.LabelFor(model => model.tintWeekDay)
#Html.LabelFor(model => model.nvarDayName)
#Html.LabelFor(model => model.Assigned)
</fieldset>
The above display these result , why different result?
First Part
1 Sunday False
Second Part
tintWeekDay
nvarDayName
Assigned

Well the following prints values..
//First Part
#(Model.tintWeekDay)
#(Model.nvarDayName)
#(Model.Assigned)
and the following is creating labels
//Second Part
#Html.LabelFor(model => model.tintWeekDay)
#Html.LabelFor(model => model.nvarDayName)
#Html.LabelFor(model => model.Assigned)
Since you haven't used the DisplayAttribute, the LabelFor is just printing the variable name.
Maybe you wanted to use:
//Second Part
#Html.DisplayFor(model => model.tintWeekDay)
#Html.DisplayFor(model => model.nvarDayName)
#Html.DisplayFor(model => model.Assigned)

Because in the first part you render the value of the model properties.
#(Model.tintWeekDay) renders 1 to the output.
But #Html.LabelFor(model => model.tintWeekDay) renders the (nonexisting) label for this field, NOT the value)
Use the DisplayAttribute to change the field labels in the model.
Example:
public class GeneralDay
{
[Display(Description = "Day of week")]
public byte tintWeekDay { get; set; }
public string nvarDayName { get; set; }
public bool Assigned { get; set; }
}

Related

why checkbox wont check on page load?

i have the following database table for the Compounds table (chemical compounds/elements in the periodic table) there are typos in table data so ignore them
the data is :
the controller :
public class CheckboxController : Controller
{
//
// GET: /Checkbox/
testdbEntities db = new testdbEntities();
[HttpGet]
public ActionResult Index()
{
var comps = db.Compounds.Select(c => new CompoundModel { Id=c.Id, CompoundName=c.Name, IsSelected=c.IsSelected}).ToList();
CheckboxVM cvm = new CheckboxVM { checkboxData=comps};
return View(cvm);
}
[HttpPost]
public string Index(IEnumerable<CheckboxVM> collection)
{
return "";
}
}
Model class CompoundModel is:
public class CompoundModel
{
public int Id { get; set; }
public string Code { get; set; }
public string CompoundName { get; set; }
public bool IsSelected { get; set; }
}
and the ViewModel CheckBoxVM:
public class CheckboxVM
{
public string Id { get; set; }
public string CompoundNmae { get; set; }
public bool IsSelected { get; set; }
public IEnumerable<CompoundModel> checkboxData { get; set; }
}
When the page loads it should display check boxes with names and if db table has checked on them (IsSelected=1) then they should be checked.In the post back i need to receive the id, of the user checked checkboxes. At the moment my code does meet the first requirement to check the checked checkboxes based on IsSelected on page load. Is there a way to fix this?
If you need a video with debugging please ask i will be happy to post : )
THE VIEW: (UPDATE)
#model recitejs1.Models.CheckboxVM
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
foreach (var item in Model.checkboxData)
{
#Html.CheckBoxFor(x=>x.IsSelected, (item.IsSelected)?new{#checked="check"}:null)#item.CompoundName
#Html.HiddenFor(x=>x.Id, item.Id)
#Html.HiddenFor(x=>x.CompoundNmae, item.CompoundName)
}
<br><br>
<input type="submit" name="name" value="Send" />
}
You cannot use a foreach loop to generate form controls. It generates duplicate name attributes (that have no relationship to your model) and duplicate id attributes (invalid html).
Create a custom `EditorTemplate for your model
In /Views/Shared/EditorTemplates/CompoundModel.cshtml
#model recitejs1.Models.CompoundModel
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.CompoundName)
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m.CompoundName)
Then in the main view
#model recitejs1.Models.CheckboxVM
....
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.checkboxData)
<input type="submit" name="name" value="Send" />
}
The EditorFor() method will generate the correct html for each item in your collection
Note: You should inspect the html before and after you make this change to better understand how model binding works.
Note also that your POST method parameter needs to be
public string Index(CheckboxVM model)
since that's what the view is based on. However the only property of CheckboxVM that you use in the view is IEnumerable<CompoundModel> checkboxData in which case your view should be
#model IEnumerable<CompoundModel>
...
#Html.EditorFor(m => m)
and keep the POST method as it is (but change the GET method)

Dropdownlist and ViewData in ASP.NET MVC 4

I have a problem with my code. Iwan to make a dropdownlist in my View.cshtml using ViewData and #Html.Dropdownlist. But i get error while i compile it.
Here is my code :
This is the model
public class DeviceComponentModel
{
public int devcomId { get; set; }
public int devcomcomponentId { get; set; }
public int? devcomdeviceId { get; set; }
public ComponentModel Component { get; set; }
public DeviceModel Device { get; set; }
}
This is the code in the controller.
public ActionResult addDevicecomponent()
{
ViewData["Device"] = new SelectList(debuDB.Devices, "Id", "Name");
ViewData["Component"] = new SelectList(debuDB.Components, "Id", "Name");
DeviceComponentModel mdlDevicecom = new DeviceComponentModel();
return View(mdlDevicecom);
}
[HttpPost]
public ActionResult addDeviceComponent(DeviceComponentModel mdlDevicecom)
{
try
{
DeviceComponent deviceComponent = new DeviceComponent()
{
Id = mdlDevicecom.devcomId,
device_id = mdlDevicecom.devcomdeviceId,
component_id = mdlDevicecom.devcomcomponentId
};
debuDB.DeviceComponents.InsertOnSubmit(deviceComponent);
debuDB.SubmitChanges();
return RedirectToAction("Index");
}
catch
{
return View(mdlDevicecom);
}
}
This is my code in the View
<div class="editor-label">
#Html.LabelFor(model => model.devcomdeviceId)
</div>
<div class="editor-field">
#Html.DropDownList("device_0",ViewData["Device"] as IEnumerable<SelectListItem>, "Choose Device")
</div>
<div class="editor-label">
#Html.LabelFor(model => model.devcomcomponentId)
</div>
<div class="editor-field">
#Html.DropDownList("component_0",ViewData["Component"] as IEnumerable<SelectListItem>, "Choose Component")
</div>
But when i compiled it i got the error like this:
"There is no ViewData item of type 'IEnumerable' that has the key 'device_0'."
I dont know why cant i get the error like that. I hope some of you can give the solution of this error.
Regards,

Get multiple checked checkbox values in MVC controller

My code is below:
On page i have a products list with checkbox, code & name of that product.
When selecting multiple checkboxes, on submit click, i need to get the selected checkbox values & save it in the DB.
Product View Model class:
public class ProductVM
{
public ProductVM()
{
this.ProductsList = new List<Product>();
}
public List<Product> ProductsList { get; set; }
public class Product
{
public bool IsSelected { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
}
Product Controller:
[HttpGet]
public ActionResult Edit()
{
var model = new ProductVM();
var product1 = new ProductVM.Product
{
Code = "Product1",
Name = "Apple"
};
var product2 = new ProductVM.Product
{
Code = "Product2",
Name = "Banana"
};
model.ProductsList.Add(Product1);
model.ProductsList.Add(Product2);
return View(model);
}
[HttpPost]
public ActionResult Edit(ProductVM model)
{
if (model.ProductsList.Any(m => m.Selected))
{
//How to get the selected Code & Name here
}
}
Product View:
#model ProductVM
#using(Html.BeginForm())
{
foreach (var item in Model.ProductsList)
{
#Html.CheckBox("IsSelected", item.IsSelected)
#Html.Label(item.Code)
#Html.Label(item.Name)
}
<input type="submit" />
}
First, you need to use for instead of foreach. Otherwise Razor won't generate the proper field names. Second, you need hidden inputs for the Code and Name properties so these will get posted back:
for (var i = 0; i < Model.ProductsList.Count(); i++)
{
#Html.HiddenFor(m => m.ProductsList[i].Code)
#Html.HiddenFor(m => m.ProductsList[i].Name)
<label>
#Html.CheckBoxFor(m => m.ProductsList[i].IsSelected)
#Html.DisplayFor(m => m.ProductsList[i].Code)
#Html.DisplayFor(m => m.ProductsList[i].Name)
</label>
}
To demo my code from my comment to question- You can get idea from it
#foreach (var item in ViewBag.FocusesList)
{
<label>
<input type="checkbox" value="#item.ConfigurationId" name="FocusList" id="FocusList" /> #item.Value.Name
</label>
}
After submit you have all checked values split by comma in Request["FocusList"]

Delete value by updating field

I have this:
View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Bycicle</h4>
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.id)
<div class="form-group">
<label class="control-label col-md-2" for="BycicleID">Mark</label>
<div class="col-md-10">
#Html.DropDownList("BycicleID", String.Empty)
#Html.ValidationMessageFor(model => model.id)
</div>
</div>
The controller:
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Bycicle bycicle = await db.Bycicles.FindAsync(id);
if (bycicle == null)
{
return HttpNotFound();
}
ViewBag.id = new SelectList(db.Bycicles, "BycicleID", "Mark", bycicle.id);
//ViewBag.Color = new SelectList(db.Bycicles, "Color", "Color", bycicle.Color);
//ViewBag.Weight = new SelectList(db.Bycicles, "Weight", "Weight", bycicle.Weight);
//ViewBag.Height = new SelectList(db.Bycicles, "Height", "Height", bycicle.Height);
return View(bycicle);
}
// POST: Bycicle/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(
[Bind(Include = "id, Mark, Color, Weight,Height")]
Bycicle bycicle)
{
if (ModelState.IsValid )
{
db.Entry(bycicle).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.id = new SelectList(db.Bycicles, "id", "Mark", bycicle.id);
return View(bycicle);
}
and the Model:
public class Bycicle
{
public int id { get; set; }
// [Column("Mark")]
public string Mark { get; set; }
public string Color { get; set; }
public string Weight { get; set; }
public string Height { get; set; }
public DateTime? LastTimeChecked { get; set; }
}
But so I can update the other values(Color, Weight, Height) But the Mark name will be deleted if I press save in the Update view. I also checked the db and the Mark value is gone after Update. But If I just press on Edit(update) Then first I see the value(Mark) in the dropdownlist, but after save the mark value is gone. Even if I didnt changed the Mark value in the Update view.
I just cant figure what is wrong.
Thank you!!
Oke,
I did understand it was a type mistake,
But what do you mean with the dropdonlists are not correct? Because you dont have a infinite mark list of bycicles. So that Is why I choose to make a dropdownlist with all the marks and the colors and the sizes. Because an admin fill in the marks, sizes, etc and then the user can select a mark, color, etc. But how will you design the different properties?
I dont have seperate tables for color, mark, etc. But is that necessary?
Thank you
Your not binding anything to the property Mark (what you have shown is bound to the ID property). Preferably the names of your select lists should not be the same as your properties.
In the controller
ViewBag.MarkList = new SelectList(db.Bycicles, "BycicleID", "Mark");
and in the view
#model YourAssembly.Bycicle
....
<div class="form-group">
#Html.LabelFor(m => m.Mark)
<div class="col-md-10">
#Html.DropDownListFor(m => m.Mark, (SelectList)ViewBag.MarkList)
#Html.ValidationMessageFor(m => m.Mark)
</div>
</div>
Note, since you binding all properties, you do not need [Bind(Include = "id, Mark, Color, Weight,Height")]
Edit
While passing values by ViewBag works, I recommend you use view models and strongly typed helpers so you have intellisense support as well as all the other benefits of using view models.
public class BycicleVM
{
public int id { get; set; }
// other properties of Bycicle that you want to edit
public SelectList MarkList { get; set; }
// other select lists
}
then assign the select lists to the view model rather than ViewBag

MVC4: ViewModel is empty on [HttpPost]

I'm trying to make a simple news system in MVC4. I'm very new at it, and I have a simple News base class that looks like this:
NewsPost:
public class NewsPost
{
public virtual int Id { get; set; }
public virtual string Subject { get; set; }
public virtual string Content { get; set; }
}
It's then attached to a category class like so:
NewsCategory:
public class NewsCategory
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<NewsPost> NewsPosts { get; set; }
}
I then have a controller for creating these NewsPosts:
NewsController:
private readonly INewMvcSiteDataSource _db;
public NewsController(INewMvcSiteDataSource db)
{
_db = db;
}
[HttpGet]
public ActionResult Create()
{
var model = new CreateNewsViewModel();
model.Categories = new SelectList(_db.NewsCategories, "Id", "Name");
return View(model);
}
[HttpPost]
public ActionResult Create(CreateNewsViewModel newsModel)
{
if (ModelState.IsValid)
{
int id = int.Parse(newsModel.SelectedCategories.Single(f => f.Selected).Value);
}
return View(newsModel);
}
And lastly, to facilitate with creating the NewsPost, I use a CreateNewsViewModel, like so:
CreateNewsViewModel:
public class CreateNewsViewModel
{
[Required]
public string Subject { get; set; }
[Required]
public string Content { get; set; }
public SelectList Categories { get; set; }
public SelectList SelectedCategories { get; set; }
}
My view looks like this:
Create.cshtml:
#model NewMvcSite.Models.CreateNewsViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>CreateNewsViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Subject)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Subject)
#Html.ValidationMessageFor(model => model.Subject)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Categories)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Categories, Model.SelectedCategories)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
For some reason, my viewmodel isn't returned when I click the submit button to create the newspost, and since there is no parameterless constructor for [HttpPost] Create action, it fails with "No parameterless constructor defined for this object."
I've been trying going through other posts here stating the same problem, but I fail to see the connection between what they are doing and what I am doing. I hope there is someone out there who can help me.
Thank you.
If you want to select category from drop down list, first of all you should add property to your model to hold Id of selected category. Something like this (property Category):
public class CreateNewsViewModel
{
[Required]
public string Subject { get; set; }
[Required]
public string Content { get; set; }
public SelectList Categories { get; set; }
public SelectList SelectedCategories { get; set; }
public int Category { get; set; }
}
after that, you should change code to filling model.Category to this:
model.Categories = new SelectList(categories, "Id", "Name", model.Category);
and than, in your view, editor for Category should look like this:
<div class="editor-field">
#Html.DropDownListFor(m => m.Category, Model.Categories);
</div>
model.Categories = new SelectList(_db.NewsCategories, "Id", "Name");
At this line you fill Categories property
#Html.DropDownListFor(model => model.Categories, Model.SelectedCategories)
Here you trying create select with Categories name and SelectedCategories items
int id = int.Parse(newsModel.SelectedCategories.Single(f => f.Selected).Value);
Here you trying get selected item, BUT on form submit you only sending one number, not list. One of your SelectList must be int
I found the solution.
I had to change the ViewModel to this:
public IEnumerable<SelectListItem> Categories { get; set; }
public int SelectedCategoryId { get; set; }
I changed the controller to:
var model = new CreateNewsViewModel
{
Categories = new SelectList(_db.NewsCategories, "Id", "Name")
};
And changed View to this:
#Html.DropDownListFor(x => x.SelectedCategoryId, Model.Categories)