I'm trying to create a single view which allows the user to see the currently listed items using the index view model and then also allows the user to create a new item using a seperate create view model
So I've got two viewModels
-IndexFunkyThingsViewModel
-CreateFunkyThingViewModel
In essence I've got a main view:
#model IndexFunkyThingsViewModel
#foreach (var item in Model.FunkyThings)
{
/*Indexy stuff*/
}
/*If create item*/
#if (Model.CreateFunkyThing)
{
#Html.Partial("_CreateFunkyThingPartial", new CreateFunkyThingViewModel());
}
Then in my partial view I have
#model CreateFunkyThingViewModel
#using (Html.BeginForm(MVC.FunkyThings.CreateFunkyThing(Model)))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Create FunkyThing</legend>
#Html.EditorForModel();
<p>
<input type="submit" class="button green" value="CreateFunkyThing" />
</p>
</fieldset>
}
Finally in the controller I have:
[HttpPost]
public virtual ActionResult CreateFunkyThing(CreateFunkyThingViewModel createFunkyThingViewModel)
{
..
}
This all seems to compile happily and when I go to the view it works so far as displaying the create fields and such like. However when I then hit the submit button the controller receives no data. The ActionResult is called however in the debugger the createFunkyThingViewModel parameter is null when called by the submit button.
What am I doing wrong?
When posting to your controller, you're not sending the model down to it. Use this:
#using (Html.BeginForm("CreateFunkyThing", "ControllerName", FormMethod.Post))
then remove the p tags from around the button, and don't use anything with it.
The paragraph tags have a tendency to group the button separately from a form even if they are in the same outer container.
Related
I am trying to use a partial view that uses a different model than the one used in the main view. The partial view has
to show a list with the products recently added. But I am stuck on how and where to implement the logic for retrieving the data I need from the database.
Home/Index.cshtml:
#Html.Partial("~/Views/Shared/_LatestProducts.cshtml", new List<Website.Models.LatestProductsList>())
Shared/_LatestProducts.cshtml:
#model List<Website.Models.LatestProductsList>
#foreach (var item in Model)
{
<a href="#" title="img">
<img src="~/Content/images/latest-product-img.jpg" alt="" /><p>#item.ProductName</p>
</a>
}
And I have the following code that I am trying to use in order to get some products for tests and show them in the partial view:
public PartialViewResult _LatestProducts()
{
List<LatestProductsList> latestProd = (from p in db.Products
where p.ID < 5
select new LatestProductsList { ProductName = p.Title }).ToList();
return PartialView(latestProd);
}
I thought that I might use it in the HomeController, but that obviously doesn't work and I am not sure if partial views should have their own controller, if I can
just call it from another class. I am still wrapping my head around ASP MVC, so any help will be appreciate it.
Just call the action that renders the partial view in Index.cshtml.
#Html.Action("_LatestProducts", "Product")
Second parameter is the name of the controller that has the _LatestProducts method.
Just a reminder: Names with _ prefix is for partial views only, not action methods. You should rename it to LatestProducts.
I am inheriting a project which is somewhat built in Umbraco 6 and I am not familiar with Umbraco but learning thus far.
A partial view is using an existing template which effectively has this in its template:
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
Layout = "MvcBanner.cshtml";
}
#section ContentPlaceHolderParent {
#Umbraco.RenderMacro("Breadcrumb")
#Umbraco.Field("pageName")
#Umbraco.Field("pageInstructions", insertBefore: "", insertAfter: "", convertLineBreaks: true)
#Html.Action(#Umbraco.Field("MVCActionName").ToString(), #Umbraco.Field("MVControllerName").ToString())
}
This template is being used by a page "UploadJobs.cshtml"
Now, on the UploadJobs.cshtml I have a few fields bound to a model and then a file upload:
#model Models.JobsModel
#using(Html.BeginUmbracoForm("UploadJobs", "Jobs"))
{
#Html.TextBoxFor(m => m.Name);
#Html.TextBoxFor(m => m.Files, new { type = "file", name = "Files" })
<input type="submit" value="Upload" id="cmdSubmitJobs" />
}
My action method looks like this:
[HttpPost]
[ValidateAntiForgeryToken]
public PartialViewResult UploadJobs(UploadJobs model)
{ ... }
When submitting, everything seems fine but when returning the model back to the view (i.e validation fails), it seems to break the page completely when rendering (i.e all styles and all formatting is gone) and any javascript//jquery functions I have returns errors when the document is being rendered
thoughts? I want to be able to obviously return the model if it is invalid
Ahmed,
your problem is probably because of you are redirecting to the partialview not the view itself. Double check your flow, the partial page is most likely called from another view (parent one). This parent view contains all required styling stuff within it.
Im kinda new in MVC4 and im not able to figure it out.
"CustomViewMOdel" "CustomViewMOdel"
"ControllerX" ----------------> "VIEW" -----------------> "ControllerY"
My problem is that i want to pass my customviewmodel to view (which is working just fine!). In the View im showing some of model's fields to users (which is working fine also). BUT Now i want user, to change ONE field of the models fields and then PASS the WHOLE model to Controller X (with all fields filled, including the field what user was able to change AND other fields what were just shown)
Can anyone give a very simple code example of how to do this?
You can just create a form that posts to another controller:
ControllerX:
public ActionResult DoSomething()
{
return View(new CustomVM());
}
ViewA
#Model CustomViewModel
#using Html.BeginForm("DoSomethingElse", "ControllerY")
{
#Html.EditorFor(vm => vm.SomeProperty)
<input type="submit" value="OK" />
}
ControllerY
public ActionResult DoSomethingElse(CustomViewModel vm)
{
// do something else
}
You can use #Html.HiddenFor(o => o.Property) on the form.
This will not show a property on it.
But the advanced user may change the property through a development console. So you should check all the changes in the ControllerY
Example:
#Html.HiddenFor(o => o.Id)
#Html.HiddenFor(o => o.Name)
#Html.EditorFor(o => o.Description)
<input type="submit" value="OK" />
This will only let the user change a description but still have "id" and "name" on the FormCollection.
I use an ajax form for removing items from a list. The first time I submit something, it works but the second times, the reference of the item submitted is not correct: it is the first reference that is still used.
Here is my ajax form:
<div>
<table>
#foreach (var item in Model.ProjectTechnology)
{
<tr>
<td>#Html.DisplayFor(m => item.TechnologyID) </td>
<td>#using (Ajax.BeginForm("RemoveLinkedTechnology", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "AddedTechnologies" })) {
#Html.Hidden("projectID", item.ProjectID)
#Html.Hidden("removedTechnologyID", item.TechnologyID)
<input type="submit" value="Suppr" />
}</td>
</tr>
}
</table>
</div>
Here is the action in my controller:
[HttpPost]
public ActionResult RemoveLinkedTechnology(int projectID, string removedTechnologyID)
{
// some code here...
}
Example:
Lets say I proceed the submitting like this: first submit: AA; second submit: BB.
For the first call: removedTechnologyID contains AA.
For the second call: removedTechnologyID still contains AA.
Any idea?
Thanks
I suspect that in your controller action you are returning a partial view which updates the contents of the <table> you have shown. Now since Html helpers such as Hidden or TextBox first look for values in ModelState before binding and then in the model what happens is that #Html.Hidden("removedTechnologyID", item.TechnologyID) sees that there is a removedTechnologyID="AA" in the model state and completely ignores your model value which is item.TechnologyID. So if you have looked at the DOM after the first AJAX request you would have seen that all hidden fields have the old values inside them.
To fix this you have 3 possibilities:
Clear the item in model state in your controller action:
[HttpPost]
public ActionResult RemoveLinkedTechnology(int projectID, string removedTechnologyID)
{
...
ModelState.Remove("removedTechnologyID");
ModelState.Remove("projectID");
return View(...);
}
Don't use helpers to generate the hidden fields:
<input type="hidden" name="projectID" value="#item.ProjectID" />
<input type="hidden" name="removedTechnologyID" value="#item.TechnologyID" />
Write a custom Html.Hidden helper which will first use the values in the model before looking at modelstate (out of scope for this answer)
Suppose I have a simple search form with a textbox. And upon submitting the form I send the contents of the textbox to a stored procedure which returns to me the results. I want the results to be displayed on the same page the form was, except just below it.
Right now I'm doing the following but it's not working out exactly the way I want:
"Index" View of my SearchController
#using (Html.BeginForm("SearchResults", "Search", FormMethod.Post, new { #class = "searchform" }))`{
<fieldset>
<legend>Name</legend>
<div class="editor-label">
#Html.Label("Search")
</div>
<div class="editor-field">
#Html.TextBox("Name")
</div>
<input type="submit" value="Search" class="formbutton" />
</fieldset>
#{ Html.RenderPartial("SearchResults", null);
This is my "SearchResults" View:
#model IEnumerable<MyProject.Models.spSearchName_Result>
<table>
#foreach (var item in Model)
{
<tr>
<td>
#item.Name
</td>
</tr>
}
</table>
This is my Controller:
// GET: /Search/SearchResult
[HttpPost]
public ActionResult SearchResult(FormCollection collection)
{
var result = myentity.spSearchName(collection["Name"]);
return PartialView("SearchResults", result);
}
I can only seem to get the results to display on an entirely new page (not being embedded as a partial view), or I get an error when I load the search page because there are no results (since I hadn't searched yet).
Is there any better way to achieve what I'm trying to do? I feel like I'm going against some of the best practices in MVC.
You could return the results in a ViewData object then only show on the view it if is not null.
Very similar to this question MVC 3 form post and persisting model data
For this instance it looks like you are not passing the results to your partial view. Try this?
#{ Html.RenderPartial("SearchResults", Model.Results);
Since you are not persisting your search information using a model, the search information will be lost when the search form is posted.
Given your design and stated goal, it would be best to convert the form in your Index view into an Ajax form, then your controller can send your partial view back to populate a div below your Ajax form.
counsellorben