Edit part of the fields? - c#

I have the following model.
public class M
{
public int Id { get; set; }
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
public int D { get; set; }
....
}
The Asp.Net Mvc 4 page need only edit one column. And I had to put #Html.HiddenFor() for all other columns - otherwise the database column for B, C, D.... will be reset to 0s. Is it a way to avoid it?
#model MyMvc.Models.M
#using (Html.BeginForm()))
{
#Html.HiddenFor(m => m.Id)
#Html.EditorFor(m => m.A)
#Html.HiddenFor(m => m.B)
#Html.HiddenFor(m => m.C)
#Html.HiddenFor(m => m.D)
......
}

You can just put a hidden field for Id and handle the others in your action method like this:
public ActionResult SaveM(M m)
{
var mToEdit = db.find(m.Id);
mToEdit.A = m.A;
db.SaveChanges();
//.......
}

HiddenFor just generates hidden field, but this never ensures that value will not be edited. Simple F12 click and anyone can edit value with developer tools. Instead, you should create ViewModel with that single field and check everything on server side
public class EditMViewModel
{
public int A { get; set; }
}
And something like this in controller action
public ActionResult Edit(int id, EditMViewModel m)
{
var someObject = LoadFromDb(id);
if (ModelState.IsValid)
{
someObject.A = m.A;
SaveToDb(someObject)
}
return RedirectToAction("Index");
}

Related

Object reference not set to an instance of an object., model is null

I am trying to display a checklist that gets data from MySQL Database and displays it in a view and updates the value of the variable (IsChecked) of each element in the table by whether we have checked the amenity or not (i am displaying some amenities). The model of the view is Hotel_5.ViewModel.BookingRoom, where BookingRoom is a custom model i created where i use multiple models. I get the exception at Model.AmenitiesList.Count(). The model is null.
This is my view
<div class="form-group">
#for (var i = 0; i < Model.AmenitiesList.Count(); i++)
{
#Html.CheckBoxFor(m => m.AmenitiesList[i].IsChecked, new { #class = "form-control" });
<label>#Model.AmenitiesList[i].amenityType</label>
//If you need to hide any values and get them in your post
#Html.HiddenFor(m => m.AmenitiesList[i].AmenityId)
#Html.HiddenFor(m => m.AmenitiesList[i].AmenityPrice)
}
</div>
This is my ViewModel
public class BookingRoom
{
public Bookings bookings { get; set; }
public Rooms rooms { get; set; }
public List<Amenities> AmenitiesList { get; set; } = new List<Amenities>();
}
This is my Amenities Model
public class Amenities
{
[Key]
public int AmenityId { get; set; }
public double AmenityPrice { get; set; }
public AmenityType amenityType { get; set; }
public bool IsChecked { get; set; }
}
public enum AmenityType
{
tv,
wi_fi,
hair_dryer,
help
}
When Querying you should Include its AmenitiesList too, otherwise it will be null:
In Controller:
var bookingRoom = context.BookingRooms.Include(b => b.AmenitiesList).FirstOrDefault(b => b.Id == someId);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
please note that what I queried might not be what you want, it is just to demonstrate how to use Include() and also you should add using Microsoft.EntityFrameworkCore.

How to return two models in MVC?

I have this function that will be called in the controller:
public EditViewModel PostEditViewModel(EditViewModel model)
{
using (var db = new NorthwindEntities())
{
var prod = db.Products.Where(x => x.Id == model.Id).Single();
{
prod.Id = model.Id;
...
//I need something like this:
//prod.CategoryID = model.CategoryList.CatId
//but obviously intellisense tells me that after the dot of CategoryList, only methods of that list can be called.
db.SaveChanges();
}
and this is my ViewModel:
public int Id{ get; set; }
...
public IEnumerable<Categories> CategoryList { get; set; }
public class Categories {
public int ProdId { get; set; }
public int? CatId { get; set; }
public string CatName { get; set; }
}
how do I call the CategoryList through my EditViewModel so that I can edit the Category of a specific product through HTML.DropdownList?
If your product model have CategoryId property (I just can't see it in your question) and you using strongly typed View You always can use this overload of DropDownListBoxFor() helper:
#Html.DropDownListFor(
x => x.CategoryId,
new SelectList(Model.CategoryList, "CatId", "CatName")
)
But actually i recomend you to use SelectListItem in ViewModels for all your dropdowns, becouse it's really bad practice - put domain entity on your View
Than your ViewModel will be like:
public int Id { get; set; }
public int CategoryId { get; set; }
...
public IEnumerable<SelectListItem> CategoryList { get; set; }
And on the View you can do this way:
#Html.DropDownListFor(x => x.CategoryId, Model.CategoryList)
In your GET ViewModel Controller you can initialize your CategoryList like this:
model.CategoryList = db.Categories.OrderBy(x => x.Name)
.Select(x => new SelectListItem
{
Text = x.Name,
Value = x.Id.ToString()
});
It really helps you to get your Views cleaner.
It looks like CategoryList is used to populate the items in your DropDownList, and CatId is the property on your view model that captures the ID value of the selected category.
If that is the case, you can just assign it like so:
if (model.CatId.HasValue)
{
prod.CategoryID = model.CatId.Value;
}
If I not mistaken and I understood you, you should to create class EditViewModel in this class create the fields:
public int Id{ get; set; }
...
public IEnumerable<Categories> CategoryList { get; set; }
Next, in your controller, you should use the following code:
var prod = db.Products.Where(x => x.Id == model.Id).Single();
{
prod.Id = model.Id;
...
prod.CategoryID = model.CategoryList.Select(m => m.CatId)
//but Select returned the List of CatId, I suggest thet prod.CategoryID is List
}
db.SaveChanges();

how to use ICollection for SelectList in Contoller of MVC?

I am developing .NET MVC application.
I want to send the collection of the objects from controller to View using select list.
without using view bag.
ViewModel :
public class AdviceCreateVM
{
public int Id { get; set; }
public string AdviceNo { get; set; }
public ICollection<CompanyVM> Companies { get; set; }
}
public class CompanyVM
{
public int Id { get; set; }
public string Name { get; set; }
}
Controller Code :
public class AdviceCreateController : Controller
{
public ActionResult Create()
{
adviceVM.Companies = new SelectList(ledgerService.GetAll().OrderBy(t => t.Name), "Id", "Name");
}
}
It gives an error -
Cannot implicitly convert type 'System.Web.Mvc.SelectList' to
'System.Collections.Generic.ICollection'. An
explicit conversion exists (are you missing a cast?)
You're trying to assign a SelectList to property of type ICollection<CompanyVM> -- which won't work. You need some like:
var viewModel = new AdviceCreateVM
{
adviceVM.Companies =
ledgerService.GetAll().OrderBy(t => t.Name)
.Select(t=>
new CompanyVM
{
Id = t.Id, // "Id"
Name = t.Name // "Name"
})
.ToList()
};
I'm just guessing on the assignments here, since you didn't specify them.
In the view, you will have to make the select list from Companies property.
#Html.DropDownListFor(model => model.CompanyId,
model.Companies.Select(company =>
new SelectListItem
{
Value = company.Id,
Text = company.Name
}), "--Select Company--")
As indicated in the comments, SelectList does not implement ICollection. Change you view model collection to SelectList
public class AdviceCreateVM
{
public int Id { get; set; }
public string AdviceNo { get; set; }
public SelectList Companies { get; set; } // change to select list
public int CompanyID { get; set; } // for binding the the drop down list
}
Controller
public ActionResult Create()
{
AdviceCreateVM model = new AdviceCreateVM(); // initialise model
model.Companies = new SelectList(ledgerService.GetAll().OrderBy(t => t.Name), "Id", "Name");
}
View
#model YourAssembly.AdviceCreateVM
#using (Html.BeginForm()) {
....
#Html.DropDownFor(m => m.CompanyID, Model.Companies)
...

Asp.net razor textbox array for list items

I can't find or figure out how to take a list of items (cupcakes) and display them in razor with a quantity field.
What is happening is I am not able to get the values for each cupcake quantity in the list. Can you do textbox arrays in Razor?
VIEW
<div class="form-group">
<label>Cupcakes</label>
#foreach (var cupcake in Model.CupcakeList)
{
#Html.TextBox("CupcakeQuantities", cupcake.Id) #cupcake.Name <br/>
}
</div>
MODEL
public List<Cupcake> CupcakeList { get; set; }
public List<int> CupcakeQuantities { get; set; }
CONTROLLER
public ActionResult Create()
{
var model = new PartyBookingModel()
{
CupcakeList = db.Cupcakes.ToList(),
CupcakeQuantities = new List<int>()
};
return View(model);
}
CUPCAKE (ENTITY)
public class Cupcake
{
public int Id { get; set; }
public string Name { get; set; }
public decimal PerDozen { get; set; }
}
You have to use an index, rather than foreach for it to work.
#for (int i = 0; i < Model.CupcakeList.Count; i++)
{
#Html.TextBoxFor(x=>Model.CupcakeQuantities[i]) #Model.CupcakeList[i].Name <br/>
}
This will create sequentially named+number entries that will be recombined back into the model on post back.
I realise this may seem like "why doesn't foreach work?", but with foreach there is not enough reflected information available to TextBoxFor (as it is just a single object), whereas the array index is extracted by reflection from the Model.CupcakeQuantities[i] expression.
The receiving controller method should take the same as the model passed to the view:
e.g.
[HttpPost]
public ActionResult(PartyBookingModel model)
Try it this way:
view:
#for (int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(x=>Model[i].Id) #Model[i].Name
#Html.TextBoxFor(x => Model[i].Quantity) <br/>
}
model:
public class CupcakeViewModel
{
public int Id {get;set;}
public string Name {get;set;}
public int Quantity {get;set;}
}
controller:
public ActionResult Create()
{
var model = db.Cupcakes.Select(c => new CupcakeViewModel {
Id = c.Id,
Name = c.Name,
Quantity = 0
})
.ToList();
return View(model);
}
[HttpPost]
public ActionResult Create(CupcakeViewModel[] cakes)
{
//Save choosen cakes
}

Asp.net MVC dropdownlist binding by using model classes

I am writing MVC listing page which need to bundle with dropdownlist.
As I am very junior to ASP.net MVC, i don't know how to make dropdownlist to run correctly and make selected dynamically.
I have two model classes
public class CycleType
{
public int CycleTypeID { get; set; }
public string Type { get; set; }
public List<CycleModel> CycleModels { get; set; }
}
-----------------------------------------------------------
public class CycleModel
{
public int CycleModelID { get; set; }
public int CycleTypeID { get; set; }
public string Model { get; set; }
public virtual CycleType CycleType { get; set; }
}
Then one Controller class,
public class CycleModelController : Controller
{
UnitOfWork<CycleModel> unitOfWork = new UnitOfWork<CycleModel>();
UnitOfWork<CycleType> unitOfWork_cycleType = new UnitOfWork<CycleType>();
...
[HttpGet]
public ActionResult Edit(int CycleModelID)
{
CycleModel cycleModel = unitOfWork.GenericTEntityRepository.GetByID(CycleModelID);
ViewBag.CycleType = new SelectList(unitOfWork_cycleType.GenericTEntityRepository.Get(orderBy: CycleTypes => CycleTypes.OrderBy(CycleType => CycleType.Type)));
return View(cycleModel);
}
...
}
Then One Razor file,
<div class="editor-field">
#*Html.DropDownList("CycleType")*#
#*Html.EditorFor(model => model.CycleTypeID)*#
#Html.DropDownListFor(model => model.CycleTypeID,
new SelectList(ViewBag.CycleType, "Type", "CycleTypeID"))
#Html.ValidationMessageFor(model => model.CycleTypeID)
</div>
When I run my program, I get error message
DataBinding: 'System.Web.Mvc.SelectListItem' does not contain a property with the name 'Type'.
1)How could I make correct this code ?
2)How could I make select item dynamically ?
Every suggestion will be really appreciated.
 
The ViewBag.CycleType is already a SelectList. Hence you can use that directly.
#Html.DropDownListFor(model => model.CycleTypeID, (SelectList)ViewBag.CycleType)
You can change the controller code as follows.
ViewBag.CycleType = new SelectList(
unitOfWork_cycleType.GenericTEntityRepository.Get(
orderBy: CycleTypes => CycleTypes.OrderBy(CycleType => CycleType.Type)),
"Type", "CycleTypeID");

Categories