ASP.NET MVC : bind form with List<Model> in view model - asp.net-mvc

I have a view model with the following properties:
// I set the values from the database
public List<Document> AvailableDocuments { get; set; }
// I need to set the values from a front end <form>
public List<RequiredDocument> RequiredDocuments { get; set; }
The RequiredDocument model contains the following properties:
// This should be an Id, maybe a hidden input
public Document Document { get; set; }
// This should be a number input
public int RequiredCopies { get; set; }
// This should be a checkbox
public bool IsRequired { get; set; }
In my view I'm looping through AvailableDocuments and every iteration should bind to a RequiredDocument model (where the user may set the values for the RequiredCopies number).
The form is submitted via Ajax. How can I bind the form to RequiredDocuments?
#foreach (Document doc in Model.AvailableDocuments)
{
<div class="reqdoc">
<!-- RequiredDocument.Document -->
<input type="hidden" name="Document" value="#doc.Id" />
<div class="form-check">
<!-- RequiredDocument.IsRequired -->
<input class="form-check-input" type="checkbox" value="" />
<label class="form-check-label">
#doc.Name
</label>
</div>
<!-- RequiredDocument.RequiredCopies -->
<input class="form-control" type="number" />
</div>
}

You can use this kind of for loop I am doing similar in my projects & it works
<table>
#for (int i = 0; i < (int)ViewBag.Count; i++)
{
#Html.HiddenFor(model => model.AvailableDocuments.ToList()[i].ID)
<tr>
<td>
#Html.CheckBoxFor(model => model.RequiredDocuments.ToList()[i].IsRequired, new { id = "chk_" + i, #class = "custom-checkbox" })
</td>
<td>
#Html.DisplayFor(model => model.AvailableDocuments.ToList()[i].Name)
</td>
<td>
#Html.TextBoxFor(model => model.RequiredDocument.ToList()[i].RequiredCopies, new { id = "RequiredCopies" + i, #class = "form-control" })
</td>
</tr>
}
</table>
Just pass a ViewBag.Count from Your get method.

Work with index and modify the name attribute as:
#{
int i = 0;
foreach (Document doc in Model.AvailableDocuments)
{
<div class="reqdoc">
<!-- RequiredDocument.Document -->
<input type="hidden" name="RequiredDocuments[#i].Document.Id" value="#doc.Id" />
<div class="form-check">
<!-- RequiredDocument.IsRequired -->
<input class="form-check-input" type="checkbox" value="" name="RequiredDocuments[#i].IsRequired" />
<label class="form-check-label">
#doc.Name
</label>
</div>
<!-- RequiredDocument.RequiredCopies -->
<input class="form-control" type="number" name="RequiredDocuments[#i].RequiredCopies" />
</div>
i++;
}
}

Related

ASP .NET MVC: Get the url and view the image as it changes

I have a function that allows me to edit an image but I want as soon as I click the Edit button I will get the URL of the current image
image:
Do not see "no file chosen"
I want the URL of the image to appear on the right
Step Two Once I swap a picture I also want the picture to change to the picture I swap
My Service:
public class FileService : IFileService
{
private readonly IWebHostEnvironment _environment;
public FileService(IWebHostEnvironment environment)
{
_environment = environment;
}
public async Task<string> File([FromForm] CreateAnimalViewModel model)
{
string wwwPath = _environment.WebRootPath;
var path = Path.Combine(wwwPath, "Images", model.Photo!.FileName);
if (model.Photo.Length > 0)
{
using var stream = new FileStream(path, FileMode.Create);
await model.Photo.CopyToAsync(stream);
}
return model.Animal!.PhotoUrl = model.Photo.FileName;
}
public interface IFileService
{
Task<string> File([FromForm] CreateAnimalViewModel model);
}
My ViewModel:
public class CreateAnimalViewModel
{
public Animal? Animal { get; set; }
public IFormFile Photo { get; set; }
}
My Controller:
public async Task<IActionResult> EditAnimal(int id)
{
var animal = await _repo.FindAnimalById(id);
ViewBag.Category = new SelectList(_repository.GetCategoriesTable(), "CategoryId", "Name");
return View(new CreateAnimalViewModel() { Animal = animal});
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditAnimal([FromForm] CreateAnimalViewModel model)
{
ModelState.Clear();
TryValidateModel(model);
await _file.File(model);
if (!ModelState.IsValid)
{
await _repo.EditAnimal(model.Animal!);
return RedirectToAction(nameof(Manager));
}
return View();
}
My Repository:
public async Task<int> AddAnimal(Animal animal)
{
_context.Add(animal!);
return await _context.SaveChangesAsync();
}
public async Task<int> EditAnimal(Animal animal)
{
_context.Update(animal);
return await _context.SaveChangesAsync();
}
public DbSet<Category> GetCategories()
{
var category = _context.Categories;
return category;
}
My View:
#model PetShop.Client.Models.CreateAnimalViewModel
<form asp-action="EditAnimal" method="post" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly"></div><input type="hidden" asp-for="Animal!.AnimalId" id="Space"/>
<dl class="row" >
<dt class = "col-sm-2"><label asp-for="Animal!.Name" id="Space"></label></dt>
<dd class = "col-sm-10"><input asp-for="Animal!.Name"/><span asp-validation-for="Animal!.Name" id="Validation"></span></dd>
<dt class = "col-sm-2"><label asp-for="Animal!.BirthDate" id="Space"></label></dt>
<dd class = "col-sm-10"><input asp-for="Animal!.BirthDate"/><span asp-validation-for="Animal!.BirthDate" id="Validation"></span></dd>
<dt class = "col-sm-2"><label asp-for="Animal!.Description" id="Space"></label></dt>
<dd class = "col-sm-10"><input asp-for="Animal!.Description"/><span asp-validation-for="Animal!.Description"></span>
</dd> <dt class = "col-sm-2"><label asp-for="Animal!.CategoryId" id="Space"></label></dt>
<dd class = "col-sm-10"><select asp-for="Animal!.CategoryId"asp-items="ViewBag.Category"></select>
<span asp-validation-for="Animal!.CategoryId"></span></dd>
<dt class = "col-sm-2"><label asp-for="Photo"></label></dt>
<dd class = "col-sm-10"><input type="file" asp-for="Photo" accept="image/*"/>
<img src="~/images/#Model.Animal!.PhotoUrl"
class="rounded-square"
height="50" width="75"
style="border:1px"
asp-append-version="true" accept="image/*" />
<span asp-validation-for="Photo" id="ImageValidation"></span></dd>
<br /> <br /><br/><input type="submit" value="Save" id="ButtonDesign"/>
</dl>
</form>
<a asp-action="Commands"><input type="submit" value="Back to Admin Page" id="BackPageButton"/></a>
image:
You cannot implement that:
I have gone through your code what you are trying to implement is to set initial value on input type="file" which is not possible due to
security reasons which you can check here. In addition you can also have a look here thousands of questions been askedbefore. Note that it's against RFC standard.
What you can do is:
While loading the Edit page hide the <input type="file"
Set a checkbox beside photo and it URL like below:
If the checkbox clicked then show the "file upload" option.
Note: Elementary JavaScript required for that implementation.
HTML:
<div>
<form asp-action="EditAnimal" method="post" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly"></div><input type="hidden" asp-for="Animal!.AnimalId" id="Space" />
<div>
<h4><strong>Animal Details</strong> </h4>
<table class="table table-sm table-bordered table-striped">
<tr>
<th> <label asp-for="Animal!.Name"></label></th>
<td> <input asp-for="Animal!.Name" class="form-control" placeholder="Enter animal name" /><span asp-validation-for="Animal!.Name"></span></td>
</tr>
<tr>
<th> <label asp-for="Animal!.Description"></label></th>
<td> <input asp-for="Animal!.Description" class="form-control" placeholder="Enter animal description" /><span asp-validation-for="Animal!.Description"></span></td>
</tr>
<tr>
<th> <label asp-for="Animal!.Category"></label></th>
<td> <input asp-for="Animal!.Category" class="form-control" placeholder="Enter animal category" /><span asp-validation-for="Animal!.Category"></span></td>
</tr>
<tr>
<th> <label asp-for="Photo"></label></th>
<td>
<img src="~/images/#Model.Animal!.PhotoUrl"
class="rounded-square"
height="50" width="75"
style="border:1px"
asp-append-version="true" accept="image/*" />
<span>#Model.ImageURL</span>
<input type="checkbox" id="CheckBoxId" class="form-check-input" style="margin-top:16px;border:1px solid" /> <span><strong>Upload New File</strong></span>
<input type="file" name="photo" id="chooseFile" accept="image/*" />
</td>
</tr>
<tr>
<th> <label>Updated On Local Time</label></th>
<td> <input asp-for="Animal!.LocalTime" class="form-control" disabled /><span asp-validation-for="Animal!.Category"></span></td>
</tr>
<tr>
<th> <button type="submit" class="btn btn-primary" style="width:107px">Update</button></th>
<td> </td>
</tr>
<tr>
<th>#Html.ActionLink("Back To List", "Index", new { /* id=item.PrimaryKey */ }, new { #class = "btn btn-success" })</th>
<td> </td>
</tr>
</table>
</div>
</form>
</div>
JavaScript:
#section scripts {
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script>
$(document).ready(function () {
//On Edit Page Load Hiding the upload option
$("#chooseFile").hide();
//When upload check box clicked showing the upload option
$('#CheckBoxId').mousedown(function() {
if (!$(this).is(':checked')) {
this.checked = true;
$("#chooseFile").show();
}
else{
$("#chooseFile").hide();
}
});
});
</script>
}
Output:

How to configure Checkboxes Materialize Css in Web application Asp.Net MVC

How do I configure Checkboxes in Asp.Net MVC Razor.
Since in the documentation we have the following configuration Materialize for checkboxes :
<p>
   <label>
     <input type = "checkbox" />
     <span> Network </span>
   </label>
</p>
And in Razor I could not perform this configuration.
<div class = "input-field col s12">
        #Html.EditorFor (model => model.AnnualDestaque)
        #Html.LabelFor (model => model.AnnualDestaque)
        #Html.ValidationMessageFor (model => model.AnnualDestaque, "", new {#class = "text-danger"})
</div>
Please include model Name in your cshtml page
#model WebApplication3.Models.Test
#{
ViewBag.Title = "Home Page";
}
#using (Html.BeginForm("Save", "Home", FormMethod.Post))
{
<div class="row">
<div class="col-md-4">
#Html.TextBoxFor(m => m.EmployeeName)
#Html.CheckBoxFor(m=>m.IsSelected)
</div>
<input type="submit" value="Save" />
</div>
}
Model
public class Test
{
public string EmployeeName { get; set; }
public bool IsSelected { get; set; }
}
If you just want to have a checkbox binded with your model like that :
public class Network
{
public bool Selected { get; set; }
public string Name { get; set; }
}
Just use :
#Html.CheckBoxFor(m=>m.Selected)
#Html.LabelFor(m=>m.Name)
I was able to solve it, and I am passing the answer.
I used Html Helper Documentation Html Helper MVC
It worked perfectly without mistakes the way it's meant to be.
<div class="input-field col s12">
<label>
<input data-val="true"
data-val-required="The Advertisement field is required."
id="Advertisement"/**** m => m.Advertisement ****/
name="Advertisement"/**** m => m.Advertisement ****/
type="checkbox"
value="true" />
<span>Anuncio Destaque</span>
<input name="Advertisement" type="hidden" value="false" />
</label>
</div>
You can make it work doing this:
<label>
<input type="checkbox" name="FIELDNAME" id="FIELDNAME" value="true" class="filled-in" #(Model.FIELDNAME? "checked" : "") />
<span>#Html.DisplayNameFor(model => model.FIELDNAME)</span>
</label>
<input name="FIELDNAME" type="hidden" value="false" />

Pass Object from view to controller using mvc4

View
#if (weekMaster != null)
{
using (Html.BeginForm("UpdatePlan", "generalPlan", FormMethod.Post, new { }))
{
<table class="table-bordered">
<tr>
#foreach (TermMaster obj in weekMaster.ToList())
{
<td align="center">
<span> #obj.termStartDate.ToString("dd MMM") - #obj.termEndDate.ToString("dd MMM")</span>
<br />
<input type="hidden" name="ObjHid" value="#obj" />
<input type="hidden" name="startDate" value="#obj.termStartDate" />
<input type="hidden" name="endDate" value="#obj.termEndDate" />
<input type="text" style="width:80%" name="weekSession" />
</td>
}
<td>
<input type="submit" value="Update" class="btn-primary" />
</td>
</tr>
</table>
} }
Controller
[HttpPost]
public ActionResult UpdatePlan(List<DateTime> startDate, List<DateTime> endDate, List<int> weekSession, List<TermMaster> ObjHid)
{
return View();
}
I am trying pass Class Object from View to Controller above TermMaster class Object pass using input method <input type="hidden" name="ObjHid" value="#obj" /> but showing NULL value if pass single value like startDate and endDate then it work fine.
What is wrong in my code? how to pass class object List in Post Method?
Please refer Image
You can not bind objects to controller from your input. You can serialize object to json. In the controller you can take your inputs value as string and deserialize it.
You have to do it by below approach.
Create a model instead of multiple parameters, and use index in cshtml.
public class model
{
public List<DateTime> startDate { get; set; }
public List<DateTime> endDate { get; set; }
public List<int> weekSession { get; set; }
public List<TermMaster> ObjHid { get; set; }
}
CSHTML
#{ int i = 0; }
#foreach (TermMaster obj in weekMaster.ToList())
{
<td align="center">
<span> #obj.termStartDate.ToString("dd MMM") - #obj.termEndDate.ToString("dd MMM")</span>
<br />
<input type="hidden" name="ObjHid[#i].termStartDate" value="#obj.termStartDate.ToString("dd MMM")" />
<input type="hidden" name="ObjHid[#i].termStartDate" value="#obj.termStartDate.ToString("dd MMM")" />
<input type="hidden" name="startDate[#i]" value="#obj.termStartDate" />
<input type="hidden" name="endDate[#i]" value="#obj.termEndDate" />
<input type="text" style="width:80%" name="weekSession[#i]" />
</td>
i++
}

Binding Complex Types in MVC5

I'm a newbie developer trying to develope a web application with asp .net mvc 5 for personel usage. The website kind of a quiz maker that I can insert Russian words with meanings and prepare a quiz by using these words.
When I trying to code the quiz page and post the data the the action method I faced some problem that I couldn't get around. I iterated through the Model, read the data and wrote them to the page. Now, what I want to do is, when I post the form, I want to get each question string and selected answer (maybe in this format: imgur.com/QETnafx). Therefore, I can easily check the answer string whether it is true or not.
I checked the following tutorials out:
Model Binding To A List by Phil Haack and ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries by Scott Hanselman
I hope I explained the situation clearly. If you need more information I can happily provide.
ViewModel
public class QuizInitializationModel
{
public List<Question> Questions { get; set; }
}
public class QuestionString
{
public int Id { get; set; }
public string WordString { get; set; }
}
public class Question
{
public QuestionString QuestionString { get; set; }
public List<AnswerItem> Answers { get; set; }
}
public class AnswerItem
{
public int Id { get; set; }
public string WordString { get; set; }
}
VIEW
#using (Html.BeginForm("Begin", "Quiz", FormMethod.Post))
{
<table class="table table-striped table-condensed table-bordered">
#for (int i = 0; i < Model.Questions.Count; i++)
{
<tr>
<td>
#Html.Label(Model.Questions[i].QuestionString.WordString)
</td>
<td>
#for (int item = 0; item < Model.Questions[0].Answers.Count; item++)
{
#Html.Label(Model.Questions[i].Answers[item].WordString)#:
#Html.RadioButton("array" + "[" + #i + "]" + "." + Model.Questions[i].QuestionString.WordString, Model.Questions[i].Answers[item].Id)<br />
}
</td>
</tr>
}
</table>
<input type="submit" value="Send" class="btn btn-primary" />
}
OUTPUT
<form action="/Admin/Quiz/Begin" method="post">
<table class="table table-striped table-condensed table-bordered">
<tr>
<td>
<label for="">вулкан</label>
</td>
<td>
<label for="trade">trade</label>
<input id="array_0________" name="array[0].вулкан" type="radio" value="18" /><br />
<label for="volcano">volcano</label>
<input id="array_0________" name="array[0].вулкан" type="radio" value="24" /><br />
<label for="talk__conversation">talk, conversation</label>
<input id="array_0________" name="array[0].вулкан" type="radio" value="15" /><br />
<label for="time">time</label>
<input id="array_0________" name="array[0].вулкан" type="radio" value="13" /><br />
<label for="income">income</label>
<input id="array_0________" name="array[0].вулкан" type="radio" value="21" /><br />
</td>
</tr>
<tr>
<td>
<label for="">мама</label>
</td>
<td>
<label for="universe">universe</label>
<input id="array_1______" name="array[1].мама" type="radio" value="25" /><br />
<label for="peace">peace</label>
<input id="array_1______" name="array[1].мама" type="radio" value="2" /><br />
<label for="value">value</label>
<input id="array_1______" name="array[1].мама" type="radio" value="20" /><br />
<label for="mom__mama">mom, mama</label>
<input id="array_1______" name="array[1].мама" type="radio" value="17" /><br />
<label for="industry">industry</label>
<input id="array_1______" name="array[1].мама" type="radio" value="19" /><br />
</td>
</tr>
</table>
And how can i fix the ids of the labels like "array_1______" ?
They appeared when I added this code "array" + "[" + #i + "]" + "." to the RadioButton control for the purpose of assign an index for each answer.
Html helpers replace invalid characters with an underscore (a period is actually not invalid, but would cause problems with jquery so its also replaced an underscore). However id attribute is not the problem, although you are generating duplicates which is invalid html.
Your manually generating the name attribute for the radio buttons which have no relationship to any property in your model so wont be bound when you post back. Your model needs to include a property you can bind the selected answer to. Modify the Question model to
public class Question
{
public QuestionString QuestionString { get; set; }
public List<AnswerItem> Answers { get; set; }
public int SelectedAnswer { get; set; } // add this
}
and modify the view to
#using (Html.BeginForm()) // note parameter not necessary if your posting to the same controller/action
{
#for (int i = 0; i < Model.Questions.Count; i++)
{
...
#Html.HiddenFor(m => m.Questions[i].QuestionString.Id)
<h2>#Model.Questions[i].QuestionString.WordString)</h2>
...
#foreach(var answer in Model.Questions[i].Answers)
{
var id = string.Format("{0}-{1}", #i, answer.Id);
#Html.Label(id, answer.WordString)
#Html.RadioButtonFor(m => m.Questions[i].SelectedAnswer, answer.ID, new { id = id })
}
....
}
<input type="submit" value="Send" class="btn btn-primary" />
}
The radio buttons are now bound to the SelectedAnswer property and when you post back, the value will be the ID of the selected AnswerItem
Note also:
A hidden input has been added for the ID of the question so the
question can be identified on post back
The question text is in a heading tag (could be another tag), but a
label is not appropriate - a label is an element associated with a
control (for setting focus to the control) but you don't have an
associated control
A unique id is created in the foreach loop so you can give each
radio button a unique id (so the html is valid) and associate the
label (the answer text) with the button

modelbinding on ASP.NET MVC Razor engine failing

The model binding just isn't working for me - I always get NULL coming through to the controller! Any thoughts people?
Rob
Here is my action signature:
public ActionResult SearchForUser(SearchForUserModel m)
Here is my Razor header model declaration:
#model WebOne.Models.StatusIndexModel
StatusIndexModel is a composite model containing SearchForUserModel:
public class SearchForUserModel
{
[Required(ErrorMessage = "Search information required")]
[DisplayName("Contact Search")]
public string Search { get; set; }
}
Here is my Razor:
#using (Html.BeginForm("SearchForUser", "Status"))
{
<div>
<div class="editor-field">
#Html.TextBoxFor(m => m.searchForUserModel.Search)
<input type="submit" class="formbutton_small" value="Find" />
<br />
#Html.ValidationMessageFor(m => m.searchForUserModel.Search)
</div>
</div>
}
Here is the generated HTML:
<form action="/Status/SearchForUser" method="post">
<div>
<div class="editor-field">
<input data-val="true" data-val-required="Search information required" id="searchForUserModel_Search" name="searchForUserModel.Search" type="text" value="" />
<input type="submit" class="formbutton_small" value="Find" />
<br />
<span class="field-validation-valid" data-valmsg-for="searchForUserModel.Search" data-valmsg-replace="true"></span>
</div>
</div>
</form>
You need to specify the prefix:
public ActionResult SearchForUser(
[Bind(Prefix="searchForUserModel")]SearchForUserModel m
)

Resources