Tag helper for collection - c#

Let's say I have a view-models like this:
public class AbonentViewModel
{
public int? Id { get; set; }
public string ClientName { get; set; }
public List<AbonentCertificate> Certificates { get; set; }
}
public class AbonentCertificate
{
public string Name { get; set; }
public string FileName { get; set; }
}
I want to write a tag helper which could show list of Certificates using custom html like this:
<multi-list asp-for="Certificates">
<div class="list-item">
<input asp-for="Name" />
<input asp-for="FileName" />
</div>
</multi-list>
Html inside th multi-list element would be repeated for each certificate object with appropriate values set.
Is there any way to do this?

Related

Pass Model to bootstrap

In my project I have Class A, which has collection of class B.
Something like this:
public class A
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<B> B { get; set; }
}
public class B
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsValid { get; set; }
}
In my view I'm iterating through A elements and do a div's list.
Now, when I'm clicking some div, I want to pass B elements to modal and show some values there.
Something like:
#model IEnumerable<A>
#foreach (var a in A)
{
<div class="container" data-toggle="modal" data-target="#testModal" <!-- how to pass this model here and use it in Modal?--> >
<p>#a.Name</p>
</div>
}
Is this possible?
You can pass it as json like:
#foreach (var a in A)
{
<div class="container" data-toggle="modal" data-target="#testModal"
data-value='#JsonConvert.Serialize(a.B)'>
<p>#a.Name</p>
</div>
}
then you can just read the json like:
var model = JSON.parse($('.container').data('value'));

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>

MVC 6 Modelbinding complex dictionaries

I'm trying to post a form containing a dictionary of complex types.
The dictionary looks like this:
public Dictionary<Question, List<QuestionAlternative>> Questions { get; set; }
One question can have many alternatives.
The question itself looks like this:
public class Question
{
public Guid Id { get; set; }
public string Text { get; set; }
public Guid TestId { get; set; }
public Test Test { get; set; }
public ICollection<QuestionAlternative> QuestionAlternatives { get; set; }
public Guid? QuestionTypeId { get; set; }
public QuestionType QuestionType { get; set; }
}
And then there's the QuestionAlternative:
public class QuestionAlternative
{
public Guid Id { get; set; }
public string Alternative { get; set; }
public Guid QuestionId { get; set; }
public Question Question { get; set; }
}
My form looks like this:
<form asp-controller="Answer" asp-action="AnswerMe" method="post">
#foreach (var questionPair in Model.Questions)
{
#Html.Hidden("Questions[" + questionIndex + "].Key.Id", questionPair.Key.Id)
<br />
foreach (var alternative in questionPair.Value)
{
<label for="#alternative.Id">#questionPair.Key.Text</label>
<textarea id="#alternative.Id" name="#("Questions["+ questionIndex + "].Value["+ index +"]")"></textarea>
index++;
}
}
questionIndex++;
}
<input type="submit" class="button" value="Answer" />
</form>
The ActionResult that i'm posting to looks like this:
[AllowAnonymous]
[HttpPost("AnswerMe")]
public IActionResult AnswerMe([FromBody]AnswerViewModel model)
{
foreach(var item in model.Questions) //throws exception
....
}
and my viewmodel:
public class AnswerViewModel
{
public ODELDAL.Entities.Test Test { get; set; }
public Dictionary<Question, List<QuestionAlternative>> Questions { get; set; }
public Guid SelectedRole { get; set; }
}
When I post my form the dictionary named Questions is null.
Is it possible to achieve this with the default modelbinder or do i need to build a custom one.
If so, how would that solution look like?
Thanks in advance
Since a Question already possesses a collection of QuestionAlternative why not use a simple collect (List, array....etc) in your view model...
public class AnswerViewModel {
public ODELDAL.Entities.Test Test { get; set; }
public Question[] Questions { get; set; }
public Guid SelectedRole { get; set; }
}
...and an updated view...
<form asp-controller="Answer" asp-action="AnswerMe" method="post">
#for(int i = 0; i < Model.Questions.Length; i++) {
#Html.HiddenFor(m => m.Questions[i].Id)
<br />
for(int j = 0; j < m.Questions[i].QuestionAlternatives.Count; j++) {
#Html.LabelFor(m => m.Questions[i].QuestionAlternatives[j].Alternative,m.Questions[i].QuestionAlternatives[j].Text)
#Html.TextAreaFor(m => m.Questions[i].QuestionAlternatives[j].Alternative)
}
}
<input type="submit" class="button" value="Answer" />
</form>
The model binder will have an easier task of reconstructing your model using this approach as it will be able to use the expressions to generate the ids for the html tags.
For example, the hidden input will look something like this when generated
<input data-val="true" id="Questions_0__Id" name="Questions[0].Id" value="{Some-Guid-Value_Here}" type="hidden">

Bind generated fields to model in razor view

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; }

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.

Categories