Delete value by updating field - asp.net-mvc-4

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

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)

Mvc: Getting the selected value of the dropdownlistFor box

In my domain I have this service
public class StudentService
{
private readonly IStudentRepository _studentRepository;
public StudentService(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
public StudentDto DisplayStudentInformation()
{
var objStuSec = _studentRepository.DisplayStudentSection();
return objStuSec;
}
}
Here is my studentDto
public class StudentDto
{
public string StudentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public List<DepartmentDto> GetAllDepartments;
}
Here is my code for the Home controller
public class HomeController : Controller
{
private StudentService _objStudentService;
public HomeController(StudentService objStudentService)
{
_objStudentService = objStudentService;
}
public ActionResult Index()
{
ViewBag.Message = "This is a Test";
var displayform = _objStudentService.DisplayStudentInformation();
return View(displayform);
}
}
Here is my html for the form
#using System.Net.Mime
#model Zakota.University.Domain.DTO.StudentDto
<form action="" method="post">
<div>
<label>First Name</label>
#Html.TextBoxFor(x=>x.FirstName, new { id = "testid1", name="firstname" })
</div>
<div>
<label>Last Name</label>
#Html.TextBoxFor(x=>x.LastName, new { id = "testid1", name="lastname" })
</div>
<div>
<label>Email Address</label>
#Html.TextBoxFor(x=>x.EmailAddress, new { id = "testid1", name="emailaddress" })
</div>
<div>
<label>Department</label>
#Html.DropDownListFor( x=> x.GetAllDepartments,new SelectList(Model.GetAllDepartments,"DepartmentId","DepartmentDescription"), new {#class = "mydropdown", name="dept"})
</div>
<div>
<label></label>
<input type="submit" value="submit"/>
</div>
</form>
I want to be able to get the selected value of the department from dropdownListFor box. I am getting null as the selected value.
Please assist. All other values are correct. The code below is part of the controller code. I just decided to separate it.
[HttpPost]
public ActionResult Index(StudentDto objstudent)
{
string strFirstName = objstudent.FirstName;
string strLastName = objstudent.LastName;
string strEmailAddress = objstudent.EmailAddress;
string strDept = Request.Form["dept"];
var displayform = _objStudentService.DisplayStudentInformation();
return View(displayform);
}
A <select> element postback a single value. You cannot bind a <select> to a collection of complex objects (in your case List<DepartmentDto>). Start by creating a view model representing what you want to edit
public class StudentVM
{
[Display(Name = "First Name")]
[Required(ErrorMessage = "Please enter your first name")]
public string FirstName { get; set; }
.... // other properties of StudentDto
[Display(Name = "Department")]
[Required(ErrorMessage = "Please select a department")]
public int SelectedDepartment { get; set; }
public SelectList DepartmentList { get; set; }
}
Next, your StudentDto model should not contain a property containing a collection of all departments. Your use of DropDownListFor() suggest each student has only one Department, therefore the property should be `public DepartmentDto> Department;
Controller
public ActionResult Create()
{
StudentVM model = new StudentVM();
ConfigureCreateViewModel(model);
return View(model);
}
[HttpPost]
public ActionResult Create(StudentVM model)
{
if(!ModelState.IsValid)
{
ConfigureCreateViewModel(model); // reassign the select list
return View(model); // return the view so user can correct errors
}
StudentDto student = new StudentDto()
{
FirstName = model.FirstName,
LastName = model.LastName,
EmailAddress = mdoel.EmailAddress,
Department = db.Departments.Find(model.SelectedDepartment) // modify to suit
}
// save StudentDto and redirect
}
private void ConfigureCreateViewModel(StudentVM model)
{
List<DepartmentDto> departments = // call a service to get a collection of all departments
model.DepartmentList = new SelectList(departments, "DepartmentId","DepartmentDescription");
}
View
#model yourAssembly.StudentVM
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.FirstName)
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(m => m.FirstName)
.... // other controls of StudentVM
#Html.LabelFor(m => m.SelectedDepartment)
#Html.DropDownListFor(m => m.SelectedDepartment, Model.DepartmentList, "--Please select--")
#Html.ValidationMessageFor(m => m.SelectedDepartment)
<input type="submit" value="submit"/>
}
Side notes:
Use #Html.LabelFor(m => m.FirstName) rather than <label>First
Name</label>. A <label> is an element associated with a control
(clicking on it sets focus to the associated control) - you usage
does nothing because it is missing the for attribute
The html helper methods correctly give the elements an id and
name attribute. In you case you are generating invalid html by
creating duplicate id attributes (the first 3 elements have
id="testid1") and you should never attempt to set the name
attribute (in the first 3 cases, your just setting it to what it
already is anyway, but in the case of the dropdown, you trying to
change it to name="dept" which fortunately does not work - because
if it did, binding would fail!)
You should also consider adding validation attributes to your view
model properties, e.g. [Required(ErrorMessage="Please enter a first
name")] and in the view including #Html.ValidationMessageFor(m =>
m.FirstName)

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,

MVC 4, Model and model render differently

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; }
}

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)