I want to create list using dropdown.
I have model class with following properties.
public class EditPaymentMethod
{
public List<string> BPay { get; set; }
public List<BillerCode> BillerCodes { get; set; }
}
public class BillerCode
{
public List<string> CodeList { get; set; }
}
In my mock class, I'm creating mock data as follows:
public static EditPaymentMethod GetPaymentMethodDetails(int tenantID)
{
for (int i = 0; i < obj.MyProperty.BPay.Count; i++)
{
obj.BillerCodes.Add(new BillerCode { CodeList = new List<string> { "AAA" + i, "BBB" + i } });
}
return obj;
}
In View:
#using (Html.BeginForm("EditPaymentMethod","PaymentMethod",FormMethod.Post))
{
#for (int i = 0; i < Model.MyProperty.BPay.Count; i++)
{
<div class="list_scbill">
#Html.Label("Biller Codes")
</div>
<div style="display: block; margin-left: 87px;">
#Html.DropDownListFor(model => model.BillerCodes[i].CodeList, new SelectList(Model.BillerCodes[i].CodeList))
</div>
}
<div id="BtnsDiv">
<button id="btn_SaveChanges" type="submit">
Save
</button>
<button id="btn_Cancel" type="button">
Cancel
</button>
</div>
}
In Controller:
public ActionResult EditPaymentMethod(EditPaymentMethod model)
{
if (ModelState.IsValid)
{
//CODE TO SAVE DATA THROUGH THE SERVICE
}
return View(model);
}
When I try to submit the form, EditPaymentMethod gets the model with BillerCodes as null.
Any idea where I'm going wrong?
Thanks in advance.
Couple things right off the bat, number one you are not actually passing the model to your controller in the route values dictionary.
#using (Html.BeginForm("EditPaymentMethod","PaymentMethod",new {model = Model}, FormMethod.Post))
will add your model as a parameter to your post. Also your controller is currently a get request you will need to flag it as a post or the controller will by default try to get the serialized string from the url rather than the request body.
[HttpPost]
public ActionResult EditPaymentMethod(EditPaymentMethod model)
Use ListBoxFor for a multi-select, instead of DropDownListFor, which just produces a single-select whose posted value will not be correct for the modelbinder to bind to a list.
For the same you have to create List Variable in Model
and on view page you have to
#Html.ListBoxFor(model => model.SelectedList, new SelectList(Model.SelectList, "Id", "Name"), new { #class = "js-example-basic-multiple form-control", #multiple = "multiple", #id = "SelectListId" })
var ListModel = {
"Id": 0,
"SelectedList": $("#SelectedListId").val(),
};
$.ajax({
url: '/Test/Test/',
type: "Post",
async: false,
dataType: "html",
data: JSON.stringify(ListModel),
contentType: "application/json;charset=utf-8",
success: function (result) {
}
});
Model Should be :
public class EditPaymentMethod
{
public List<string> BPay { get; set; }
public List<BillerCode> BillerCodes { get; set; }
public int[] SelectedList{ get; set; }
}
Related
Im Trying to create a tree view menu, but it isnt working properly. There are 3 different stored procedures, 1st for families (parent), 2nd for categories(child), and 3rd for reports(grandchild). Families SP takes user id as paramters and seems to be working fine. Category SP takes userID and familyID and 3rd takes userID, FamilyID and CategoryID. When runnning the code it does display the families, and displays the 1 report name underneath. If I remove line of code that calls the stored procedure out of the foreach loop, it does return categories for 1 family, although it displays on all the families.
If I add a breakpoint on on the controller it will go through the loops and return the correct data, so I assume the issue is in the way it is being displayed .[Displayed data] On this screenshot is possible to see how the data is being displayed, being EPOS and RES being retuned from family SP and WebBooking which is a category
FAMILIES
¦
¦--CATEGORIES
¦
¦
¦---REPORT_NAME
Thank you In advance!
On the controller I'm calling each of the stored procedures, and if tested with a breakpoint all the data that should be returned is being returned properly. Perhaps a solution for my problem would be populate the view with the returned data from the controller, however I don't know how to do it?
Controller
foreach (var cat in model.familiesReport = context.P_Mob_Get_ReportFamilies(user).ToList())
{
Console.WriteLine(cat.FamilyName);
foreach (var name in model.CategoriesReport = context.P_Mob_Get_ReportCategories(user, cat.FamilyID).ToList())
{
Console.WriteLine(name.Category);
foreach (var test in model.namesReport = context.P_Mob_Get_ReportNames(user, cat.FamilyID, name.CategoryID).ToList())
{
Console.WriteLine(test.ReportName);
}
}
I have got a View Model that has the 3 SP_Results (Complex types in EF). On the view I am going through every single Complex type and return the name for each one, (Family, Category, Name)
View
<ul>
#foreach (var family in Model.familiesReport)
{
#family.FamilyName
<ul class="">
#foreach (var cat in Model.CategoriesReport)
{
<li href="#" class=""><a class="menu_cat"> #cat.Category</a></li>
<ul class="">
#foreach (var name in Model.namesReport)
{
<li href="#" class=""><a class="menu_name"> #name.ReportName</a></li>
}
</ul>
}
</ul>
}
</ul>
I have finally found the solution for this. Ive created a new model and instead of saving the results of the stored procedure in the complex types generated by EF saved them in this model. Each class in the model has a list where the data will be saved. as displayed bellow.
Model:
public class FamilyResultResponse
{
public List<Family> Families { get; set; }
public List<Sites> SitesGet { get; set; }
}
public class Family
{
public Nullable<int> FamilyID { get; set; }
public string FamilyName { get; set; }
public List<FamilyResultCat> FamilyCat { get; set; }
}
public class FamilyResultCat
{
public Nullable<int> familyid { get; set; }
public Nullable<int> CategoryID { get; set; }
public string Category { get; set; }
public int Allowed { get; set; }
public List<FamilyResulReportByCategory> FamilCatRep { get; set; }
}
public class FamilyResulReportByCategory
{
public Nullable<int> ReportID { get; set; }
public Nullable<int> categoryid { get; set; }
public string ReportName { get; set; }
}
Controller:
Iterate through the lists
public ActionResult Index(Guid? userID\)
{
var model = new FamilyResultResponse();
model.Families=new List<Family>();
SPMenuModel modelSPMEnu = new SPMenuModel();
foreach (var f in context.P_Mob_Get_ReportFamilies(userID).ToList())
{
var fam = new Family();
fam.FamilyID = f.FamilyID;
fam.FamilyName= f.FamilyName;
fam.FamilyCat = new List<FamilyResultCat>();
Console.WriteLine(f.FamilyName);
foreach (var c in context.P_Mob_Get_ReportCategories(userID, f.FamilyID).ToList())
{
var famcat = new FamilyResultCat();
famcat.CategoryID = c.CategoryID;
famcat.Category = c.Category;
famcat.Allowed = c.Allowed;
famcat.FamilCatRep= new List<FamilyResulReportByCategory>();
Console.WriteLine(c.Category);
foreach (var n in context.P_Mob_Get_ReportNames(userID, f.FamilyID, c.CategoryID).ToList())
{
var famcatrep = new FamilyResulReportByCategory();
famcatrep.ReportID = n.ReportID;
famcatrep.ReportName = n.ReportName;
famcatrep.categoryid = n.categoryid;
Console.WriteLine(n.ReportName);
famcat.FamilCatRep.Add(famcatrep);
}
fam.FamilyCat.Add(famcat);
}
model.Families.Add(fam);
}
modelSPMEnu.familyResult = model;
return View(model);
View
#foreach (var fam in Model.Families)
{
#fam.FamilyName
<ul class="">
#foreach (var cat in fam.FamilyCat)
{
<li href="#" class=""><a class="menu_cat"> #cat.Category </a></li>
foreach (var name in cat.FamilCatRep)
{
<ul class="">
<li class=""><a>#name.ReportName</a></li>
</ul>
}
}
</ul>
}
I'm need to pass dynamically created data from a partial view to the controller on submit from the main form.
Here's the Action that returns the partial view:
[HttpGet]
public virtual PartialViewResult AddItem()
{
var item = new QuotedItem();
ViewBag.StockID = new SelectList(db.StockItems.OrderBy(s => s.Name), "StockID", "Name");
return PartialView("EditorTemplates/QuotedItem", item);
}
Here's the EditorTemplate for QuotedItem:
#model StockSystem.Models.QuotedItem
<div id="itemRow">
<span>
#Html.DropDownListFor(model => model.StockID, null)
#Html.ValidationMessageFor(model => model.StockID, "", new { #class = "text-danger" })
</span>
<span>
#Html.EditorFor(model => model.Price)
#Html.ValidationMessageFor(model => model.Price, "", new { #class = "text-danger" })
</span>
<span>
#Html.EditorFor(model => model.Quantity)
#Html.ValidationMessageFor(model => model.Quantity, "", new { #class = "text-danger" })
</span>
</div>
Here's the View:
#model StockSystem.Models.Quote
#{
ViewBag.Title = "Create";
}
<h2>New Quote for #ViewBag.Customer</h2>
<hr />
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.Hidden("CustomerID", (object)ViewBag.CustomerID)
<div class="addItem">
#Ajax.ActionLink(" ", "AddItem",
new AjaxOptions
{
UpdateTargetId = "editorRows",
InsertionMode = InsertionMode.InsertAfter,
HttpMethod = "GET"
})
</div>
<div id="editorRows">
#Html.EditorFor(q => q.QuotedItems)
</div>
<p></p>
<div>
<input class="add" type="submit" value="" />
<a class="back" href="#Url.Action("Index", "Quotes", new { id = ViewBag.CustomerID })"></a>
</div>
}
Here's the Create Action:
public ActionResult Create(int id)
{
var customer = db.Customers.Find(id);
ViewBag.CustomerID = id;
ViewBag.Customer = customer.CustomerName;
var quote = new Quote() { QuotedItems = new List<QuotedItem>() };
return View(quote);
}
Here's the EF model for QuotedItem:
public partial class QuotedItem
{
public int QuotedItemID { get; set; }
public int QuoteID { get; set; }
public int StockID { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public virtual Quote Quote { get; set; }
public virtual StockItem StockItem { get; set; }
}
And Quote:
public partial class Quote
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Quote()
{
this.QuotedItems = new HashSet<QuotedItem>();
}
public int QuoteID { get; set; }
public int CustomerID { get; set; }
public int UserID { get; set; }
public System.DateTime QuoteDate { get; set; }
public string QuoteRef { get; set; }
public virtual Customer Customer { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<QuotedItem> QuotedItems { get; set; }
public virtual User User { get; set; }
}
I can add items to the page but they are not added to the quote on submit.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote) //, List<QuotedItem> items
{
if (ModelState.IsValid)
{
//quote.QuotedItems is empty, how do I bind this data and save to database?
db.Quotes.Add(quote);
db.SaveChanges();
return RedirectToAction("Index", new { id = quote.CustomerID });
}
return View(quote);
}
The collection is not being sent to the controller. How is this done?
Thanks
Edit: I was thinking about trying this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote, List<QuotedItem> items)
{
if (ModelState.IsValid)
{
quote.QuotedItems = items;
db.Quotes.Add(quote);
db.SaveChanges();
return RedirectToAction("Index", new { id = quote.CustomerID });
}
return View(quote);
}
But I thought there must be a better way. If I were try this approach I'm still not entirely sure how to send this to the controller, I assume as a parameter in Html.BeginForm()? I'm fairly new to MVC and still getting to grips with the conventions.
By using the Bind attribute in your method signature, you are preventing the QuotedItems property from being posted to the controller action.
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef")] Quote quote)
Adding the QuotedItems property name to the include list should solve this:
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote)
EDIT
Without seeing your QuotedItem editor template, it's hard to say for sure, but it sounds like your issue might be that each item added to your list doesn't have a unique id set on the elements that make up that item. Without this, the model binder will struggle to work out which element belongs to which object in the collection.
Take a look at these two articles and see if they help:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
https://www.mattlunn.me.uk/blog/2014/08/how-to-dynamically-via-ajax-add-new-items-to-a-bound-list-model-in-asp-mvc-net/
Edit 2
Each element in your template should be given a unique ID, an index is a good way to do this, so are item GUIDs (if you have them); but as long as each element ID is unique to that item it should work.
#model StockSystem.Models.QuotedItem
<div id="itemRow">
<span>
#Html.DropDownListFor(model => model.StockID, null)
#Html.ValidationMessageFor(model => model.StockID, "", new { #class = "text-danger" })
</span>
<span>
#Html.EditorFor(model => model.Price, new { htmlAttributes = new { id = $"[{YOURINDEX}].Price" } })
#Html.ValidationMessageFor(model => model.Price, "", new { #class = "text-danger" })
</span>
<span>
#Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { id = $"[{YOURINDEX}].Quantity" } })
#Html.ValidationMessageFor(model => model.Quantity, "", new { #class = "text-danger" })
</span>
In the code above the [YOURINDEX] value would need to be incremented for each new item added to the collection.
How you implement and increment that index is up to you, but I would suggest reading the two articles I linked to previously to get an understanding of why this is necessary.
Image for what i need
i need when edit employee data show to me courses that submit before
this is my secnario
in create view
courses drowpdown user select three courses
Delphi
Flash
c++
then when click submit button for employee.it will have 3 courses submitted
I need to retrieve courses that submitted before for employee martin
from database
in edit view(get)
I need to show :
course name course id
Delphi 1
Flash 2
c++ 3
and CourseId will be hidden
what i write in edit view to show selected course
my code as below for view and controller
Edit.cs.html view
#model WebCourse.Models.Customemployee2
<body>
<div>
#using (Html.BeginForm())
{
<div>
Name:#Html.TextBoxFor(a => a.Name)
<br />
Courses:#Html.DropDownList("CourseId")
<table id="tb2"></table>
<br />
<input type="submit" />
</div>
}
</div>
</body>
in empcourse controller
namespace WebCourse.Controllers
{
public class empcourseController : Controller
{
mycourseEntities db = new mycourseEntities();
// GET: empcourse
public ActionResult Edit(int id)
{
Employee old = db.Employees.Find(id);
if (old != null)
{
var vm = new Customemployee2();
vm.Name = old.Name;
ViewBag.CourseId = new SelectList(db.Courses.ToList(), "Id", "CourseName");
return View(vm);
}
}
}
}
model view Customemployee2
namespace WebCourse.Models
{
public class Customemployee2
{
public string Name { get; set; }
public int CourseId { get; set; }
public List<EmployeeCourse> Courses { get; set; }
}
}
I suggest you update your edit view model to have a collection of CourseVm
public class EditEmployeeVm
{
public int Id { set; get; }
public string Name { get; set; }
public List<SelectListItem> Courses { get; set; }
public int[] CourseIds { set; get; }
public List<CourseVm> ExistingCourses { set; get; }
}
public class CourseVm
{
public int Id { set; get; }
public string Name { set; get; }
}
Now in your Edit GET action, populate the ExistingCourse collection.
public ActionResult Edit(int id)
{
var vm = new EditEmployeeVm { Id=id };
var emp = db.Employees.FirstOrDefault(f => f.Id == id);
vm.Name = emp.Name;
vm.ExistingCourses = db.EmployeeCourses
.Where(g=>g.EmployeeId==id)
.Select(f => new CourseVm { Id = f.CourseId,
Name = f.Course.Name}).ToList();
vm.CourseIds = vm.ExistingCourses.Select(g => g.Id).ToArray();
vm.Courses = db.Courses.Select(f => new SelectListItem {Value = f.Id.ToString(),
Text = f.Name}).ToList();
return View(vm);
}
Now in your Edit view, just loop through the ExistingCourses collection and display it.
#model EditEmployeeVm
#using (Html.BeginForm())
{
#Html.HiddenFor(g=>g.Id)
#Html.LabelFor(f=>f.Name)
#Html.DropDownList("AvailableCourses" ,Model.Courses,"Select")
<h4>Existing courses</h4>
<div id="items"></div>
foreach (var c in Model.ExistingCourses)
{
<div class="course-item">
#c.Name Remove
<input type="text" name="CourseIds" value="#c.Id" />
</div>
}
<input type="submit"/>
}
You should have the below javascript code also in the view to handle the remove and add of a course.
#section scripts
{
<script>
$(function() {
$(document).on("click",".remove",function(e) {
e.preventDefault();
$(this).closest(".course-item").remove();
});
$('#AvailableCourses').change(function() {
var val = $(this).val();
var text =$("#AvailableCourses option:selected").text();
var existingCourses = $("input[name='CourseIds']")
.map(function() { return this.value; }).get();
if (existingCourses.indexOf(val) === -1) {
// Not exist. Add new
var newItem = $("<div/>").addClass("course-item")
.append(text+' Remove ');
newItem.append('<input type="text" name="CourseIds"
value="' + val + '" />');
$("#items").append(newItem);
}
});
})
</script>
}
So when you submit the form, The CourseIds property will have the course ids (as an array).
[HttpPost]
public ActionResult Edit(EditEmployeeVm model)
{
// to do : check model.ExistingCourses and save the data now
}
BTW, The same can be used for your create form.
I am trying to create a viewmodel and add a SelectListItem to allow me to bind a dropdown list.
I have a very basic viewmodel that looks like this
public class CreatePurchaseViewModel
{
public Product Product { get; set; }
public IEnumerable<SelectListItem> Products { get; set; }
public int SelectedProductId { get; set; }
public DateTime OrderDate { get; set; }
public bool OrderSent { get; set; }
}
My controller looks like this
[HttpGet]
public ActionResult Create()
{
var model = new CreatePurchaseViewModel
{
Products = context.Products.Select(x =>
new SelectListItem()
{
Text = x.ProductName,
Value = x.ProductID
})
};
return View(model);
}
However it complains that Value = x.Product cant convert type int to string. So if I add a .ToString it compiles ok but when I try load the view I get an error
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.
My View
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>CreatePurchaseViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.SelectedProductId)
</div>
<div class="editor-field">
#Html.DropDownListFor(x => x.SelectedProductId,Model.Products)
#Html.ValidationMessageFor(model => model.SelectedProductId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OrderDate)
</div>
<div class="editor-field">
#Html.TextBoxFor(model=>model.OrderDate)
#Html.ValidationMessageFor(model => model.OrderDate)
</div>
<div>
Sent
#Html.RadioButtonFor(model => model.OrderSent, "Sent", new { #checked = true })
Not Sent
#Html.RadioButtonFor(model=>model.OrderSent,"Not Sent")
Im pretty new to both entity framework and mvc so any help would be great.
Thank you
You haven't specified how does your Product model look like but we can assume that the ProductID property is integer so you might need to convert it to a string:
[HttpGet]
public ActionResult Create()
{
var model = new CreatePurchaseViewModel
{
Products = context.Products.Select(x =>
new SelectListItem
{
Text = x.ProductName,
Value = x.ProductID.ToString()
}
)
};
return View(model);
}
It seems like it's not possible to edit custom object anymore after I upgraded to asp.net mvc 2 rc 2? I use this approach http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html with a custom object like this:
My model has just one property but inherits from an abstract base class
public class Page : ContentItem {
[DataType(DataType.MultilineText)]
public virtual string MainIntro { get;set; } // This property render correct
[DisplayFormat(NullDisplayText="(null value)")]
public virtual DetailCollection Tags { get; set; }
}
My controller looks like this
public ActionResult Edit(string pagePath) {
var page = _repository.GetByUrlSegment(pagePath);
return View(page.EditViewName, new DashboardModel(page, RootPages));
}
And my view looks like this
<% using (Html.BeginForm("update","Dashboard", FormMethod.Post, new { name = "editForm" } )) %>
<% { %>
<div>
<%=Html.EditorFor(model => model.CurrentItem) %>
<div class="editor-button">
<input type="submit" value="Save" />
</div>
</div>
<% } %>
Perhaps it would be better to expose this to the view as a space-separated string and exclude the collection from being displayed in the view. Alternatively, you might be able to define a specific template for how you want to display a collection. It's not clear to me how MVC would be able to determine what to display otherwise.
Try something like:
[ShowForDisplay(false)]
[ShowForEdit(false)]
public virtual DetailCollection Tags { get; set; }
public virtual string TagList
{
get
{
if (tags == null) return "(null value)";
// assumes DetailCollection implements IEnumerable<string>
return string.Join( " ", tags.Select( t => t).ToArray() );
}
set
{
tags = new DetailCollection( value.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries )
.Select( s => s.Trim() ) );
}
}