Viewmodel always null following file upload - c#

I am creating a page in Asp.Net MVC where a user can upload a file, along with details about the file from textboxes.
For this I use a viewmodel, and a very simple method configuration. The page is populated correctly by the [Get] Method, and the user can choose the file and enter the details, but once the 'Submit' button is clicked, and the [Post] method is called, the viewmodel is completely null.
I have done my research on this and have tried:
adding enctype="multipart/form-data"
simply using the file as a separate parameter
To no avail.
Here is my controller methods:
public ActionResult FileComment(int id)
{
//set up [get] view
return View("FileComment", obj);
}
//THIS METHOD's VIEWMODEL ALWAYS NULL
[HttpPost]
public ActionResult FileComment(CalibrationCommentViewModel file)
{
//save file to database
return View("Edit", new { id = file.id });
}
Here is part of my view:
#using (Html.BeginForm("FileComment", "Calibration", FormMethod.Post, new { enctype = "multipart/form-data", #data_ajax = "false" }))
{
#Html.HiddenFor(m => m.ID)
<div class="container">
<h4>Add File for #Model.ID</h4>
<hr />
<div class="row">
<div class="col-md-1">g
#Html.LabelFor(model => model.file, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-2">
#Html.TextBoxFor(model => model.file, new { type = "file" })
</div>
<div class="col-md-9"></div>
</div>
<br />
<div class="row">
<div class="col-md-1">
#Html.LabelFor(model => model.attachmentType, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-2">
#Html.DropDownListFor(model => model.attachmentType, Model.attachTypeList, new { #class = "form-control" })
</div>
<div class="col-md-9"></div>
</div>
<br />
<div class="row">
<div class="col-md-1">
#Html.LabelFor(model => model.Date, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-2">
#Html.EditorFor(model => model.Date)
</div>
<div class="col-md-9"></div>
</div>
<br />
<div class="row">
<div class="col-md-1">
#Html.LabelFor(model => model.description, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-2">
#Html.TextAreaFor(model => model.description, new { cols=35, #rows=3})
</div>
<div class="col-md-9"></div>
</div>
<br />
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-2">
<button type="submit" onclick="JavascriptFunction()">Add to #Model.ID</button>
</div>
<div class="col-md-9"></div>
</div>
</div>
}

Change
public ActionResult FileComment(CalibrationCommentViewModel file)
to
public ActionResult FileComment(CalibrationCommentViewModel model)

your view has no reference to view model at the top the view something like this
#model Nameofyourproject.Models.CalibrationCommentViewModel

Related

Data parsing from Model to Partial view error ASP.NET MVC

In my Application, In EDIT view I want to call data from the database and fill into the partial view that have sent through to the database when creates the request using same partial view . Currently my code I have written like below. But what happens is, If there is 4 records, It will generate 4 line, but there is no data there. All comes as empty.
<ul id="RequItms" style="list-style-type: none">
#if (Model != null && Model.GeneralItmsList != null)
{
foreach (var item in Model.GeneralItmsList)
{
Html.RenderAction("GeneralItmsPartialView", "AppRequests", Model.GeneralItmsList.ToList());
}
}
</ul>
Here is the view. This is the view I'm currently getting from the above code.
But this is the way it should load in that empty fields.
I have checked in the Model.GeneralItemsList There is shows the data, But I think when parsing it to the partial view must be the error occurs.
Here is the partial view code looks like.
#model Asp_PASMVC.Models.GeneralItms
#using Asp_PASMVC.Infrastructure
<li style="padding-bottom:15px">
#using (Html.BeginCollectionItem("GeneralItmsList"))
{
#Html.HiddenFor(model => model.TempID)
<div class="form-horizontal" id="quickForm" novalidate="novalidate">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
<div class="col-md-5 col-sm-6">
<div class="form-group">
Select Item Description
<div class="col-md-10">
#Html.EditorFor(model => model.Attachment_Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Attachment_Description, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="form-group">
Attachment Amount
<div class="col-md-10">
<div class="input-group-prepend">
<span class="input-group-text">Rs.</span>
#Html.EditorFor(model => model.Attachment_Amount, new { htmlAttributes = new { #class = "form-control" } })
</div>
#Html.ValidationMessageFor(model => model.Attachment_Amount, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="form-group">
Attachment
<div class="col-md-10">
<input type="file" name="ImageData#(Model.TempID.ToString())" id="ImageData#(Model.TempID.ToString())" multiple="multiple" data-id="Img#(Model.TempID.ToString())" onchange="checkImage(this)" />
#Html.ValidationMessageFor(model => model.Attachment, "", new { #class = "text-danger" })
</div>
</div>
<img id="Img#(Model.TempID.ToString())" src="" alt="" width="100" height="100" class="ml-1" />
</div>
<button type="button" class="btn btn-danger" onclick="$(this).parent().remove();">Remove</button>
</div>
</div>
}
</li>
I hope that I have explained this question properly. Thanks for the support.

ASP.NET MVC - Using a Form in a Bootstrap Modal to call an Action from a Controller

I have a Form that creates an entry into my database. I am trying to add an additional form via a modal that will allow the user to populate the first form by searching a property on the webservice.
What I need is for when the user types hits search in the modal it will call an action on controller that then runs my web service client that then returns a list of appropriate information. I then want this list displayed as a table on the page. The user can then select which search result they want to use to which will then populate the original form. I think I can figure most of this out but wasnt sure of the best way to kick off the search from the modal. Code is as follows.
View
#model *******
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<!-- Trigger the modal with a button -->
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#Search">Populate From Service</button>
<!-- Modal -->
<div id="Search" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Search By Property</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<p>blah blah blah</p>
<div class="form-group">
<label for="API14" class="control-label col-md-2">API</label>
<div class ="col-md-10">
<input type="text" class="form-control" id="API14" aria-describedby="API14" placeholder="Enter API">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Search" class="btn btn-success" />
<input type="button" value="Close" data-dismiss="modal" class="btn btn-danger" />
</div>
</div>
</div>
</div>
</div>
</div>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.API14, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.API14, new { htmlAttributes = new { #class = "form-control"} })
#Html.ValidationMessageFor(model => model.API14, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PROP_NO, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PROP_NO, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PROP_NO, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PROP_NM, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PROP_NM, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PROP_NM, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ENTITY, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10 ">
#Html.EditorFor(model => model.ENTITY, new { htmlAttributes = new { #class = "form-control" } } )
#Html.ValidationMessageFor(model => model.ENTITY, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PROD_ZONE_NM, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PROD_ZONE_NM, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PROD_ZONE_NM, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.LEASE_NAME, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.LEASE_NAME, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LEASE_NAME, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.WELL_NO, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.WELL_NO, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.WELL_NO, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-success" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
You could divide your issue into two steps.
Step 1: "What I need is for when the user types hits search in the modal it will call an action on controller that then runs my web service client that then returns a list of appropriate information. I then want this list displayed as a table on the page."
Add the following to your scripts section:
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script>
$(document).ready(function () {
$('#submitModal').click(function () {
var data = {
API14: $('#API14').val()
}
$.ajax({
url: '/Default/SearchByProperty',
data: data
}).success(function (html) {
$('#API14List').html(html);
$('#Search').modal('toggle');
});
});
});
</script>
}
This is a simple ajax call that takes the value from you modal input and submits to the server. Note the "url" parameter passed in the call as this will need to match your "/{controller}/{action}". Important: You will also need to update your "Search" button#API14 to type "button", not "submit", as this will avoid a postback which is undesired when making AJAX calls.
You can then add something like this to your controller:
public ActionResult SearchByProperty()
{
var model = new List<string>();
model.Add("one");
model.Add("two");
model.Add("three");
return PartialView(model);
}
... which will require the following in a partial view file I named SearchByProperty.cshtml:
#model List<string>
<table>
#foreach (var item in Model) {
<tr class="API14-item">
<td>#item</td>
</tr>
}
</table>
Step 2: "The user can then select which search result they want to use to which will then populate the original form. I think I can figure most of this out but wasnt sure of the best way to kick off the search from the modal. Code is as follows."
If you are confident in writing jQuery, then you should be able to write some js in the scripts section of your create page that will take the values you place in your table and populate your form:
$(document).on('click', '.API14-item', function () {
//
// TODO: your code here
//
});
Hope this helps!

JQuery Validation message shows on page load

I have the following view:
#model GRCWebApp.ViewModels.NewClubInterestsViewModel
#{
ViewBag.Title = "Add Club Interests";
}
<div class="col-md-10 col-offset-md-1">
<h2 class ="text-success">Add Club Interests for #Html.DisplayFor(model => model.Name)</h2>
</div>
#using (Html.BeginForm("NewInterests", "Club", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
<div class="row">
<div class="col-md-8">
<div class="well bs-component">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(x => Model.ClubId)
<div class="form-group">
<div class="col-md-10 col-md-offset-1">
<h3>Tick the areas your club is interested/runs events in</h3>
</div>
</div>
<div class="col-md-offset-1">
#for (int i = 0; i < Model.ClubTypeInterests.Count(); i++)
{
<div>
#Html.HiddenFor(x => Model.ClubTypeInterests[i].InterestId)
#Html.CheckBoxFor(x => Model.ClubTypeInterests[i].selected)
#Html.LabelFor(x => Model.ClubTypeInterests[i].InterestName, Model.ClubTypeInterests[i].InterestName)
</div>
}
</div>
<div class="form-group">
<div class="row">
<div class="col-md-offset-1 col-md-12">
<input type="submit" name="Submit" value="Next" class="btn btn-success btn-lg" /> to setup Online membership
<input type="submit" name="Submit" value="Complete" class="btn btn-warning btn-sm" /> to just provide online event entries
</div>
</div>
</div>
</div>
</div>
</div>
</div>
}
#using (Html.BeginForm("AddInterest", "Club"))
{
#Html.AntiForgeryToken()
<hr />
<div class="row">
<div class="col-md-8">
<div class="well bs-component">
<div class="form-group">
<div class="col-md-12 col-md-offset-1">
<h3>Not listed? - Add extras here</h3>
</div>
</div>
#Html.HiddenFor(model => model.ClubTypeId)
#Html.HiddenFor(model => model.ClubId)
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-inline">
<div class="form-group">
<div class="row col-md-offset-1 col-md-11">
<div class="col-md-4">
#Html.LabelFor(model => model.InterestName, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.InterestName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.InterestName, "", new { #class = "text-danger" })
</div>
<div class="col-md-5">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
<input type="submit" value="Add" class="btn btn-info" style="margin-top: 22px" />
</div>
</div>
</div>
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Overtime the page loads the Validation message shows for InterestName in the second form AddInterest.
The Get method for the whole form is:
[HttpGet]
public ActionResult NewInterests(NewClubInterestsViewModel model, int id)
{
//Find the Club and then pass its id to the ViewModel
var club = db.Clubs.Find(id);
//model.ClubId = club.ClubId ;
//Interests List
IEnumerable<Interest> allExistingInterests;
//Generate a list of the interests that apply to that type of club
using (ApplicationDbContext context = new ApplicationDbContext())
{
allExistingInterests = context.Interests
.Where(s => s.ClubTypeId == club.ClubTypeId)
.OrderBy(s => s.InterestName)
.ToList();
}
IEnumerable<int> clubInterestIds = club.ClubInterests.Select(x => x.InterestId).ToList();
//Generate the ViewModel with the appropriate Interests
var viewModel = new NewClubInterestsViewModel
{
ClubId = club.ClubId,
Name = club.Name,
ClubTypeId = club.ClubTypeId,
ClubTypeInterests =
allExistingInterests.Select(
x => new ClubInterestsViewModel { InterestId = x.InterestId, InterestName = x.InterestName, selected = clubInterestIds.Contains(x.InterestId) }).ToArray()
};
return View(viewModel);
}
What do I need to do to stop the validation message showing on load?
Remove the NewClubInterestsViewModel model parameter from your GET method. It should be just
public ActionResult NewInterests(int id)
The first step in the model binding process is that instances of your parameters are initialized and then its properties are set based on form values, route values, query string values etc. In your case there are no values to set, so the properties of your model are their defaults, but because you have validation attributes on your properties, validation fails and errors are added to ModelState which are then displayed in the view.

ASP.NET MVC I'm trying to add a review product (http post) in the same page using (partial view)

_getProductReviews.cshtml:
I'm calling my partial view like this:
<p>#Html.Partial("_CreateR");</p>
_CreateR.cshtml:
This code is auto generated by the controller:
#model Commerce.Domain.Entites.t_review
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>t_review</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.text, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.text)
#Html.ValidationMessageFor(model => model.text)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.title, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.title)
#Html.ValidationMessageFor(model => model.title)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.customer_id, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.customer_id)
#Html.ValidationMessageFor(model => model.customer_id)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.product_fk, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.product_fk)
#Html.ValidationMessageFor(model => model.product_fk)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
ProductController:
// GET: /Product/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Product/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "id,text,title,customer_id,product_fk")] t_review review)
{
if (ModelState.IsValid)
{
prose.CreateReview(review);
return RedirectToAction("Index");
}
return View(review);
}
When I use a simple view with actionlink it works but when I try to use partial View shows this msg
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Commerce.Domain.Entites.t_review]', but this dictionary requires a model item of type 'Commerce.Domain.Entites.t_review'.
Html.Partial renders a view without calling the Controller first.
Html.Action calls a Controller Action which can return like everything: a view, a partial view, json, etc.
As a general guideline, you should use Html.Partial only when you want to display static content or when you have access to the model required. For everything else, like wen you want to return more data from the server, use Html.Action.

Display error when input field is empty

I have a view that allows user to add new items to a database.
The view looks like this:
#model News.Models.NewsEntry
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>NewsEntry</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.title, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.title)
#Html.ValidationMessageFor(model => model.title)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.body, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.body)
#Html.ValidationMessageFor(model => model.body)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.category, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.category)
#Html.ValidationMessageFor(model => model.category)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Can I write some function (if sentance) inside my view that checks if the title input or the body input are empty and displays a message if they are.
My attempt so far:
EDIT:
In ASP MVC this should be done on the model, decorate the property using Required attribute
[Required(ErrorMessage = "Title is required!")]
public string title { get; set; }
[Required(ErrorMessage = "Body is required !")]
public string body { get; set; }
You will need to add following namespace:
using System.ComponentModel.DataAnnotations;
I created a project for you.
Try it its very simple:

Categories

Resources