Bind generated fields to model in razor view - c#

UPDATE: fixed this issue by adding the name attribute to the select tag that was added in order for it to be added to the formelement upon submit.
I have a partial view that get's passes a model that has a foreign key. The partial view's sole purpose is to create a new object in the database for this model. I created a drop down for one of the fields based on something outside of the model and now when I post the form, that field isn't included in the api post to create the record.
(for those familiar, yes, this is pretty much the contact example out of the box, I'm trying to extend it a bit and could use some help)
<form id="addContact" data-bind="submit: createContactFromForm">
#Html.ValidationSummary(true)
<fieldset>
<legend>Contact</legend>
#Html.EditorForModel()
<div class="editor-label"><label>Store:</label></div>
<div class="editor-field" id="storediv">
<select id="StoreId" **name="StoreId"** data-bind="options: stores, optionsText: 'Name', optionsValue: 'Id', optionsCaption: 'Choose...'"></select>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</form>
How can I get the Store field to be part of the model on form submit? I'm overriding the submit to call the createContactFromForm function in the knockoutjs viewmodel.
Updated with portion of the viewmodel that is being called:
self.createContactFromForm = function (formElement) {
// If valid, post the serialized form data to the web api
$(formElement).validate();
if ($(formElement).valid()) {
$.post("api/contacts", $(formElement).serialize(), "json")
.done(function (newContact) {
self.contacts.push(newContact);
$('#addContact')[0].reset();
});
}
}
Server side model:
public Contact()
{
this.Created = DateTime.Now;
this.Emails = new List<Emails>();
}
[ScaffoldColumn(false)]
public int Id { get; set; }
[Required, MaxLength(256)]
public string FirstName { get; set; }
[Required, MaxLength(256)]
public string LastName { get; set; }
[ScaffoldColumn(false)]
public string Name { get { return string.Concat(this.FirstName, " ", this.LastName); } set { } }
[MaxLength(256)]
public string EmailAddress {
get
{
return this.Emails.Count == 0 ? string.Empty : this.Emails[0].EmailAddress;
}
set
{
if (this.Emails.Count == 0)
{
this.Emails.Add(new Emails());
}
this.Emails[0].EmailAddress = value;
}
}
[MaxLength(50)]
public string PhoneNumber { get; set; }
[MaxLength(256)]
public string Address { get; set; }
[MaxLength(256)]
public string City { get; set; }
[MaxLength(50)]
public string State { get; set; }
[MaxLength(256)]
public string ZipCode { get; set; }
[Required]
[ScaffoldColumn(false)]
public int StoreId { get; set; }
public Store Store { get; set; }
[ScaffoldColumn(false)]
public DateTime Created { get; set; }
public virtual IList<Emails> Emails { get; protected set; }

Related

C# receiving data from dynamically created HTML form

I am creating an ASP.Net application that displays records from a SQLite database and incorporating filter options that are built from the records that are coming in since I do not know what kind of data will be in the columns. I have the filter in place and will create the HTML form that will display the field value and how many records with that value there are. However I am not sure how to grab that data since as far as I am aware, the receiving method in the controller will expect a matching parameter for each variable (HTML form: value="bob", the receiving method in the controller takes a parameter such as string bob).
My code for generating the HTML form is:
<div>
<text>Employment:</text> <br />
#foreach (var employment in Model.Employment)
{
<input type="checkbox" value="{#employment.Key}"/>#employment.Key <text>(#employment.Value)</text> <br />
}
<hr />
</div>
Since there could be, for instance, 15 different selection chosen, how would I grab all of the values that are generated? Additionally, there are about 5 more sections like this for filter options. Is it possible to transmit all selections as a dictionary like
<key,<key,value>>
and then parse through the nested dictionaries? The dictionaries would then hold the main category of filters(main key) and then each accepted filter option(parent's value/key) within that category with the a ture(for the parent's value's value).
Edit: Adding some addition code as requested. This is the class that represents an employee for a company:
public class MemberModel
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string EmailAddress { get; set; }
public string PhoneNumber { get; set; }
public string Position { get; set; }
public string Department { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public string EmploymentStatus { get; set; }
public string Shift { get; set; }
public string Manager { get; set; }
public string Photo { get; set; }
public string FavoriteColor { get; set; }
}
This might not be necessary for the implementation but made sense to me for building this app. This is a class that contains a list of all employees and dictionaries that I use for building the filter options:
public class TeamMembersModel
{
public Dictionary<string, int> Employment { get; set; }
public Dictionary<string, int> Position { get; set; }
public Dictionary<string, int> Shift { get; set; }
public Dictionary<string, int> Department { get; set; }
public Dictionary<string, int> Manager { get; set; }
public List<MemberModel> Employees { get; set; }
}
This code is a condensed version of how I build the form for filtering:
<form asp-action="" asp-controller="TeamMembers" method="get">
<!-- Department -->
<div>
<text>Department:</text> <br />
#foreach (var departments in Model.Department)
{
<input type="checkbox" value="#departments.Key" />#departments.Key <text>(#departments.Value)</text> <br />
}
<hr />
</div>
<!-- This is repeated for each dictionary in the TeamMembersModel class -->
<button type="submit" value="Filter">Filter</button>
</form>

Select Tag Helper ASP .NET CORE 2.0 is not setting selected value

I am trying to use select tag helper in ASP .NET Core 2.0 MVC application according to this thread Select Tag Helper in ASP.NET Core MVC .
Here is my view model :
public class SensorEditViewModel
{
public int SensorID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Uid { get; set; }
public string AE_SN { get; set; }
public DateTime SubscriptionEndDate { get; set; }
public string Type { get; set; }
public bool sensorAccessApproved { get; set; }
public string UserId { get; set; }
public SelectList UserEmailList { get; set; }
}
Here is part of GET where model is filled with propper SelectList and UserId and pushed to the view:
var users = _context.Users.OrderBy(u => u.UserName).Select(x => new { Text = x.Email, Value = x.Id });
model.UserEmailList = new SelectList(users, "Value", "Text");
model.Id = ownerId;
return View(model);
and finally in the Edit view I am using Select TagHelper like this :
<div class="form-group">
<label class="control-label">User Email</label>
<select asp-for="Id" asp-items="#Model.UserEmailList" class="form-control" ></select>
</div>
But my problem is that Select is not preset with value selected in controller (model.Id = ownerId;). Do you have any clue what might be wrong? Thanks.
You need to pass the selected value into the SelectList constructor:
model.UserEmailList = new SelectList(users, "Value", "Text", ownerId)
More info in the MS docs

Complex ViewModel - View cannot Automap values from model Advice Needed..

I have a complex View. It has data from 4 Models. The models are all static and work as expected. I have created a ViewModel to attempt to show just the data needed for this view. It is made up of Competitors and some complex Classes and Events they participate in.
I have made a complex ViewModel. When I walk through the Controller, I can see all three parts being constructed from the ViewModel. Its all there including data. When I try to map the values using Intellesense in the View, it has no way of knowing this data, or has no mapping from the complex ViewModel. Am I doing this right? I have tried several ways to map these values to the View. I think I need to initialize or map the values to the Models derived from, I just cannot figure out how.
Please advise on how to map these values, data elements to the view.
ViewModel:
Compeditor is an from an actual model direct to the DB
The rest of the data is gathered from multiple tables and passed to view from controller
namespace eManager.Web2.Models
{
public class CompDetailPlus
{
public CompDetailPlus()
{
this.Compeditor = new Compeditor();
}
public virtual Compeditor Compeditor { get; set; }
public virtual IEnumerable<InEventClass> InEventClass { get; set; }
public virtual IEnumerable<AllEventClasses> AllEventClasses { get; set; }
}
public class Compeditor
{
[Key]
public virtual int CompeditorId { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string MiddleInt { get; set; }
public virtual string StreetAddress { get; set; }
public virtual string City { get; set; }
public virtual string State { get; set; }
public virtual string PostalCode { get; set; }
public virtual string EmailAddress { get; set; }
public virtual string HomePhone { get; set; }
public virtual string CellPhone { get; set; }
public virtual double Height { get; set; }
public virtual double Weight { get; set; }
public virtual int Age { get; set; }
public virtual int Event_CompId { get; set; }
}
public class InEventClass
{
public virtual int EventClassID { get; set; }
public virtual string ClassName { get; set; }
public virtual bool IsSelected { get; set; }
}
//duplicate to simplify how the second list is pulled and then combined with first list
public class AllEventClasses
{
public virtual int EventClassID { get; set; }
public virtual string ClassName { get; set; }
public virtual bool IsSelected { get; set; }
}
}
Controller:
public ActionResult CompeditorDetail(int CompeditorId)
{
//Pull the Competitor detail for the ID passed in
var comp = _db.Compeditors.Single(c => c.CompeditorId == CompeditorId);
//Pull a list of Event-Classes the competitor is already signed up for on current event
var nlist = (from o in _db.Compeditors
join o2 in _db.Event_Class_Compeditors_s on o.CompeditorId equals CompeditorId
where o.CompeditorId.Equals(CompeditorId)
join o3 in _db.Event_Classes on o2.EventClassID equals o3.EventClassID
where o2.EventClassID.Equals(o3.EventClassID)
join o4 in _db.Class_Definitions on o3.ClassID equals o4.Class_Definition_ID
where o3.ClassID.Equals(o4.Class_Definition_ID)
select new InEventClass()
{
ClassName = o4.Class_Name,
EventClassID = o2.EventClassID,
IsSelected = true
}).ToList();
//pull a complete list of Event Classes that are avaiaible
var totallist = (from o in _db.Event_Classes
join o2 in _db.Event_Classes on o.ClassID equals o2.ClassID
where o.ClassID.Equals(o2.ClassID)
join o3 in _db.Class_Definitions on o2.ClassID equals o3.Class_Definition_ID
where o2.ClassID.Equals(o3.Class_Definition_ID)
join o4 in _db.Events on o.EventID equals o4.EventID
where o.EventID.Equals(o4.EventID)
where o4.CurrentEvent.Equals(true)
select new AllEventClasses()
{
ClassName = o3.Class_Name,
EventClassID = o2.EventClassID,
IsSelected = false
}).ToList();
var whatsleft = totallist.Where(eachtotalclass => !(nlist.Any(eachClassIHave => eachClassIHave.EventClassID == eachtotalclass.EventClassID))).ToList();
var model = new CompDetailPlus { AllEventClasses = whatsleft, Compeditor = comp, InEventClass = nlist };
return View(model);
}
View:
(Has to show the Competitor detail and a compound list of Event_Classes they are in)
In the view, I cannot see the values for any data.. all error on run and no good for display.
#model IEnumerable<eManager.Web2.Models.CompDetailPlus>
#{
ViewBag.Title = "Competitor's Detail";
}
<h2>#ViewBag.Title</h2>
<fieldset>
<legend>Compeditor</legend>
<table border="1" >
<tr>
<td>
<div class="display-field">
#Html.HiddenFor(model => model.Compeditor.CompeditorId)
</div>
<b>First Name</b>
<div class="display-field">
#Html.DisplayFor(model => model.Compeditor.FirstName)
</div>
</td>
<td>
<b>Last Name</b>
<div class="display-field">
#Html.DisplayFor(model => model.Compeditor.LastName)
</div>
</td>
#using (Html.BeginForm("CompeditorDetail", "Compeditor", FormMethod.Post))
{
foreach (var item in Model)
{
<input type="checkbox" name="MyID" value="#item.AllEventClasses.IsSelected"/> #item.InEventClass.ClassName <br />
<input type="hidden" name="CompeditorID" value="#item.InEventClass.CompeditorId" />
}
}
</td>
Your View accepts a model of IEnumerable eManager.Web2.Models.CompDetailPlus which would be fine, but your controller is sending a single eManager.Web2.Models.CompDetailPlus object.
Try changing this in your View
#model IEnumerable<eManager.Web2.Models.CompDetailPlus>
to this:
#model eManager.Web2.Models.CompDetailPlus
And change the bottom part of your view so that it's iterating through Enumerable compaosite items inside your model.

ValidationMessage does not render in my view (asp.mvc3)

This problem is very strange, maybe I have missed some small detail, since I'm new to mvc 3...
In a partial view, I have a different model than in the main view (I don't think that it matters in this case). I have added a couple of Validation-helper calls in the view. No matter what I do, they dont show up on the page.
I have enabled framework source debugging, and I can see that the HTML is generated, and are written to "output". Still, they dont appear in the final rendered page. I cannot understand why.
In my partial view:
#model ModelsDTO.Domain.GridRowDTO
#Html.ValidationSummary()
#Html.TextBox("Kalla")
#Html.ValidationMessage("Kalla")
I have the textbox there just to see if it renders. It does.
My controller code (hard coded message, just to try to make it work):
[HttpPost]
public ActionResult SaveGridRow(GridRowDTO rad)
{
List<string> valideringsFel = _dagboksanteckning.SaveDagbokObjekt(rad);
ModelState.AddModelError("Kalla", "Källan felaktig");
return PartialView("_DagbokGrid", rad);
}
The model:
public class GridRowDTO
{
public string Kronika { get; set; }
public string Ok { get; set; }
public string Datum { get; set; }
public string Tid { get; set; }
public string Kalla { get; set; }
public string Handelse { get; set; }
public string Bedomning { get; set; }
public string Till { get; set; }
public string Rubrik { get; set; }
public string Verksamhetsslag { get; set; }
public string OperationPadrag { get; set; }
public string Verksamhetskod { get; set; }
public string LatitudTecken { get; set; }
public string Latitud { get; set; }
public string LongitudTecken { get; set; }
public string Longitud { get; set; }
public string Media { get; set; }
public string AnnatDokument { get; set; }
public string Region { get; set; }
public string id { get; set; }
}
Edit, very interesting finding!
When tracing the call with IE9 F12-mode, the response text acutally contains the expected HTML! Why does'nt it render!
<div class="validation-summary-errors"><ul><li>Källan felaktig</li>
</ul></div>
<input class="input-validation-error" id="Kalla" name="Kalla" type="text" value="1" />
<span class="field-validation-error">Källan felaktig</span>
I would be really thankfull if I could get some assistance to understand this problem.
If you are calling this controller action using AJAX you should make sure that you are substituting the contents of the partial with the new value. For example assuming your partial is wrapped inside a div:
<div id="container">
#Html.Patrial(....)
</div>
Now inside the success callback make sure you have refreshed the contents of the div:
$.ajax({
url: '#Url.Action("SaveGridRow")',
type: 'POST',
data: ...,
success: function(result) {
// Here you must refresh the div or whatever part of the DOM
// you need to update
$('#container').html(result);
}
});
or if you are using Ajax.* helpers to call the action make sure you have specified UpdateTargetId in the AjaxOptions and that this value corresponds to the id of some DOM element you want to refresh.

ASP.Net MVC returning value of a DropDown

I am learning, and managed to make a nice info display page, displaying lists of transactions. However, I have no added DropDown box, which has a list of Bank Accounts. It's defaulted to All.
When the user selects an account, and presses the submit button, the page should then reloca with only transactions for that account.
I have created the drop down, and the form for it, like this:
<form id="form1" runat="server">
<h2>
Transactions:</h2>
<p>
<%
using (Html.BeginForm())
{
%>
Bank Account:
<% =Html.DropDownList("ddAccounts", Model.BankAccountItems)%> <input id="Submit1" type="submit" value="Select" />
<%
}
%>
</p>
</form>
My model contains this:
public class AccountTransactionDisplay
{
public AccountTransactionDisplay()
{
DisplayLines = new List<AccountTransactionDisplayLine>();
}
public SelectList BankAccountItems { get; set; }
public List<AccountTransactionDisplayLine> DisplayLines {get; set; }
public string ClosingBalance { get; set; }
}
public class BankAccountDropdownItem
{
public string Text {get; set;}
public string Value {get; set;}
}
public class AccountTransactionDisplayLine
{
public string RowColouring { get; set; }
public string TransactionDate { get; set;}
public string PayeeName { get; set; }
public string Amount { get; set; }
public bool AmountIsDebit { get; set; }
public string CategoryName { get; set; }
public string CostCenterName { get; set; }
public string BudgetName { get; set; }
public string RunningTotal { get; set; }
public bool RunningTotalIsDebit { get; set; }
public bool AlternateRowColour { get; set; }
public bool HasSplitItems { get; set; }
}
So, AccountTransactionDisplay is the model I pass to the view. In that model, I have this:
public SelectList BankAccountItems { get; set; }
That holds a list of items that are displayed in my Drop Down. That is being displayed correctly.
However, when the user clicks the submit button, I am unsure how to get the selected value back.
I thought that I would have a method in my controller that accepts the POST... So, I have added this:
[HttpPost]
public ActionResult Transactions(AccountTransactionDisplay model)
{
AccountTransactionDisplay trans = GetTransactions();
return View(trans);
}
And if I set a breakpoint, it is hitting this, but it seems model is empty. I need to add the id of the selected account ot the GetTransactions method, to do the filtering.
When your page renders, view the source. Whatever the name attribute of the select element is, that is the name of a property you will need to add to your model, then the model binder will bind that value to your model. When a form is submitted, only name/value pair of the form fields are submitted (for the most part), so the select element's name will be in the form data as well as its selected value, all of the options are not posted back, so MVC has no way of rebinding your SelectList property.
HTH

Categories