I am not sure whether I've framed the question properly above in subject but I will try to explain to my best about the question I have.
I have below ContactUsModel which is a part of HomeViewModel, better say Nested Model Class in a single model
public class ContactUsDataModel
{
public string ContactName { get; set; }
public string ContactEmail { get; set; }
public string ContactMessage { get; set; }
public string ContactPhone { get; set; }
}
and I am getting this Model referred in HomeViewModel as below:
public class HomeViewModel
{
/*My other models goes here*/
public ContactUsDataModel CUDModel { get; set; }
}
Now in Index.cshtml view I strongly create a form view as below:
#model ProjectName.Models.HomeViewModel
<!--I have other views for other models-->
#using (Html.BeginForm("ContactPost", "Home", FormMethod.Post, new { id = "contactform" }))
{
#Html.TextBoxFor(m => m.CUDModel.ContactName, new { #class="contact col-md-6 col-xs-12", placeholder="Your Name *" })
#Html.TextBoxFor(m => m.CUDModel.ContactEmail, new { #class = "contact noMarr col-md-6 col-xs-12", placeholder = "E-mail address *" })
#Html.TextBoxFor(m => m.CUDModel.ContactPhone, new { #class = "contact col-md-12 col-xs-12", placeholder = "Contact Number (optional)" })
#Html.TextAreaFor(m=>m.CUDModel.ContactMessage, new { #class = "contact col-md-12 col-xs-12", placeholder = "Message *" })
<input type="submit" id="submit" class="contact submit" value="Send message">
}
I do ajax Post as below:
$('#contactform').on('submit', function (e) {
e.preventDefault();
var formdata = new FormData($('.contact form').get(0));
$.ajax({
url: $("#contactform").attr('action'),
type: 'POST',
data: formdata,
processData: false,
contentType: false,
//success
success: function (result) {
//Code here
},
error: function (xhr,responseText,status) {
//Code here
}
});
});
and in Controller I tried to receive it as below:
public JsonResult ContactPost(ContactUsDataModel model)
{
var name=model.ContactName; //null
/*Fetch the data and save it and return Json*/
//model is always null
}
For some reason the above model is always null. But this works if I refer the model as HomeViewModel model instead of ContactUsDataModel model in controller parameter like below:
public JsonResult ContactPost(HomeViewModel model)
{
var name=model.CUDModel.ContactName; //gets value
/*Fetch the data and save it and return Json*/
//Model is filled.
}
My question here is even though I fill model of type
ContactUsDataModel in the view I am getting it as null if I refer
directly, but ContactUsModel which is inside HomeViewModel gets
filled. Doesn't type of model matter here. Is the hierarchy its
referred is necessary while fetching in controller?
Well, if your generated <input> name is CUDModel.ContactName instead of simply ContactName, the default Model-Binder wouldn't be able to bind it.
Fortunately, you can use the [Bind] attribute with prefix:
public JsonResult ContactPost([Bind(Prefix="CUDModel")]ContactUsDataModel model)
{
// ...
}
See MSDN
Your view posts the Type you have referenced in the view - #model ProjectName.Models.HomeViewModel - CUDModel is simply a property of HomeViewModel.
Using your web browser, inspect each DOM input element "name" property. MVC automatically maps properties from your inputs to the class using the input's "name" property.
To solve this you can create a custom model binder or create the inputs by hand, specifying the name property in such a way that the automatic model binder can match them to properties of your class.
However, there isn't anything wrong with your controller action taking HomeViewModel as an argument.
More information, found here.
Related
I have a save method which will be called via AJAX post and it passes a object instead of the view model. I parse the object and build the view model. Is there way I can validate that view model object
against the data annotation defined on the view model.
In the below example I tried to check the model state but it always is true and is not validating.
Is there a way I can run validate against ViewModel?
public class InvoiceViewModel
{
public long InvoiceId { get; set;
[Display(Name = "Invoice Number"),Required]
public string InvoiceNumber { get; set;}
[Display(Name = "Type"),Required]
public string InvoiceType { get; set; }
[Display(Name = "Amount"),Required]
public decimal InvoiceAmount { get; set; }
}
// controller method
public JsonResult SaveInvoice([FromBody] object invoice)
{
// parse through the invoice object
var invoiceVM = GetInvoiceViewModel(invoice)
// I tried the ModelState.IsValid - it did nto work
// how can I validate invoiceVM against the data annotation defined
}
public InvoiceViewModel GetInvoiceViewModel(object invoice)
{
}
As Camilo Terevinto said,you need to fix how to pass the model to action by ajax.
Before you did the work,you need to know that if the model data you passed contains wrong format,the backend would recieve null model.For example,InvoiceAmount is a decimal type property,if you do set a string like "aaa" or an empty string " ",it would be null.
And something special about model binding you need to know,the long and decimal type property have default value 0 although you do not pass the property.The Reuiqred attribute does not work for this.
For example,you could see the following gif,I not only do not pass the value but also do not pass the InvoiceAmount property(for how to do not pass the property you could check the following code).But in the backend you could see InvoiceAmount have default value 0:
var data = {
InvoiceId: $("#InvoiceId").val(),
InvoiceNumber: $("#InvoiceNumber").val(),
InvoiceType: $("#InvoiceType").val(),
//InvoiceAmount: $("#InvoiceAmount").val() //remove this...
}
As a conclusion,that is to say,for the long and decimal type property,you could not pass wrong format data to them,but you could send model without using these types' properties.
Here is a whole working demo:
View:
#model InvoiceViewModel
<form>
<div>
<label asp-for="InvoiceId"></label>
<input asp-for="InvoiceId" class="form-control" />
</div>
<div>
<label asp-for="InvoiceNumber"></label>
<input asp-for="InvoiceNumber" class="form-control" />
</div>
<div>
<label asp-for="InvoiceType"></label>
<input asp-for="InvoiceType" class="form-control" />
</div>
<div>
<label asp-for="InvoiceAmount"></label>
<input asp-for="InvoiceAmount" class="form-control" />
</div>
<div>
<input type="button" value="post" onclick="PostData()" />
</div>
</form>
#section Scripts
{
<script>
function PostData() {
var data = {
InvoiceId: $("#InvoiceId").val(),
InvoiceNumber: $("#InvoiceNumber").val(),
InvoiceType: $("#InvoiceType").val(),
InvoiceAmount: $("#InvoiceAmount").val()
}
console.log(data);
console.log(JSON.stringify(data));
$.ajax({
url: "/Home/SaveInvoice",
type: "POST",
contentType: "application/json; charset=utf-8", //be sure add this...
data: JSON.stringify(data),
success: function (res) {
alert(res.message);
}
})
}
</script>
}
Controller:
public JsonResult SaveInvoice([FromBody]InvoiceViewModel invoice)
{
if (ModelState.IsValid)
{
return Json(new { message = "Success" });
}
return Json(new { message = "Error" });
}
Result:
When creating Employee entity you are supposed to select MeetingCenterfrom DropDownList. All MeetingCenters show just fine in DropDownList with their Names, but when some of them is selected and Employee is created Meeting Center is null. Im using NoSQL DocumentDB database.
Controller:
[ActionName("Create")]
public async Task<IActionResult> CreateAsync()
{
ViewBag.MeetingCentersList = await _meetingCenterReposiotry.GetItemsAsync();
return View();
}
Create View:
#model Employee
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { #class = "form-horizontal" }))
{
...
<div class="form-group">
#Html.LabelFor(MeetingCenter => Model.MeetingCenter, new { #class = "control-label" })
#Html.DropDownListFor(MeetingCenter => Model.MeetingCenter, new SelectList(ViewBag.MeetingCentersList, "MeetingCenterId", "Name"), new { #class = "form-control" })
</div>
...
}
Piece of Employee Model
public class Employee
{
...
[JsonProperty(PropertyName = "id")]
public string EmployeeId { get; set; }
[JsonProperty(PropertyName = "meetingCenter")]
public MeetingCenter MeetingCenter { get; set; }
...
}
Piece of MeetingCenter Model
public class MeetingCenter
{
...
[JsonProperty(PropertyName = "id")]
public string MeetingCenterId { get; set; }
...
}
With your current code, the DropDownListFor helper will render a SELECT element with options, which has the MeetingCenterId as the value attribute and the Name as the Text. The SELECT element's name attribute value will be MeetingCenter. So when the form is submitted the form data will look like this
MeetingCenter: 2
Assuming user selected the option with value "2".
But the MeetingCenter property of your view model(Employee) is not a numeric type, it is a complex type(MeetingCenter). So model binder cannot map this value to MeetingCenter property of your view model.
You can render the SELECT element with the name MeetingCenter.MeetingCenterId and then model binder will be able to map the posted form data as the input element name matches with the naming-structure of your view model.
So you should render something like this inside your form.
<select name="MeetingCenter.MeetingCenterId">
</select>
You can generate the above markup by using the SELECT tag helper and specifying MeetingCenter.MeetingCenterId as the asp-for property.
<select asp-for="MeetingCenter.MeetingCenterId"
asp-items="#(new SelectList(ViewBag.MeetingCentersList,
"MeetingCenterId", "Title"))">
</select>
Now when the form is submitted, it will populate the MeetingCenter property of your view model and it's MeetingCenterId property.
If you want the full MeetingCenter property to be populated (properties other than MeetingCenterId, get the full object by querying the data provided by _meetingCenterReposiotry.GetItemsAsync() using the MeetingCenterId available to you in the HttpPost action. Something like this
var id = viewModel.MeetingCenter.MeetingCenterId;
var items = await _meetingCenterReposiotry.GetItemsAsync();
var item = items.FirstOrDefault(a=>a.MeetingCenterId==id);
// User item now
// May be do somethig like : viewModel.MeetingCenter = item;
I also suggest you to use the correct types. If MeetingCenterId is numeric value, use int as type instead of string
I have a controller which returns a Partial View with a Model.
The view that contains the partial View has a button, When clicking on the button, a function of the controller is called and it returns the same partial View with the model updated. The new model is loaded without any problem, but the page doesn't reload, the view is the same view as before the onclik.
The code of partial View
<div class="well">
#if (publication.Coments != null) {
foreach (var comments in publication.Coments) {
<div class="row">
<div class="col-md-12">
#comments.Nick
<span class="pull-right">#comments.DateComment.ToShortDateString()</span>
<p>#comments.Message</p>
</div>
</div>
}
}
</div>
The method of controller return the partial view with the next code :
ViewData["publication"] = publication;
return PartialView("details_comment");
I call the partial view in the view :
#Html.Partial("../Home/ListPublication")
I debugged the page and the model is reloaded ok, but the partial view doesn't reload.
I mentioned on the comments I was having the same issue but later today I figured at MSDN that this is an expected behaviour if you are returning the same model and view types after a POST. For my scenario I had to use ModelState.Clear() before changing any values on the returning view model. To explain a little better, I'll try to describe my case as close as I can remember to try to contextualize:
view models
// ~/Models/SomeFeatureModels.cs
public class SomeViewModel {
public int Id {get;set;}
public string SomeField{get;set;}
public string SomeOtherField{get;set;}
public DateTime CreatedOn{get;set;}
}
public class SomeOtherViewModel {
public int Id {get;set;}
public string SomeField{get;set;}
public string SomeOtherField{get;set;}
public DateTime CreatedOn{get;set;}
}
public class IndexViewModel {
public string FeatureTitle{get;set;}
}
templates
<!-- ~/Views/Some/SomeInfo.cshtml -->
#model.App.Models.SomeInfoViewModel
#using(Html.BeginForm("AddSomeInfo", "Some", FormMethod.Post, new { #id="frmAddSomeInfo" }) {
<div id="some-info">
#Html.DisplayFor(m=>m.SomeField)
#Html.EditorFor(m=>m.SomeField)
#Html.ValidatorFor...
<input type="submit">Go</input>
</div>
}
<!-- ~/Views/Some/SomeInfo.cshtml -->
#model.App.Models.SomeOtherInfoViewModel
#using(Html.BeginForm("AddSomeOtherInfo", "Some", FormMethod.Post, new { #id="frmAddSomeOtherInfo" }) {
<div id="some-other-info">
#Html.DisplayFor(m=>m.SomeField)
#Html.EditorFor(m=>m.SomeField)
#Html.ValidatorFor...
<input type="submit">Go</input>
</div>
}
<!-- ~/Views/Some/Index.cshtml -->
#model App.Models.IndexViewModel
#{
layout: "someLayout.cshtml"
}
<h2>Model.FeatureTitle</h2>
#{ RenderAction("SomeInfo") }
#{ RenderAction("SomeOtherInfo") }
#section scripts {
//bundle must include:
// jquery, jquery.unobtrusive.ajax, jquery.validate, jquery.validate.unobtrusive
<script>
$(function() {
$('#frmAddSomeInfo').submit(function(e) {
e.preventDefault();
var form = $(this);
if (form.valid()) {
$.ajax({
url: form.action,
type: form.method,
data: form.serialize()
}).done(function(payload) {
$('#some-info').html(payload);
}).fail(function(jqXHR, error, errorThrown) {
// handle
});
}
});
$('#frmAddSomeOtherInfo').submit(function(e) {
e.preventDefault();
var form = $(this);
if (form.valid()) {
$.ajax({
url: form.action,
type: form.method,
data: form.serialize()
}).done(function(payload) {
$('#some-other-info').html(payload);
}).fail(function(jqXHR, error, errorThrown) {
// handle
});
}
});
});
</script>
}
controller
// ~/Controllers/SomeController.cs
public class SomeController: Controller {
// This would be the landing view of a given controller
public ActionResult Index() {
// for this view model I have basically typed the things that
// are a concern of Index, like page title and other things
// but nothing related to the view models that I will be
// updating or inserting
var viewModel = somePrivateMethodToBuildMyViewModel();
return View(viewModel);
}
public PartialViewResult SomeInfo() {
// this is technically a fresh instance with normalized
// or localized default data that I will be sending
// when the index requests this partial view
var someViewModel = somePrivateMethodToBuildSomeViewModel();
return PartialView(someViewModel);
}
[HttpPost]
public PartialViewResult AddSomeInfo(SomeViewModel viewModel) {
// this is where I am checking if my view model is alright
// and then the "issue" will occur
if (!ModelState.IsValid) {
// ... handle
} else {
// I was doing "normal stuff" like
// translating view model to an entity (let's call it model)
// committing changes with some ORM and get and id and timestamp back
// and naturally assign these values to the view model
viewModel.Id = model.id;
viewModel.createdOn = model.created_on;
}
// then return the same view and same model **types** of the request
return PartialView("SomeInfo", viewModel);
}
}
This is the part that I had to use ModelState.Clear(). I've changed my POST action to this:
// ~/Controllers/SomeController.cs
public class SomeController: Controller {
// ...
[HttpPost]
public PartialViewResult AddSomeInfo(SomeViewModel viewModel) {
if (!ModelState.IsValid) {
// ... handle
} else {
// Included this line for valid model state handling
ModelState.Clear();
// then persist, etc
// then change view model
viewModel.Id = model.id;
viewModel.createdOn = model.created_on;
}
// then returning the view model to the same partial should now work
return PartialView("SomeInfo", viewModel);
}
}
Sorry this got a little too much, but I just wanted to show how I got it working on my scenario.
Try like below.
return PartialView("details_comment", publication);
You need to pass the model's object with the partial view to see the value, as your model will get bound with the helpers to create a view
return PartialView("details_comment",publication);
Updated
Instead of relative URL:
Try: #Html.Partial(#"~/Views/Home/ListPublication.cshtml") or use
#{Html.RenderPartial("ListPublication");}
The other thing I noticed is that you are using old ViewData. I am not saying you should not use it at all but a better approach is to use a strongly typed ViewModel. A View Model is a class that will have necessary properties and logic for your view to render. So you could have a class:
public class PublicationVM{public Publication publication {get; set;} }
and can have other necessary properties if needed by the view. SO has lot of information about using View Model. Please check What is ViewModel in MVC?
I have a partial view to post comment for my article module on my main view for article detail. Model for comment has three required fields, ID (identity field), ArticleId and CommentText. (I am using Razor syntax)
I tried to pass ArticleId at controller in Create Action.
public ActionResult Create(ArticleComment articlecomment, string AID)
{
articlecomment.ArticleId = AID; //this is required
if (User.Identity.IsAuthenticated)
{
articlecomment.UserId = WebSecurity.CurrentUserId.ToString();
}
else
{
articlecomment.UserId = Constants.Anonymus;
}
articlecomment.CommentDate = DateTime.Now;
if (ModelState.IsValid)
{
db.ArticleComment.Add(articlecomment);
int success = db.SaveChanges();
if (success > 0)
{
return Content("<script language='javascript' type='text/javascript'>alert('Comment added successfully.');window.location.href='" + articlecomment.ArticleId + "';</script>");
}
else
{
return Content("<script language='javascript' type='text/javascript'>alert('Posting comment has failed, please try later.');window.location.href='" + articlecomment.ArticleId+ "';</script>");
}
}
return PartialView(articlecomment);
}
But still ModelState.IsValid is returning false. I have used following code and find that ModelState is getting ArticleId as null.
foreach (var modelStateValue in ViewData.ModelState.Values)
{
foreach (var error in modelStateValue.Errors)
{
// Do something useful with these properties
var errorMessage = error.ErrorMessage;
var exception = error.Exception;
}
}
I have also thought to set value for ArticleId using Hidden field using ViewBag but have not find any working code. I tried following:
#Html.HiddenFor(model => model.ArticleId, new { #value = ViewBag.Article })
and
#Html.HiddenFor(model => model.ArticleId, (object)ViewBag.Article)
My 'ParticalView' to post comment is:
#model Outliner.Models.ArticleComment
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="editor-label">
#* #Html.HiddenFor(model => model.ArticleId, new { #value = ViewBag.Article })
#Html.HiddenFor(model => model.ArticleId, (object)ViewBag.Article)*#
#Html.LabelFor(model => model.Comment)
<span class="error">#Html.ValidationMessageFor(model => model.Comment)</span>
</div>
#Html.TextAreaFor(model => model.Comment)
<input type="submit" value="Post" />
}
And this is how I am calling this partial view on 'ArticalDetail' view (my main view):
#Html.Action("Create", "ArticleComment")
I have passed required field value at controller for a View before, but I am facing issue for PartialView. What I am doing wrong and how can I make this work?
Edit After a try
As Satpal and Fals lead me to a direction, I tried their suggestions, and tried following:
TryUpdateModel(articlecomment);
and also
TryUpdateModel<ArticleComment>(articlecomment);
and also
TryValidateModel(articlecomment);
but I was still getting same validation error for ArticleId, then I checked in Watch and all tree methods I tried are returning False.
I also tried following:
UpdateModel(articlecomment);
and
UpdateModel<ArticleComment>(articlecomment);
above methods are generating an exception :
The model of type 'Outliner.Models.ArticleComment' could not be
updated.
Here is my model:
[Table("ArticleComments")]
public class ArticleComment
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string ArticleId { get; set; }
public string UserId { get; set; }
[Required]
[Display(Name = "Comment")]
public string Comment { get; set; }
[Required]
[Display(Name = "Commented On")]
public DateTime CommentDate { get; set; }
}
I don't get it, why my model is not updating ... :(
It is quite late answer, but it should work.
Before ModelState.IsValid, add following
ModelState.Remove("ArticleId");
It will remove that field from validation.
You can try TryUpdateModel(articlecomment) once before checking ModelState.IsValid. However I have not tested it
After update any requerid field after the ModelBind you must call another method to update the validation.
You can use:
TryValidateModel(articlecomment);
or
TryUpdateModel<ArticleComment>(articlecomment);
To me it seems that your #Html.Action(...) code it invoking the action to create the partial view, like you said. If you are doing this it isn't the correct way to invoke a partial view. While it isn't uncommon for a action to return a partial view, it is normally via AJAX, in my experience, so you can just insert it into the DOM after it returns.
You can use the following method to render a partial view:
#{
Html.RenderPartial("_myPartialView",
new ArticleComment {ArticleId = model.Id});
}
This should render your partial view, pass your model to it so it can render properly. Then when the form is POST'ed to the server it should create the model from the form data. You shouldn't need the AID parameter as it is part of your ArticleComment model.
I can't seem to figure out how to send back the entire ViewModel to the controller to the 'Validate and Save' function.
Here is my controller:
[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel transaction)
{
}
Here is the form in the view:
<li class="check">
<h3>Transaction Id</h3>
<p>#Html.DisplayFor(m => m.Transaction.TransactionId)</p>
</li>
<li class="money">
<h3>Deposited Amount</h3>
<p>#Model.Transaction.Amount.ToString() BTC</p>
</li>
<li class="time">
<h3>Time</h3>
<p>#Model.Transaction.Time.ToString()</p>
</li>
#using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post, new { transaction = Model }))
{
#Html.HiddenFor(m => m.Token);
#Html.HiddenFor(m => m.Transaction.TransactionId);
#Html.TextBoxFor(m => m.WalletAddress, new { placeholder = "Wallet Address", maxlength = "34" })
<input type="submit" value="Send" />
#Html.ValidationMessage("walletAddress", new { #class = "validation" })
}
When i click on submit, the conroller contains the correct value of the walletAddress field but transaction.Transaction.Time, transaction.Transaction.Location, transaction.Transaction.TransactionId are empty.
Is there a way i could pass the entire Model back to the controller?
Edit:
When i dont even receive the walletAddress in the controller. Everything gets nulled!
When i remove this line alone: #Html.HiddenFor(m => m.Transaction.TransactionId);
it works and i get the Token property on the controller, but when i add it back, all the properties of the transaction object on the controller are NULL.
Here is the BitcoinTransactionViewModel:
public class BitcoinTransactionViewModel
{
public string Token { get; set; }
public string WalletAddress { get; set; }
public BitcoinTransaction Transaction { get; set; }
}
public class BitcoinTransaction
{
public int Id { get; set; }
public BitcoinTransactionStatusTypes Status { get; set; }
public int TransactionId { get; set; }
public decimal Amount { get; set; }
public DateTime Time { get; set; }
public string Location { get; set; }
}
Any ideas?
EDIT: I figured it out, its in the marked answer below...
OK, I've been working on something else and bumpend into the same issue all over again.
Only this time I figured out how to make it work!
Here's the answer for anyone who might be interested:
Apparently, there is a naming convention. Pay attention:
This doesn't work:
// Controller
[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel transaction)
{
}
// View
#using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post, new { transaction = Model }))
{
#Html.HiddenFor(m => m.Token);
#Html.HiddenFor(m => m.Transaction.TransactionId);
.
.
This works:
// Controller
[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel **RedeemTransaction**)
{
}
// View
#using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post, new { **RedeemTransaction** = Model }))
{
#Html.HiddenFor(m => m.Token);
#Html.HiddenFor(m => m.Transaction.TransactionId);
.
.
In other words - a naming convention error! There was a naming ambiguity between the Model.Transaction property and my transaction form field + controller parameter. Unvelievable.
If you're experiencing the same problems make sure that your controller parameter name is unique - try renaming it to MyTestParameter or something like this...
In addition, if you want to send form values to the controller, you'll need to include them as hidden fields, and you're good to go.
The signature of the Send method that the form is posting to has a parameter named transaction, which seems to be confusing the model binder. Change the name of the parameter to be something not matching the name of a property on your model:
[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel model)
{
}
Also, remove the htmlAttributes parameter from your BeginForm call, since that's not doing anything useful. It becomes:
#using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post))
Any data coming back from the client could have been tampered with, so you should only post back the unique ID of the transaction and then retrieve any additional information about it from your data source to perform further processing. You'll also want to verify here that the user posting the data has access to the specified transaction ID since that could've been tampered with as well.
This isn't MVC specific. The HTML form will only post values contained within form elements inside the form. Your example is neither inside the form or in a form element (such as hidden inputs). You have to do this since MVC doesn't rely on View State. Put hidden fields inside the form:
#Html.HiddenFor(x => x.Transaction.Time)
// etc...
Ask yourself though.. if the user isn't updating these values.. does your action method require them?
Model binding hydrates your view model in your controller action via posted form values. I don't see any form controls for your aforementioned variables, so nothing would get posted back. Can you see if you have any joy with this?
#using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post, new { transaction = Model }))
{
#Html.TextBoxFor(m => m.WalletAddress, new { placeholder = "Wallet Address", maxlength = "34" })
#Html.Hidden("Time", Model.Transaction.Time)
#Html.Hidden("Location", Model.Transaction.Location)
#Html.Hidden("TransactionId", Model.Transaction.TransactionId)
<input type="submit" value="Send" />
#Html.ValidationMessage("walletAddress", new { #class = "validation" })
}
Try to loop with the folowing statement not with FOREACH
<table>
#for (var i = 0; i < Model.itemlist.Count; i++)
{
<tr>
<td>
#Html.HiddenFor(x => x.itemlist[i].Id)
#Html.HiddenFor(x => x.itemlist[i].Name)
#Html.DisplayFor(x => x.itemlist[i].Name)
</td>
</tr>
}
</table>
Try Form Collections and get the value as. I think this may work.
public ActionResult Send(FormCollection frm)
{
var time = frm['Transaction.Time'];
}
Put all fields inside the form
#using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post))
and make sure that the model
BitcoinTransactionViewModel
included in view or not?
Can you just combine those 2 models you have? Here's how I do it with one model per view...
1. I use Display Templates from view to view so I can pass the whole model as well as leave data encrypted..
2. Setup your main view like this...
#model IEnumerable<LecExamRes.Models.SelectionModel.GroupModel>
<div id="container">
<div class="selectLabel">Select a Location:</div><br />
#foreach (var item in Model)
{
#Html.DisplayFor(model=>item)
}
</div>
3. Create a DisplayTemplates folder in shared. Create a view, naming it like your model your want to pass because a DisplayFor looks for the display template named after the model your using, I call mine GroupModel. Think of a display template as an object instance of your enumeration. Groupmodel Looks like this, I'm simply assigning a group to a button.
#model LecExamRes.Models.SelectionModel.GroupModel
#using LecExamRes.Helpers
#using (Html.BeginForm("Index", "Home", null, FormMethod.Post))
{
<div class="mlink">
#Html.AntiForgeryToken()
#Html.EncryptedHiddenFor(model => model.GroupKey)
#Html.EncryptedHiddenFor(model => model.GroupName)
<p>
<input type="submit" name="gbtn" class="groovybutton" value=" #Model.GroupKey ">
</p>
</div>
}
4. Here's the Controller.
*GET & POST *
public ActionResult Index()
{
// Create a new Patron object upon user's first visit to the page.
_patron = new Patron((WindowsIdentity)User.Identity);
Session["patron"] = _patron;
var lstGroups = new List<SelectionModel.GroupModel>();
var rMgr = new DataStoreManager.ResourceManager();
// GetResourceGroups will return an empty list if no resource groups where found.
var resGroups = rMgr.GetResourceGroups();
// Add the available resource groups to list.
foreach (var resource in resGroups)
{
var group = new SelectionModel.GroupModel();
rMgr.GetResourcesByGroup(resource.Key);
group.GroupName = resource.Value;
group.GroupKey = resource.Key;
lstGroups.Add(group);
}
return View(lstGroups);
}
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Index(SelectionModel.GroupModel item)
{
if (!ModelState.IsValid)
return View();
if (item.GroupKey != null && item.GroupName != null)
{
var rModel = new SelectionModel.ReserveModel
{
LocationKey = item.GroupKey,
Location = item.GroupName
};
Session["rModel"] = rModel;
}
//So now my date model will have Group info in session ready to use
return RedirectToAction("Date", "Home");
}
5. Now if I've got alot of Views with different models, I typically use a model related to the view and then a session obj that grabs data from each model so in the end I've got data to submit.
The action name to which the data will be posted should be same as the name of the action from which the data is being posted. The only difference should be that the second action where the data is bein posted should have [HttpPost] and the Posting method should serve only Get requests.