Save multiply records from one form - asp.net-mvc-3

I have one form when I return all products. And next to everyone product I have TextBox.
View form:
|ID|Product|TextBox (amount of product)
|3 |Carrot | 20
|4 |Potatos| 5
|7 |Tomato | 10
In this textbox I write a amount of the products and save this to database
Add(zuzycie) table:
|ID|ID_Product|amount|date
|1 | 3 | 20 |3.12.2011
|2 | 4 | 5 |3.12.2011
|3 | 7 | 10 |3.12.2011
and sum amount of product in other (product) databse.
Product table
|ID|name |amount
|3 |Carrot |10 + 20
|4 |Potatos|15 + 5
|7 |Tomato |7 + 10
In database, amount are save as seperate record. I hope you are understand what I have meaning.
How to get ID of everyone products in controller and save it in database?
View:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Zużycie produków</legend>
<br />
#{
var grid = new WebGrid(ViewBag.produkty,null, "Produkty", 5);
}
#grid.GetHtml(
tableStyle: "grid",
headerStyle: "head",
alternatingRowStyle: "alt",
columns: grid.Columns(
grid.Column("nazwa_prod","Produkt"),
grid.Column("ilosc","Ilość"),
grid.Column("jednostka","Jed."),
grid.Column("cena","Cena"),
grid.Column("nazwa","Firma"),
grid.Column("ID_Produkt", "ID_Prod" ),
grid.Column(header: "Zuzycie", format: (item) =>
new HtmlString(
Html.TextBoxFor(model => model.ilosc).ToString())) /*amount text box */
)
)
Model:
public class zuzycieModel
{
public int ID_Produktu { get; set; } //Id_product
public decimal ilosc {get;set;} //amount
public string data { get; set; } //date
}
Controller:
public ActionResult zuzycie()
{
var prod = (from d in baza.Produkts
join s in baza.Firmas on d.ID_firma equals s.ID_firma
select new { d.ID_firma, d.nazwa_prod, d.ilosc, d.jednostka, d.cena, d.ID_Produkt, s.nazwa }).ToList();
ViewBag.produkty = prod;
return View();
}
[HttpPost]
public ActionResult zuzycie(zuzycieModel model)
{
Zuzycie zuz = new Zuzycie(); //table zuzycie
var dat = DateTime.Today;
zuz.ID_Produkt = model.ID_Produktu; //Id product
zuz.ilosc = model.ilosc; //amount
zuz.data = dat; //date
baza.Zuzycies.InsertOnSubmit(zuz);
baza.SubmitChanges();
return RedirectToAction("zarzadzaj_produktami", "Produkt");
}
I try get ID of product, I putted it in View as HiddenFor and get using model... but it doesn't work...

I'm not clear on what was your idea with HttpPost zuzycie() method. What is Zuzycie() ? You're asking about saving multiple records but your ZuzycieModel cleary refers to a single ProductID.
Why are you using a ViewBag to pass the collection to your View ? can't you just return it through
return View(prod);
Notice what are you passing - Collection (a List<>) and I don't see this to be reflected in your data persistance logic.

Related

MVC 3 dropdownfor populated but cannot get user's selection

I'm new to MVC 3. I want 3 dropdown lists. The user picks an item from each list and then retrieves the selections based on the matches. For my problem I'm just using 2 dropdowns and code snippets. I have all 3 dropdowns populated - the first two from Linq to Sql and the 3rd is an option list created with Razor (A-Z).
I'm missing the step of setting the values of what was chosen into MemberSetup.SelectedProgramID and MemberSetup.SelectedOrganizationID. I'd like the text stored in MemberSetup.SelectedProgramName and MemberSetup.SelectedOrganizationName respectively. I think if I can get the selected ids into the model, I can pass them through ActionLink and not deal with #Html.Hidden variables. However, no matter what is selection the model SelectedProgramID and SelectedOrganizationID are zero (expect 1, 2, 3 or 4 for Program ID and 1, 2, 5, or 6 for Organization ID).
Any help / corrections would be appreciated.
Model:
{
public int SelectedProgramID { get; set; }
public string SelectedProgramName {
get { return this._myProgramName; }
set { this._myProgramName = value; }
}
public IEnumerable<SelectListItem> ProgramList { get; set; }
public int SelectedOrganizationID { get; set; }
public string SelectedOrganizationName
{
get { return this._myOrganizationName; }
set { this._myOrganizationName = value; }
}
public IEnumerable<SelectListItem> OrganizationList { get; set; }
}
Controller:
{
var db = new STARDataContext();
MemberSetup setupModel = new MemberSetup();
setupModel.ProgramList = db.ProgramAlls.ToList()
.Select(p => new SelectListItem
{
Value = p.ProgramID.ToString(),
Text = p.ProgramName.ToString()
});
setupModel.OrganizationList = db.AreaAlls.ToList()
.Select(p => new SelectListItem
{
Value = p.AreaID.ToString(),
Text = p.AreaName.ToString()
});
return View(setupModel);
}
View:
{
#using ( Html.BeginForm() ) {
#Html.DropDownListFor(model => model.SelectedProgramID, Model.ProgramList)
#Html.DropDownListFor(model => model.SelectedOrganizationID, Model.OrganizationList, "Please select Organization", new { #class = "DropDownList" } )
#Html.Hidden("SelectedProgramID", Model.SelectedProgramID)
#Html.Hidden("SelectedProgramName", Model.SelectedProgramName)
#Html.Hidden("SelectedOrganizationID", Model.SelectedOrganizationID)
#Html.Hidden("SelectedOrganizationName", Model.SelectedOrganizationName)
#Html.ActionLink("Get Members", "Select", new {programID=Model.SelectedProgramID,orgID=Model.SelectedOrganizationID })
}
}
use hiddenFor instead of hidden,so your syntax should look like this
#Html.HiddenFor(a=>a.SelectedProgramName)
Since you have SelectedProgramID and SelectedOrganizationID defined, you won't need to use hidden field for it. To construct the dropdown, you should do something like this
Html.DropDownListFor(x=>x.ID,
new SelectList(Model.Products,"ID", "Sku", Model.ID), " select ")
For your reference: Use Html.DropDownListFor to get a selected value
The above class, controller and view are correct for presenting the drop-downs. This is why I was perplexed.
However, I had the SelectMember in the Get section. [HttpPost] and SelectMember can see what was selected.

Submit column values in ASP.Net MVC3

I'm using ASP.Net MVC3, I've a View in which I'm displaying a simple Table with Model Data as follows:
+-------+---------------+----------------+
| ID | Name | Order |
+-------+---------------+----------------+
| ID | Name | textbox val=1 |
+-------+---------------+----------------+
| ID | Name | textbox val=3 |
+-------+---------------+----------------+
| ID | Name | textbox val=2 |
+-------+---------------+----------------+
+-------+ +--------------+
|submit | | update order |
+-------+ +--------------+
Here, Order column contains Inputbox with Order values (1,3,2 etc.,). I need to Update my Model [Item {ID, Name, Order}]by reading Order column.
Meaning, I need to submit the Order values to Model, by reading a HTML table column. How to do this?
Create a view model for each item:
public class ItemViewModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
And a model for the action:
public class EditViewModel
{
public IEnumerable<ItemViewModel> Items { get;set; }
public int Index { get; set; }
}
Render the rows like this:
#foreach (var item in Model.Items)
{
<tr>
<td><input type="hidden" name="Id[#Model.Index]" value="#item.Id" />#item.Id</td>
<td>#item.Name</td>
<td><input type="text" name="Value[#Model.Index]" value="#item.Value" /></td>
</tr>
#{ Model.Index = Model.Index + 1 }
}
And finally receive the rows as:
[HttpPost]
public ActionResult Edit(ItemViewModel[] items)
{
}

Incorporating custom view model data from multiple tables into a view

I can't understand why I can't find anything that clearly explains how to do this with MVC. Seems like a pretty routine issue:
I have three tables:
PackageName: PackageNameID,PackageName
Food: FoodID,Food
PackageContent: PackageContentID, PackageNameID, FoodID, Qty
The application is supposed to describe packages of food. For example, a package named "A" might contain 4 onions and 3 peppers. Another package, "B", might contain 2 rolls and 2 onions.
Currently I have a custom view model ("PackageNameModel") that collects the data:
public ViewResult Index() {
var viewModel =
from pn in db.PackageNames
from pc in db.PackageContents
.Where(p => p.PackageNameID == pn.PackageNameID).DefaultIfEmpty()
from f in db.Foods
.Where(f => f.FoodID == pc.FoodID).DefaultIfEmpty()
select new PackageFoodModel { PackageName = pn, PackageContent = pc, Food = f };
return View( viewModel );
}
This returns the data correctly, but what do I do with it so that the view is actually one that is useful for the application?
Using this in my view:
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.PackageName.PackageName1 ) ,
#Html.DisplayFor(modelItem => item.Food.Food1)=#Html.DisplayFor(modelItem => item.PackageContent.Qty)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.PackageName.PackageNameID }) |
#Html.ActionLink("Details", "Details", new { id = item.PackageName.PackageNameID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.PackageName.PackageNameID })
</td>
</tr>
}
I am able to display the following:
- A , Onions=4 Edit | Details | Delete
- A , Peppers=3 Edit | Details | Delete
- B , Rolls=2 Edit | Details | Delete
- B , Onions=2 Edit | Details | Delete
This is not very useful. What I'm trying to do is display something like this:
- A (Onions=4,Peppers=3) Edit | Details | Delete
- B (Rolls=2,Onions=2) Edit | Details | Delete
Eventually, the next page down after navigating to the "Edit" action would provide an editable name for the package as well as a table of all available foods and an adjacent quantity box so that the foods/quantities within each package may be updated.
Can anyone explain how this is done within the MVC framework?
All the tutorials I have seen on the web/in books deal with data that is much simpler. Can anyone point me to some sample code / tutorials that deal with something like this?
Thanks in advance!
You need to aggregrate your results.
Create a view model like this
public class PackageViewModel
{
public int ID { set;get;}
public string Name { set;get;}
public List<FoodItem> FoodItems { set;get;}
public PackageViewModel()
{
FoodItems=new List<FoodItem>();
}
}
public class FoodItem
{
public string FoodName { set;get;}
public int Quantity { set;get;}
}
and in your Get action, You need to do the aggregate the data from your data which is ccoming from your data access layer and fill to the ViewModel List
public ActionResult IndeX()
{
List<PackageViewModel> listVM=new List<PackageViewModel>();
//Get your data and do aggregation and fill in listVM
return View(listVm)l
}
and in our view,
#model List<PackageViewModel>
#foreach(var item in Model)
{
<tr>
<td>#item.Name</td>
<td>
foreach(var food in item.FoodItems)
{
#food.FoodName - #food.Quantity
}
</td>
<td>
#Html.ActionLink("Edit","Edit",new {#id=item.ID})
</td>
</tr>
}

MVC 3 - validating values on multiple rows

I have an MVC project similar to this...
Model
Public Class ItemDetails
Public Property SerialNo As Integer
Public Property Description As String
Public Property GroupNo As Integer
Public Property Price As String
Public Property Quantity As Integer
End Class
Controller
Function ListItems() As ActionResult
' GetItems retrieves the items from the database
Dim i As List(Of ItemDetails) = ItemsRepository.GetItems
Return View(i)
End Function
View
#ModelType List(Of MyApp.ItemDetails)
#Using Html.BeginForm()
Dim RowNo As Integer
For i As Integer = 0 To Model.Count - 1
RowNo = i
#Html.HiddenFor(Function(model) model(RowNo).SerialNo)
#Html.LabelFor(Function(model) model(RowNo).Description)
#Html.HiddenFor(Function(model) model(RowNo).GroupNo)
#Html.LabelFor(Function(model) model(RowNo).Price)
#Html.TextBoxFor(Function(model) model(RowNo).Quantity)
Next
End Using
Note: This is done from memory so may not be completely accurate.
As you can see this displays a list of items. The items are retrieved from a database. Each item has a description and a Group No. The user can enter how many of each item they would like to order.
Two or more items can be in the same group. For examle there might be: Item 1 in Group 1, Item 2 in Group 1, Item 3 in Group 2 and Item 4 in Group 3.
When the user clicks submit I would like to validate that for each Group No the combined Quantity does not exceed 10. So in the example above if I enter a Quantity of 7 for Item 1 then quantity for Item 2 must be 3 or less.
I can validate this easily client side.
What is the best way to go about validating this server side (where and how)?
I need to total the combined value of Quantity does not exceed 10 for each Group No and if it does display an error.
Personally I use FluentValidation.NET for this kind of tasks. It allows you to define your complex validation rules for a given view model into a separate layer, express them in a fluent manner, it has an absolutely marvelous and seamless integration with ASP.NET MVC and allows you to unit test your validation logic in isolation.
If you don't want to use third party libraries you could always write a custom validation attribute and decorate your view model property with it. You could introduce a view model that will contain the collection of ItemDetails as a property and then decorate this property with your custom validator.
public class ItemDetails
{
public int SerialNo { get; set; }
public string Description { get; set; }
public int GroupNo { get; set; }
// Please take a note that I have allowed myself
// to use the decimal datatype for a property called
// Price as I was a bit shocked to see String in your code
public decimal Price { get; set; }
public int Quantity { get; set; }
}
public class MyViewModel
{
[EnsureMaxGroupItems(10, ErrorMessage = "You cannot have more than 10 items in each group")]
public IList<ItemDetails> Items { get; set; }
}
and the validation attribute itself:
[AttributeUsage(AttributeTargets.Property)]
public class EnsureMaxGroupItemsAttribute : ValidationAttribute
{
public int MaxItems { get; private set; }
public EnsureMaxGroupItemsAttribute(int maxItems)
{
MaxItems = maxItems;
}
public override bool IsValid(object value)
{
var items = value as IEnumerable<ItemDetails>;
if (items == null)
{
return true;
}
return items
.GroupBy(x => x.GroupNo)
.Select(g => g.Sum(x => x.Quantity))
.All(quantity => quantity <= MaxItems);
}
}
and finally your controller actions will work with the view model:
public ActionResult ListItems()
{
var model = new MyViewModel
{
Items = ItemsRepository.GetItems()
};
return View(model);
}
[HttpPost]
public ActionResult ListItems(MyViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
...
}
and next the corresponding strongly typed view:
#model MyViewModel
#Html.ValidationSummary()
#using (Html.BeginForm())
{
#Html.EditorFor(x => x.Items)
<button type="submit">Go go go</button>
}
and the last bit is the corresponding editor template that will automatically be rendered for each element of the Items collection so that you don't even need to write for loops (~/Views/Shared/EditorTemplates/ItemDetails.cshtml):
#model ItemDetails
#Html.HiddenFor(x => x.SerialNo)
#Html.LabelFor(x => x.Description)
#Html.HiddenFor(x => x.GroupNo)
#Html.LabelFor(x => x.Price)
#Html.TextBoxFor(x => x.Quantity)

MVC3 Dropdown drillthrough hierarchy

I have a table for product category that has a hierarchical structure. Each Category_ID may have a number of children determined by their Parent_id. For example Air Fresheners (26) has children 26, 27 and 28 as they have a Parent_id of 25.
I would like to set up a page to drill through the categories with dropdowns. A user would select a level 2 category such as Air Fresheners they would then get a dropdown containing children of the previous selection.
What is the best way to do this? I am considering jQuery and JSON, but there might be a better way.
I have the following GetCategoryChildren method:
public string ThisName { get; set; }
public int ThisHLevel { get; set; }
public IEnumerable<SelectListItem> Children { get; set; }
public GetCategoryChildren(int category_ID)
{
var rep = new Product_CategoryRepository();
Children = rep.All.Where(x => x.Parent_id == category_ID).ToList()
.Select(x => new SelectListItem
{
Text = x.Name,
Value = x.Category_ID.ToString()
});
ThisName = rep.All.Where(x => x.Category_ID == category_ID)
.FirstOrDefault().Name;
ThisHLevel = rep.All.Where(x => x.Category_ID == category_ID)
.FirstOrDefault().HLevel;
}
Lend me your brains.
Take a look at Project Awesome
The AjaxDropdown does the trick.

Resources