Passing hidden object from view to controller - c#

I have a controller sending a view model consisting of a list and an object client to a view.
The view will show the list in a grid but hide the object client.
Here is the view:
#model .Business.BusinessModels.MatchesClientViewModel
#{
ViewBag.Title = "SaveClient";
}
<h2>SaveClient</h2>
<h3>
The info captured matches #Model.ClientMatches.Count()
</h3>
#using (Html.BeginForm("SaveClient", "Client", FormMethod.Post))
{
#Html.AntiForgeryToken()
WebGrid grid = new WebGrid(Model.ClientMatches);
#grid.GetHtml(columns: new[]
{
grid.Column("Name"),
grid.Column("Surname"),
grid.Column("Email"),
})
#Html.Hidden("client", Model.client)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
My action which submit button hits is:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SaveClient(MatchesClientViewModel matchesClientViewModel)
{
*some actions*
return View();
}
However the view model sent to controller from view is null. Any idea how to properly pass the hidden part of the view model to the controller?

If you want to pass an entire object as hidden you will have to add hidden fields for every attribute of the class like this:
Let's say the model Client is something like this
public class Client
{
public string Id { get; set; }
public string SomeAttribute { get; set; }
\\ ......
}
In order to pass your values to your Action you should add to your form every property as a hidden field like this
#Html.HiddenFor(m => m.client.Id, Model.client.Id)
#Html.HiddenFor(m => m.client.Someattribute, Model.client.Someattribute)
One other way to go would be to change your model to something like this:
public class MatchesClientViewModel
{
public List<ClientMatch> ClientMatches { get; set; }
public string clientId { get; set; }
\\ .....
}
and pass your clientId only to your view and back to the controller like this
#Html.HiddenFor(m => m.clientId., Model.clientId)
Or If you do not want to change your ViewModel just add a hidden field like you did for your object for the client id and pass it as an extra parameter to the controller
#Html.HiddenFor('clientId', Model.client.Id)
and make your action like this
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SaveClient(MatchesClientViewModel matchesClientViewModel, string clientId)
{
*some actions*
return View();
}

Related

How can I pass hidden field value from view to controller ASP.NET MVC 5?

I am trying to pass hidden field value from view to controller by doing the following
#Html.HiddenFor(model => model.Articles.ArticleId)
and also tried
<input type="hidden" id="ArticleId" name="ArticleId" value="#Model.Articles.ArticleId" />
On both instances the value of ArticleId is 0 but when i use TextboxFor i can see the correct ArticleId, please help
Here it is
View
#model ArticlesCommentsViewModel
....
#using (Html.BeginForm("Create", "Comments", FormMethod.Post))
{
<div class="row">
<div class="col-xs-10 col-md-10 col-sm-10">
<div class="form-group">
#Html.LabelFor(model => model.Comments.Comment, new { #class = "control-label" })
#Html.TextAreaFor(m => m.Comments.Comment, new { #class = "ckeditor" })
#Html.ValidationMessageFor(m => m.Comments.Comment, null, new { #class = "text-danger"})
</div>
</div>
</div>
<div class="row">
#*#Html.HiddenFor(model => model.Articles.ArticleId)*#
<input type="hidden" id="ArticleId" name="ArticleId" value="#Model.Articles.ArticleId" />
</div>
<div class="row">
<div class="col-xs-4 col-md-4 col-sm-4">
<div class="form-group">
<input type="submit" value="Post Comment" class="btn btn-primary" />
</div>
</div>
</div>
}
Controller
// POST: Comments/Create
[HttpPost]
public ActionResult Create(CommentsViewModel comments)//, int ArticleId)
{
var comment = new Comments
{
Comment = Server.HtmlEncode(comments.Comment),
ArticleId = comments.ArticleId,
CommentByUserId = User.Identity.GetUserId()
};
}
Model
public class CommentsViewModel
{
[Required(ErrorMessage = "Comment is required")]
[DataType(DataType.MultilineText)]
[Display(Name = "Comment")]
[AllowHtml]
public string Comment { get; set; }
public int ArticleId { get; set; }
}
ViewModel
public class ArticlesCommentsViewModel
{
public Articles Articles { get; set; }
public CommentsViewModel Comments { get; set; }
}
The model in the view is ArticlesCommentsViewModel so therefore the parameter in your POST method must match. Your use of
#Html.HiddenFor(model => model.Articles.ArticleId)
is correct, but you need to change the method to
[HttpPost]
public ActionResult Create(ArticlesCommentsViewModel model)
and the model will be correctly bound.
As a side note, your ArticlesCommentsViewModel should not contain data models, and instead should contain only those properties you need in the view. If typeof Articles contains properties with validation attributes, ModelState would be invalid because your not posting all properties of Article.
However, since CommentsViewModel already contains a property for ArticleId, then you could just use
#Html.HiddenFor(model => model.Comments.ArticleId)
and in the POST method
[HttpPost]
public ActionResult Create([Bind(Prefix="Comments")]CommentsViewModel model)
to effectively strip the "Comments" prefix
In your controller, you need to pass the hidden value with the model,
for example, if you have a userId as a hidden value, in your Page you add:
#Html.HiddenFor(x => x.UserId)
In your model of course you would already have UserId as well.
In your controller, you need the model as a parameter.
public async Task<ActionResult> ControllerMethod(YourViewmodel model) { model.UserId //this should be your HiddenValue
I guess your model have another class called Articles inside CommentsViewModel.Change your controller function for accessing the ArticleId accordingly.
[HttpPost]
public ActionResult Create(CommentsViewModel comments)//, int ArticleId)
{
var comment = new Comments
{
Comment = Server.HtmlEncode(comments.Comment),
ArticleId = comments.Articles.ArticleId, // Since you are using model.Articles.ArticleId in view
CommentByUserId = User.Identity.GetUserId()
};
}
In my case, I didn't put the hidden input in the form section, but out of form, so it's not send to backend. Make sure put hidden input inside the form.
Also make sure name attribute is specified on the hidden field. Element's "id" is often used on client side but "name" on server side.
<input type="hidden" value="#ViewBag.selectedTraining" id="selectedTraining"
name="selectedTraining" />
In my case, I was passing a couple of fields back and forth between controllers and views. So I made use of hidden fields in the views.
Here's part of the view. Note a controller had set "selectedTraining" and "selectedTrainingType" in the ViewBag to pass to the view. So I want these values available to pass on to a controller. On the hidden tag, the critical thing is set to the "name" attribute. "id" won't do it for you.
#using (Html.BeginForm("Index", "ComplianceDashboard"))
{
<input type="hidden" value="#ViewBag.selectedTraining" id="selectedTraining" name="selectedTraining" />
<input type="hidden" value="#ViewBag.selectedTrainingType" id="selectedTrainingType" name="selectedTrainingType" />
if (System.Web.HttpContext.Current.Session["Dashboard"] != null)
{
// Show Export to Excel button only if there are search results
<input type="submit" id="toexcel" name="btnExcel" value="Export To Excel" class="fright" />
}
<div id="mainDiv" class="table">
#Html.Grid(Model).Columns(columns =>
Then back on the controller:
// POST: Dashboard (Index)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(string excel)
{
string selectedTraining, selectedTrainingType;
selectedTraining = Request["selectedTraining"];
selectedTrainingType = Request["selectedTrainingType"];
Or can put the requests as parameters to the method: public ActionResult Index(string excel, string selectedTraining, string selectedTrainingType)

Edit and update rows in dynamic table in Asp.net mvc4 razor view

I am new to asp.net MVC. I have a dynamic table in my project. Adding dynamic rows in table is achieved with the help of following link
Adding and deleting rows in dynamic table in Asp.net mvc razor view
I need to edit and update the dynamic table.
I have tried following code
My sample model
public class Gift
{
public string Name { get; set; }
public double Price { get; set; }
}
public class GiftViewModel
{
public string Age { get; set; }
public DateTime TheDate { get; set; }
public IEnumerable<Gift> Gifts { get; set; }
}
My sample Controller
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(GiftViewModel model)
{
// do work here
return RedirectToAction("Index");
}
public ViewResult AddNew()
{
return View("_TimeSheetView");
}
}
My sample Partial View
#model HelloWorldMvcApp.Gift
#using (Html.BeginCollectionItem("giftList"))
{
<div>
<span class="drop_medium">
#Html.TextBoxFor(m => m.Name)
</span>
<span class = "drop_medium">
#Html.TextBoxFor(m => m.Price)
</span>
</div>
}
My sample main view
#model HelloWorldMvcApp.GiftViewModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.Age)
#foreach (var data in Model.Gifts)
{
{ Html.RenderPartial("_TimeSheetView", data); }
}
#Html.ActionLink("Add another", "AddNew", null, new { id="addItem" })
<input type="submit" value="Save"/>
}
<script type="text/javascript">
$("#addItem").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) { $("#dynamic").append(html); }
});
return false;
});
</script>
When I click 'Add Another' button a row is added to the table. After editing the values in the table When I click submit button I receive nothing in the controller. The IEnumerable Gifts variable is null. How to take the table values to the controller. Please help me to fix this is issue. Thanks in advance
Your model's collection property is named Gifts so the partial needs to be
#model HelloWorldMvcApp.Gift
#using (Html.BeginCollectionItem("Gifts")) // not "giftlist"
{
...
}
This will generate inputs with the correct name attributes for binding to a collection (where ## is a Guid)
<input name="Gifts[##].Name" ... />
<input name="Gifts[##].Price" ... />
<input type="hidden" name="Gifts.Index" value="##" />
The problem you're facing is the name of the rendered input isnt matching your model structure. There are a couple of ways out of this:
Make an editor template for the model type
your partial view:
#model IEnumerable<HelloWorldMvcApp.Gift>
#Html.EditorForModel("","Gifts")
and an EditorTemplate for the Gift model:
#model HelloWorldMvcApp.Gift
<div>
<span class="drop_medium">
#Html.TextBoxFor(m => m.Name)
</span>
<span class = "drop_medium">
#Html.TextBoxFor(m => m.Price)
</span>
</div>
Manually create the inputs with the properly parsed name - "Gifts[x].Property"
Obviously the first option is far cleaner and imho preferred.
Hope this works, and helps :)

model returned to view has no effect on field

My Model;
namespace GeneralUtility.Models
{
public class MyModel
{
public int BirthDateYear { get; set; }
public String Details { get; set; }
}
}
My Controller
namespace GeneralUtility.Controllers
{
public class WorkspaceController : Controller
{
public ActionResult MyHelper(MyModel model)
{
if(model.someCondition)
model.Details= "TEST";
else
model.Details= "Some other TEST";
return View(model);
}
}
}
My View
<div data-role="fieldcontain">
#using (Html.BeginForm("MyHelper", "WorkSpace", FormMethod.Post, new { id = "frmMyForm" }))
{
...
<div data-role="fieldcontain">
#Html.EditorFor(x => x.Details )
</div>
...
}
</div>
After I submit my form, I can see the model and any changes I make in MyHelper action method. However, when I make changes and return the model from the controller (I can see the changes in the model while in debug). I get the same value as before in #Html.EditorFor(x => x.Details ) field. What can I do to get the changed Details value of the model to show?
That's because by default ASP.NET MVC returns the model that was passed into a method (using what is stored in the ModelState, if it exists). If it doesn't exist, it uses what you pass to the View.
In order to prevent this, you need to call ModelState.Clear() before returning your view.
Check this blog post for a more detailed explanation.

Displaying Partial View in a View and Passing Arguments

I'm trying to display two partial views in my index view. In those partial views are data grids that I want to display data when something is searched in the search box I have set up. Both of these pages work when I do them separately, but I don't know how do use them as partial views.
My View looks like this:
#using (Html.BeginForm("Index", "Home", "POST"))
{
<div class="searchField">
<div class="searchbox">
Search: <input type="text" name="heatSearch" />
<input type="submit" value="Submit">
</div>
</div>
}
<div>
#Html.Partial("PartialChemAnalysis", (string)ViewBag.SearchKey)
</div>
#Html.Partial("PartialSlag", (string)ViewBag.SearchKey)
My Controller looks like this:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string heatSearch)
{
ViewBag.SearchKey = heatSearch;
return View();
}
public ActionResult PartialChemAnalysis(string heatSearch)
{
HomeModel C = new HomeModel();
IEnumerable<HomeModel> model = C.ChemList;
C.ChemistryDataPull(heatSearch);
return PartialView(C.ChemList);
}
public ActionResult PartialSlagView(string heatSearch)
{
PartialSlagViewModel D = new PartialSlagViewModel();
IEnumerable<PartialSlagViewModel> model = D.SlagList;
D.SlagViewDataPull(heatSearch);
return PartialView(D.SlagList);
}
Ideally what's in that search box would be passed to both views and the grids would form based on that. I'm not sure what I'm doing wrong so any help is appreciated.
I would start with this:
#{
//create your first model
HomeModel CModel = new HomeModel();
CModel.ChemistryDataPull(Model.SearchValue);
//create your other model
PartialSlagViewModel DModel = new PartialSlagViewModel();
DModel.SlagViewDataPull(Model.SearchValue);
}
#Html.Partial("PartialAnalysis", CModel)
#Html.Partial("PartialSlag", DModel)
This is assuming you've already searched, processed a postback, and you've returned the SearchValue back to your view in your model. You could return it in ViewBag.SearchValue instead I suppose and replace Model.SearchValue with ViewBag.SearchValue, but your model would be a better place to store it.
If I were you, I post it to another method.
#using (Html.BeginForm("Index", "Home", "POST"))
{
<div class="searchField">
<div class="searchbox">
Search: <input type="text" name="Search" />
<input type="submit" value="Submit">
</div>
</div>
}
#Html.Partial("PartialAnalysis", (string)ViewBag.SearchKey)
#Html.Partial("PartialSlag", (string)ViewBag.SearchKey)
//In Home Controller
[HttpPost]
public ActionResult Index(string Search)
{
ViewBag.SearchKey = Search;
return View();
}
Partial views do not require a controller action. The presence of a controller action will actually make it into a view.
In your #Html.Partial call you want to pass a view model for the view to consume. This is where you'd want to put the data for your grid, searched by whatever keywords, sorted, prepped and ready to render.
This can either be an entirely different view model you've created that is dedicated to supporting your partial view, exposed as a property in the parent page's view model, or simply an IEnumerable property in the parent page's view model that has the data (I prefer the first approach btw; it's heavier code-wise but preserves encapsulation better).
To wrap it all up, your controller looks like:
public class HomeController : Controller
{
public ActionResult Index(string search)
{
return View(new IndexViewModel(search));
}
}
Your view model looks like:
public class IndexViewModel
{
private string _search;
public IndexViewModel(string search)
{
_search = search;
}
public AnalysisViewModel AnalysisViewModel
{
get
{
return new AnalysisViewModel(_search);
}
}
public SlagViewModel SlagViewModel
{
get
{
return new SlagViewModel(_search);
}
}
}
and your view for showing the partials looks like
#Html.Partial("PartialAnalysis", Model.AnalysisViewModel)
#Html.Partial("PartialSlag", Model.SlagViewModel)
I needed to change my partial view calls in my view to:
#if(ViewBag.SearchKey != null)
{
<div>
#Html.Action("PartialChemAnalysis", "Home", (string)ViewBag.SearchKey)
</div>
<div>
#Html.Action("PartialSlagView", "Home", (string)ViewBag.SearchKey)
</div>
}

ASP.NET MVC form element name generation

I have a class that looks like this:
public class UserListVM
{
public SearchModel SearchModel { get; set; }
public PagedList<User> Users { get; set; }
}
public class SearchModel
{
public string Text { get; set; }
/* other properties */
}
I send UserListVM to my view but the action accepts SearchModel:
public ActionResult Search(SearchModel filter)
{
UserListVM model = new UserListVM();
model.Users = userService.GetUsers(filter);
model.SearchModel = filter;
return View(model);
}
My view is:
#model UserListVM
<form>
#Html.TextBoxFor(m => Model.SearchModel.Text)
</form>
But this generates:
<input id="SearchModel_Text" name="SearchModel.Text" type="text" value="">
Which sends UserListVM to the action instead of SearchModel. How can I get it to generate this:
<input id="Text" name="Text" type="text" value="">
#Html.TextBoxFor(m => m.SearchModel.Text, new { id = "Text" })
Utilize the overloaded TextBoxFor() method that takes a second object parameter (called htmlAttributes). Here you can specify HTML attributes to apply to the DOM element you are currently utilizing (in this case, your input element).
Edit: I believe your lambda expression is wrong. Change:
#Html.TextBoxFor(m => Model.SearchModel.Text)
To
#Html.TextBoxFor(m => m.SearchModel.Text)
// htmlAttributes omitted to show the issue
Edit Edit: it turns out that even with a specified name attribute, it will be rendered according to what the form is requiring for a POST to the necessary field(s).
Edit Edit Edit: Try to be explicit with FormExtensions.BeginForm():
#using (Html.BeginForm("Search", "YourController", FormMethod.Post, null))
{
#Html.TextBoxFor(m => m.SearchModel.Text)
}
Use this as a substite of your <form /> element.
Create a partial view for your SearchModel, and call it using Html.Partial. Then, from within that partial view, do all of the EditorFor/TextBoxFor Extensions
Your view - UserList.cshtml:
#model UserListVM
#using (Html.BeginForm())
{
#Html.Partial("Search", Model.SearchModel)
}
Your view - Search.cshtml:
#model SearchModel
#Html.TextAreaFor(m => m.Text)
Assumming there is more the the View than you have shown, why not just have your Search method take the UserListVM model. It will just contain a null reference to the users, so there is no extra data sent in the post.
Try doing it manually like this:
#Html.TextBox("Text", Model.SearchModel.Text)

Categories

Resources