How should my model be to store data in database from dynamically added textboxes? - asp.net-mvc-3

My model:
public class Order
{
public int OrderId { get; set; }
public int Quantity { get; set; }
public double Width { get; set; }
public double Height { get; set; }
}
In my strongly-typed view for that model I have a form with TextBoxFor for that properties like:
<table>
<tr>
<td>+</td>
<td>#Html.TextBoxFor(m => m.Quantity)</td>
<td>#Html.TextBoxFor(m => m.Width)</td>
<td>#Html.TextBoxFor(m => m.Height)</td>
</tr>
</table>
The link with the AddTextBox() is a jQuery function to dynamically add another table like that containing more than three textboxes.
My controller:
[HttpPost]
public ActionResult SaveOrder(Order order)
{
context.Order.Add(order);
context.SaveChanges();
return View();
}
When debugging I can see that the order object is filled with the data from the form but only with the first quantity, weight and height textbox's values, I know that is the expected behavior and I know I'm receiving all values because I tested like the example below and my Lists got filled correctly:
[HttpPost]
public ActionResult SaveOrder(List<int> Quantity, List<int> Width, List<int> Height)
{
return View();
}
So here is the question again: how should I create a model to hold that array of data and save on my database?
I hope I was clear with the question and thanks for your answer.

Your view model has to have a list that you are going to add to. You cannot add models to fixed instance of singletone (which the #model is inside your view). SO your model has to be extendable.
Here is your sample, Editing a variable length list, ASP.NET MVC
Look what they've done and do the same for your control and view. I built my app completely based on this article - its simple enough to understand for even newbie (with basic knowledge) and implement similar functionality within your realm.
They also have full demo source code you can download and play with
Its just too long to describe the process, in simple words you
create dedicated action in your controller and call it using ajax to generate whatever you want to add to your view (textbox in your case, but it can certainly be something much more complex) and
$(<your selector>).append(<your result from ajax call>).
On posting back to controller you get the list with actual number of items that you added/removed in your view
One by one you add them to your DTO and commit the transaction when you done.
Hope this helps.

Finally !
I don't know if I was very clear on my question but here is the solution I found, I don't know if that is very simple or not because I'm not very experienced with programming, so thanks to who tried to help me.
Istead of having only one model I had to create another on to hold on my database all the Measures that every order has, so I changed my model to look like this:
public class Order
{
public int OrderId { get; set; }
public virtual List<Measures> Measures { get; set;}
// I have many other properties here but i erased for simplicity...
}
public class Measures
{
public int MeasuresId { get; set; }
public int Quantity { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public Order Order { get; set; }
}
So on my view after adding some <input> dinamically all their name attribute was Quantity, Width or Height and the response I was receiving on my controller was like this:
Quantity: 10
Width: 20
Height: 16
Quantity: 3
Width: 14
Height: 10
Quantity: 500
Width: 2
Height: 5
Finally, my controller is:
[HttpPost]
public ActionResult SaveOrder(Order Order, List<int> Quantity, List<double> Width, List<double> Height)
{
List<Measures> Measures = new List<Measures>();
//At this point my Order model is filled with all the properties
//that came from the form and I'll save it to the Database so that
//this model can have its Id filled from the identity column
unitOfWork.ServicosRepository.Insert(Order);
unitOfWork.Save();
//Now that I have the OrderId I can add how much Measures I want referencing
//that OrderId to access that further on my View
for (int i = 0; i < Quantity.Count; i++)
{
Measures measures = new Measures { Quantity = Quantity[i], Width = Width[i], Height = Height[i], Order = Order };
unitOfWork.MedidasRepository.Inserir(medidas);
unitOfWork.Salva();
Medidas.Add(medidas);
}
return PartialView("_Emitir", Pedido);
}

Related

How to update hierarchical ViewModel?

I am stuck with this problem.
I have a model AssessmentModel defined like this:
public class AssessmentModel
{
public Respondent Respondent { get; set; }
public List<CompetencyModel> Competencies { get; set; }
}
public class CompetencyModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<ResultModel> Results { get; set; }
}
public class ResultModel
{
public int Id { get; set; }
public int Score { get; set; }
}
All I need is to set value to the Score property of ResultModel.
Score is the only editable property here.
And I have just 1 View only, this view has a #model List, it displays a list of CompetencyModel items with Edit button for each one.
When I click the Edit button, the Id of CompetencyModel is passed to the same View, and the View draws an Edit form for ResultModel items that belong to the selected CompetencyModel.
However the form for ResultModel items exists on the same View, and the model of the View is still #model List.
How can I get to the Score property by using bindable Html.EditorFor(m=>m.Score) helper for each ResultModel item?
The View is defined like this:
#model List<CompetencyModel>
#foreach(var comp in Model)
{
<p>#comp.Name</p>
Edit
}
In the controller I set ViewBag.CurrentId = comp.Id, and at the bottom of the View:
if(ViewBag.CurrentId != null) //draw a form for ResultModel items
{
// What should I do now?
// how cant I use Html.EditorFor(m=>...) if the Model is still List<CompetencyModel>
}
I need to get to a single ResultModel entity to set a value to a Score property.
Thank you.
You should be able to get this done using Linq. Consider having the following code segment in the your last if statement
var result = Model.Results.FirstOrDefault(r => r.Id == ViewBag.CurrentId);
I dont have a IDE with me, so watchout for syntext errors

implementing dropdownlist in asp.net mvc 3

I am teaching myself asp .net mvc3. I have researched a lot but the more I read the more confused I become. I want to create a page where users can register their property for sale or rent.
I have created a database which looks like this:
public class Property
{
public int PropertyId { get; set; }
public int PropertyType { get; set; }
ยทยทยท
public int Furnished { get; set; }
...
}
Now, I want dropdownlistfor = PropertyType and Furnished.
Property type would be
1 Flat
2 House
3 Detached House
...
Furnished would be:
1 Furnished
2 UnFurnished
3 PartFurnished
...
Now, I am really not sure where to keep this information in my code. Should I have 2 tables in my database which store this lookup? Or should I have 1 table which has all lookups? Or should I just keep this information in the model?
How will the model bind to PropertyType and Furnished in the Property entity?
Thanks!
By storing property types and furnished types in the database, you could enforce data integrity with a foreign key, rather than just storing an integer id, so I would definitely recommend this.
It also means it is future proofed for if you want to add new types. I know the values don't change often/will never change but if you wanted to add bungalow/maisonette in the future you don't have to rebuild and deploy your project, you can simply add a new row in the database.
In terms of how this would work, I'd recommend using a ViewModel that gets passed to the view, rather than passing the database model directly. That way you separate your database model from the view, and the view only sees what it needs to. It also means your drop down lists etc are strongly typed and are directly in your view model rather than just thrown into the ViewBag. Your view model could look like:
public class PropertyViewModel
{
public int PropertyId { get; set; }
public int PropertyType { get; set; }
public IEnumerable<SelectListItem> PropertyTypes { get; set; }
public int Furnished { get; set; }
public IEnumerable<SelectListItem> FurnishedTypes { get; set; }
}
So then your controller action would look like:
public class PropertiesController : Controller
{
[HttpGet]
public ViewResult Edit(int id)
{
Property property = db.Properties.Single(p => p.Id == id);
PropertyViewModel viewModel = new PropertyViewModel
{
PropertyId = property.Id,
PropertyType = property.PropertyType,
PropertyTypes = from p in db.PropertyTypes
orderby p.TypeName
select new SelectListItem
{
Text = p.TypeName,
Value = g.PropertyTypeId.ToString()
}
Furnished = property.Furnished,
FurnishedTypes = from p in db.FurnishedTypes
orderby p.TypeName
select new SelectListItem
{
Text = p.TypeName,
Value = g.FurnishedTypeId.ToString()
}
};
return View();
}
[HttpGet]
public ViewResult Edit(int id, PropertyViewModel propertyViewModel)
{
if(ModelState.IsValid)
{
// TODO: Store stuff in the database here
}
// TODO: Repopulate the view model drop lists here e.g.:
propertyViewModel.FurnishedTypes = from p in db.FurnishedTypes
orderby p.TypeName
select new SelectListItem
{
Text = p.TypeName,
Value = g.FurnishedTypeId.ToString()
};
return View(propertyViewModel);
}
}
And your view would have things like:
#Html.LabelFor(m => m.PropertyType)
#Html.DropDownListFor(m => m.PropertyType, Model.PropertyTypes)
I usually handle this sort of situation by using an enumeration in code:
public enum PropertyType {
Flat = 1,
House = 2,
Detached House = 3
}
Then in your view:
<select>
#foreach(var val in Enum.GetNames(typeof(PropertyType)){
<option>val</option>
}
</select>
You can set the id of the option equal to the value of each item in the enum, and pass it to the controller.
EDIT: To directly answer your questions:
You can store them as lookups in the db, but for small unlikely to change things, I usually just use an enum, and save a round trip.
Also look at this approach, as it looks better than mine:
Converting HTML.EditorFor into a drop down (html.dropdownfor?)

select the value to populate html.dropdownlist

I have two classes as follows
public class ODCTE_Major
{
public int ODCTE_MajorId { get; set; }
public string OfficialMajorName { get; set; }
public string MajorCode { get; set; }
... More unrelated code ....
}
AND
public class CareerMajor
{
...lots of unrealted code to this question left out
public int ODCTE_MajorId { get; set; }
public virtual ODCTE_Major ODCTE_Major { get; set; }
}
I added a controller with CRUD methods and in the create.cshtml there is this line
<div class="editor-field">
#Html.DropDownList("ODCTE_MajorId", String.Empty)
#Html.ValidationMessageFor(model => model.ODCTE_MajorId)
</div>
The select list populates it with the OfficialMajorName from ODCTE_Major. I need the select list to populate with the MajorCode or a value that looks like MajorCode - OfficialMajorName.
Could someone provide assistance for how this is done, please?
Thanks.
Add this to ODCTE_Major:
public string MajorDisplayName
{
get { return string.Format("{0} - {1}", MajorCode, OfficialMajorName); }
}
This is just a read only property used to create the display text in the format you want the menu to use.
Then in CareerMajor, add:
public IEnumerable<ODCTE_Major> Majors{ set; get; } // Thank you Shyju!
This will give you a place in your view model to pass the list of Majors you want in your menu to the view.
Then in your action method when you're creating a CareerMajor view model to send to the view, populate the new IEnumberable with the ODCTE_Major entities you'd like displayed in your menu.
On the view page:
#Html.DropDownListFor(m => m.ODCTE_MajorId, new SelectList(Model.Majors, "ODCTE_MajorId", "MajorDisplayName", Model.ODCTE_MajorId), "Select One")
This creates a SelectList to populate the drop down with. The SelectList constructor is saying use ODCTE_MajorId as the value for a SelectListItem in the menu, and to use MajorDisplayName as the text to actually display in the menu. It sets the selected value, if there is one, and adds a null item with the text "Select One" to the top of the menu. Feel free to take that final argument out if you don't want the null text.
Have your ViewModel hold a Collection property to represent all available Majors (for poulating the Dropdown)
public class CareerMajor
{
//other proiperties
public int ODCTE_MajorId { get; set; }
public IEnumerable<ODCTE_Major> Majors{ set; get; }
}
And in your GET Action, fill it and send it to your strongly typed view
pubilc ACtionResult Create()
{
var viewModel=new CareerMajor();
viewModel.Majors=db.GetllAllMajors(); // getting a list of ODCTE_Major objects
return View(viewModel);
}
and in the View, use the DropDownListFor HTML Helper method.
#model CareerMajor
#Html.BeginForm())
{
#Html.DropDownListFor(m=>m.ODCTE_MajorId,
new SelectList(Model.Majors,"ODCTE_MajorId ","MajorCode"),"select one..")
//other elements
}
In your controller action:
ViewBag.ODCTE_MajorId = new SelectList(availableMajors, "ODCTE_MajorId", "MajorCode");
*second and third parameters are the names of the value and text fields respectively
Then in your view:
#Html.DropDownList("ODCTE_MajorId", String.Empty)
where availableMajors is an IEnumerable that contains the majors you want to list.

Two render bodies in layout page?

I understand that only 1 RenderBody can exist in the MVC3 layout page however I want to attempt to create another. Maybe I'm looking at it the wrong way... Ideally I want to add a testimonial section that pulls in from the DB and display 1 testimonial at a time and a different 1 for each page refresh or new page. What is the best way to go about this?
Controller
CategoryDBContext db = new CategoryDBContext();
public ActionResult Testimonial(int id)
{
TestimonialModel model = db.Testimonials.Find(id);
return View(model);
}
Model
public class TestimonialModel
{
public int ID { get; set; }
public int CategoryID { get; set; }
public string Data { get; set; }
}
public class CategoryDBContext : DbContext
{
public DbSet<TestimonialModel> Testimonials { get; set; }
}
The View is in a folder called CategoryData.
You need to be use:
Layout:
#RenderSection("Testimonial", false) #*false means that this section is not required*#
and in you View
#section Testimonial{
}
I would use #Html.Action()
Here is a great blog post about using them: https://www.c-sharpcorner.com/article/html-action-and-html-renderaction-in-Asp-Net-mvc/
This would allow you to have a TestimonialController that can take in values, query for data and return a partial view.

Populate a DropdownList with composite key records in MVC3.net?

I don't know if I'm missing something obvious, but I really want to grab names of clients associated with a composite key.
Controller Code:
Job job = db.Jobs.Find(id);
ViewBag.jobClientsList = new SelectList(job.JobClients.ToList(), "ClientNumber", "ClientNumber");
View Code:
<%: Html.DropDownList("ClientNumber", ViewData["JobClientsList"] as SelectList)%>
Model:
namespace Sample.CustomerService.Domain {
using System.ComponentModel.DataAnnotations;
public class JobClient {
public JobClient() { }
[Key]
[Column(Order = 1)]
public virtual int JobNumber { get; set; }
[Key]
[Column(Order = 1)]
public virtual int ClientNumber { get; set; }
public virtual Client Client { get; set; }
public virtual Job Job { get; set; }
}
}
This code works, but all I get in the dropdownlist is a bunch of numbers. What I would really like is the client names associated with the numbers but I'm really not sure how to do it! I've been looking around for ages!
After re-reading your question your answer seems simpler then expected.
Check out the Select list class http://msdn.microsoft.com/en-us/library/system.web.mvc.selectlist.aspx
The constructor your using in your controller is wrong, it should be:
ViewBag.jobClientsList = new SelectList(job.JobClients.ToList(), "ClientNumber", "Client");
You were setting the text value of the selectList to be "ClientNumber" which is why you had a list of numbers and not names!
By default the select list is showing you the property that is marked [Key]
<%: Html.DropDownList("ClientNumber",
ViewData["JobClientsList"].Client as SelectList)%>
Should print the client name (assuming the primary Key on the Client object is their name, otherwise You'd need something like ViewData["JobClientsList"].Client.FullName
The best solution would be to use a ViewModel instead of using ViewBag or ViewData for this, it'll help avoid a lot of headaches both now and in the future.
What I have done in the past to get DropDownLists working is save the List to the Session Variable, and then create my SelectList in the actual DropDownList.
Controller:
Job job = db.Jobs.Find(id).ToList();
ViewBag.jobClientList = job;
View:
<%: Html.DropDownList("ClientNumber", new SelectList((If you view is strongly typed, put that here) ViewData["JobClientsList"],"ClientNumber","ClientNumber")%>
This may be poorly worded, so I think I can clarify if need be
Anyone looking for a solution, try the following:
In your controller:
1) Get the list:
var allCountries = countryRepository.GetAllCountries();
2) define a variable:
var items = new List<SelectListItem>();
3)loop each item:
foreach(var country in allCountries)
{
items.Add(new SelectListItem() {
Text = coutry.Name,
Value = Country.Id.ToString(),
// Put all sorts of business logic in here
Selected = country.Id == 13 ? true : false
});
}
model.Countries = items;
In your view:
#Html.ActionLink("StringToDisplay", "actionName", "controllerName", new SelectList(Model.Countries, "Value","Text"),"--Please Select--", new{#class="form-control"})
Not to mention Model should have a property with
public IEnumerable<Country> Countries {get; set;}

Resources