View not passing data to controller - asp.net-mvc

I've been looking on SO and google for over a week now and still was unable to find the working answer. Hopefully someone can help me.
Im working on a project with asp.net (Entity Framework + Razor) and I'm trying' to add two models to the views. It is showing perfectly, using editorFor(). Now the problem is some part is not passing the information to the controller.
In this case every exercise got some answers. This is my exercise model:
Table("Exercise")]
public class ExerciseModel
{
[Key]
public int ExerciseId { get; set; }
[Required]
public string Question { get; set; }
[Required]
public List<AnswerModel> Answers { get; set; }
And this the answermodel:
[Table("Answer")]
public class AnswerModel
{
[Key]
public int AnswerId { get; set; }
[Required]
public string Answer { get; set; }
}
The view exists out of two parts, the exercise part (the working one) and the answer part. I want to add more answers into a list in exercisemodel. I've tried different ways. Editor templates, partial views etc.
This is the view:
You can create a new question and add answers on the go using Jquery. What i want to create is that i can post answers into that list in exercisemodel.
#using (Html.BeginForm("CreateQuestion", "Admin", FormMethod.Post))
{
#Html.ValidationSummary(true)
//will be changed
#Html.Partial("_PartialCreateExercise")
//this shows the answers form
<div style="display: none;" id="new">
<div class="editor-field">
#Html.EditorFor(m => m.Answers);
</div>
</div>
<p>
<input name="command" type="button" id="add" value="add new answers" />
</p>
<p>
<input name="command" type="submit" value="Create" />
</p>
}
This works, but when i submit the page the List in exercisemodel (of type AnswerModel) remains empty. And finally the editor template for answers:
#model Academy.Models.AnswerModel
#{
Layout = null;
}
<h2>Answer</h2>
<p>
#Html.LabelFor(model => model.Answer)
#Html.EditorFor(model => model.Answer)
</p>
The jQuery:
$(document).ready(function () {
$("#add").click(function () {
$('#add').after($("#new").html());
$('#new').css("Display", "block");
});
});
It doesn't do much and tried alot in there, so it's becoming messy. But when using the debug mode the List in ExerciseModel is empty and also the AnswerModel.
So again, the problem is that when posting the form, the List in ExerciseModel remains empty. I can't reach the List in exercisemodel for some reason through editor template. (controller not included because it doesn't do a lot right now and the List is always empty)
This has been keeping me busy for a week now, hopefully someone can help me?

I suspect that the culprit lies in your jQuery code, the one that's supposed to dynamically add new answers. You haven't shown it so it is hard to tell what might be wrong with it.
What you should be careful with is the naming convention of the input fields. Phil Haack illustrated in his blog post this convention.
Basically there are 2 approaches to dynamically adding a new element (when #btnadd is clicked):
Send an AJAX call to a controller action that will return a partial view containing en empty template. The naming convention should once again be respected. The difficulty here comes with the index. Since the naming convention allows you to use non-sequential indexes (read Phil Haack blog post once again) the easiest here would be to use Guids as indexes. Steven Sanderson illustrated this concept in his blog post and even showed a custom Html.BeginCollectionItem helper which does exactly that.
Do it purely on the client side. For example you could use a framework such as knockoutjs. Once again Steven Sanderson illustrated this concept in his blog post.
So So basically it's up to you to choose the approach you prefer. But no matter which approach you choose when the form is submitted if you haven't respected the nameing convention of your Answers input fields all you will get in your controller action is null.

Related

Code regarding EditorTemplates usage ASP.Net MVC

i was reading a post on EditorTemplates
from this url http://stackoverflow.com/questions/4872192/checkboxlist-in-mvc3-0
after seeing their code i just do not understand area like how it would work
view model:
public class MyViewModel
{
public int Id { get; set; }
public bool IsChecked { get; set; }
}
A controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new[]
{
new MyViewModel { Id = 1, IsChecked = false },
new MyViewModel { Id = 2, IsChecked = true },
new MyViewModel { Id = 3, IsChecked = false },
};
return View(model);
}
[HttpPost]
public ActionResult Index(IEnumerable<MyViewModel> model)
{
// TODO: Handle the user selection here
...
}
}
A View
(
~/Views/Home/Index.cshtml
):
#model IEnumerable<AppName.Models.MyViewModel>
#{
ViewBag.Title = "Home Page";
}
#using (Html.BeginForm())
{
#Html.EditorForModel()
<input type="submit" value="OK" />
}
and the corresponding Editor template
(
~/Views/Home/EditorTemplates/MyViewModel.cshtml
):
#model AppName.Models.MyViewModel
#Html.HiddenFor(x => x.Id)
#Html.CheckBoxFor(x => x.IsChecked)
see this code
#using (Html.BeginForm())
{
#Html.EditorForModel()
<input type="submit" value="OK" />
}
1) what this line will do
#Html.EditorForModel() ?
2) if this line would load a view called
MyViewModel from this location
/Views/Home/EditorTemplates/MyViewModel.cshtml
3) then how mvc engine would understand that it has to load view called
MyViewModel from this location /Views/Home/EditorTemplates/
4) i saw people always create
EditorTemplates
folder in shared view but in this case it is created in home folder.....why ?
5) if there are so many other view in this location then how this line
#Html.EditorForModel()
would load this specific view
MyViewModel.cshtml
from this location
/Views/Home/EditorTemplates.
i am new in mvc and learning. so please help me to understand how the above code will work?
also please answer my 5 questions. thanks
Before answer to your specific question, you have to know that asp .net mvc relay heavily on Convention over Configuration.
1) what this line will do
#Html.EditorForModel() ?
It just tell the view to render the model pass in as a whole thing to the EditorFor.
2) if this line would load a view called
MyViewModel from this location
/Views/Home/EditorTemplates/MyViewModel.cshtml 3) then how mvc engine
would understand that it has to load view called
MyViewModel from this location /Views/Home/EditorTemplates/
Mvc knows it by convention. It will look into Views for a template same name to the viewModel type(in this case MyViewModel )
the pattern mvc look at is:
Views{Controller}\EditorTemplates\MyViewModel.cshtml
Views\Shared\EditorTemplates\MyViewModel.cshtml
And if it find it, it will stop looking. Hence the view in Controller will be used even if there is one in the shared.
4) i saw people always create
EditorTemplates folder in shared view but in this case it is created
in home folder.....why ?
If it is in Shared, that means any other controller with same ViweModel type name MyViewModel can use that same view. If it is in home, that means it is only available to "Home" controller specific.
5) if there are so many other view in this location then how this line
#Html.EditorForModel() would load this specific view
MyViewModel.cshtml from this location
/Views/Home/EditorTemplates. i am new in mvc and learning. so please
help me to understand how the above code will work?
That is the convention, as I answered above, there is certain pattern which mvc looks view in, the first match get applied.
Edit
Thank Stephen Muecke for pointing out, I was typing too fast.
The search Pattern for view is:
Views{Controller}\EditorTemplates\MyViewModel.cshtml
Views\Shared\EditorTemplates\MyViewModel.cshtml
So if it find it, it will stop looking. This means if it found in the current controller (in your example is Home), then it stop looking. It only continue to look when it can not find it in the controller specific folder.
Edit 2 - include some reason to use Editor template
the reason for writting editor/display template is for code reuse.
Consider using jquery datepicker on a datetime property.
If you don't use Editor template, then you are going to duplicate code in the view to use jquery datepicker.
If you use editor template, then if some day you want to change jquery datepicker to some other plugin, you only change in the editor template, and no where else. Hence Don't Repate Yourself (DRY) principal.
This also keep same consistency of ui across multiple page when showing same type of input.
The example I gave above is on one property, but if a template is for whole model, that is where EditorForModel comes in, but same idea.
Consider this article on some usage of template
https://www.simple-talk.com/dotnet/asp.net/extending-editor-templates-for-asp.net-mvc/
And below is a more depth detail on template written for asp .net mvc 2. But same thing apply to mvc 4 and 5
http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html

ASP.NET MVC Binding to View Model as well as routed values

I know similar questions have been asked regarding complex model binding in ASP.NET MVC, but I am having a problem binding because of a lack of a sufficient prefix coming back on the POST and wondered if there were an easy solution.
I have a view Model that looks something like this:
public class ViewModel<Survey, Contact>
{
public Survey Model { get; set; }
public Contact Model2 { get; set; }
}
I then have an action method like this that accepts the POSTed
public ActionResult Survey(
string id, string id2, SurveyViewModel<Survey, Contact> model)
{
// code goes here...
}
In my form, the first two id's are from the URL route and I then have form code (using #Html.EditorFor(x => x.Model.SurveyName) or similar), generated with names like this:
<input class="text-box single-line" id="Model_Email"
name="Model.Email" type="text" value="" />
A post works if I change the name from Model.Email to model.Model.Email, but I am trying to avoid having to create a custom model binder.
Is there
A setting I can make in the view to change the name for all fields rendered in a view using the #Html.EditorFor typed view helpers?
Something I can change using the Bind attribute on the action that would allow it to default binding to that object?
The answer may be "build a custom binder", but I just wanted to pose the question before biting that off.
Thanks for the help. Best Regards,
Hal
You can pass custom viewdata with custom HtmlFieldPrefix to view. Every control rendered with helper will have that prefix.
ViewData.TemplateInfo.HtmlFieldPrefix = "prefix here";
Take a look at this: Forcing EditorFor to prefix input items on view with Class Name?

Upload and store many images a to database and create thumbnails at once using ASP.Net MVC

How can I upload many images at once (by open dialog and shift/ctrl) and store them to sql server database (create a record for each image) and then create thumbnails with ASP.Net MVC ?
How view and controller should be?? Thanks alot.
It seems from your question that you are going way over your head. You are asking questions about ASP.NET MVC, image treatment algorithms, SQL server and general web design all at once.
To avoid going into the nitty gritty of your question I'll simply explain what you need to do. You are going to need to do the research for this yourself because no amount of S.O. questions and answers will give you the appropriate technical knowhow.
You first need to have a database which can store images. Here is a little tutorial http://www.codeproject.com/Articles/354639/Storing-and-Retrieving-Images-from-SQL-Server-Usin.
That will probably take you a while. But once you are done that you will need to get into your project and start working on the basic architecture. What are your objects going to look like? What will the flow of your program be? One big question you will need to ask is how are you going to connect to your database? The answer should probably be Entity Framework. You need to look into using EF to transfer data from your server side code to your DB.
As far as your views and your controllers, controllers are where all the calculating and processing happens in your application, and views are almost like templates which display calculated data. You need to work out what data you want to pass back and forth. Generally speaking given the small amount of information that you have provided, the view will look like pretty much whatever you want it to look like, and the controller will have to take the image passed from the view, turn it into a thumbnail and then pass it (with EF) back to your database.
A lot of work, eh? ;)
You have to create 2 Classes: MainClass and MainClassViewModel
The main class has the property of images with a tagname, like:
public class MainClass
{
[Key]
public int MainClassId {get; set;}
[DisplayName("Image 1")]
public Bytes[] Image1 {get;set;}
}
Then you will need a ModelView (it's a class way to similar to the original just will have to change the type of "Bytes[]" to "HttpPostedFileBase":
public class MainClassModelView
{
[Key]
public int MainClassId {get; set;}
[DisplayName("Image 1")]
public HttpPostedFileBase Image1 {get;set;}
}
and in your view you have to use this ModelView, in the 1st line:
#model ApplicationName.Models.MainClassModelView
Then you have to use the view:
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MainClassView</h4>
<hr />
#Html.Images(m => m.Image1)
#Html.ValidationMessageFor(model => model.Image1, "", 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-default" />
</div>
</div>
</div>
}

Model with List - approaches to add new item to the list from a Razor view

I have a model with various properties but the one of interest is a List of another type of Model.
For example:
public class User
{
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<UserInterest> Interests { get; set; }
}
I then use an Editor Template within my view to render out a view for each item of the model items.
#Html.EditorFor(x => x.Interests)
The EditorFor template looks something like:
#model Interest
<div>
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x => x.InterestText)
#Html.CheckBoxFor(x => x.Delete)
....
</div>
Something very similar to the accepted answer here: Model Containing List of Models (MVC-3, Razor)
My question is - how would you from the client-side (jQuery) create a new item within the property without going back to the server. I currently have a rough way of doing it whereby I post the data back to my controller which returns the model back with a new blank item within the Interests property.
This seems to be overkill making a HTTP request and not very elegent. I was thinking of using jQuery .Clone() but not entirely sure on what I'd need to do in terms of naming the elements and clearing existing values.
So does anybody have any suggestions. I'm hoping to get more opinions and different approaches.
You can simply create the Textbox and checkbox on the fly and add that to the DOM. When saving it, Use jQuery ajax to post that data ( new record data) to an action method and save it there. Return a status back (Succcess /Falied) from your action method to your client side code ( your callback function of jQuery ajax/post) and check it there. If it is success, Show a success message to the user and append the new item to the existing list.
Sample jSFiddle : http://jsfiddle.net/carwB/2/
If you want to return some complex data ( ex : All new records with its id etc..) along with the status, you may return JSON from your action method.
EDIT : To keep your Model binding works with the newly added dynamic elements, you need to follow the naming convention of the elements.
The trick is to keep the id property value of the html element in this format.
CollectionName_ItemIndex__PropertyName
and name property value in this format
CollectionName[ItemIndex].PropertyName
I created a sample working program and explained it how it works Here based on your requirements.
In such situations I prefer to use client templating. You send data to server with ajax and then receive JsonResult. Look at JsRender this is javascript lib without jQuery dependency.
1.Create two partial view one is for list item and second one is creation
2.First partail view should be inside the div which has id 'divMdeolList'
3.and Creation view will have the code like that
#using (Ajax.BeginForm("SubmitData", new AjaxOptions { UpdateTargetId = "divMdeolList" }))
{
#Html.TextBoxFor(x => x.InterestText)
<p>
<input type="submit" value="Create" />
</p>
}
4. And then create a ActionResult type action on controller that will render the partialview
public ActionResult SubmitData(YourModel model)
{
//Do : save the record
return PartialView("FirstPartailView", model);
}
This will update the View without postback

MVC: Binding dynamic select list back to ViewModel on Post

I have a MVC 3 project, and is stuck on the binding of the view back to the model on Post.
Here is my Model:
public class DBViewModel
{
public ProductionDatabasesViewModel PDBViewModel { get; set; }
public IList<string> SelectedNames { get; set; }
public DBViewModel()
{
SelectedNames = new List<string>();
PDBViewModel = new ProductionDatabasesViewModel();
}
}
My view: (cut down version)
#model Web.Models.DBViewModel
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
#Html.ListBoxFor(x => x.SelectedNames, new SelectList(Model.SelectedNames))
<input id="button-submit" name="SubmitButton" type="submit" value="Submit" />
</fieldset>
}
Snippet of the Controller:
[HttpPost]
public ActionResult Database(DBViewModel model)
{
var users = model.SelectedNames; //<---- empty, the count is 0 always.
}
In the view there is the ability to select users from a autocomplete box and then jQuery script that will add the selected names to the list in the view above. This all works, so I can search for the users, and then click the add button to add the users to the list. But I run into problems when clicking the Submit button. The users that were added in the view (selectlist in the view), is not bound to the Model. So on post the model.SelectedNames is empty. I have also tried Request["SelectedNames"] and Request.Form["SelectedNames"] and they are all null.
I am very experienced in normal webforms, but still learning MVC, so any help would be much appreciated.
[UPDATE]
I will update the question further tomorrow my time, but it appears that the items that is in the list will be bound to the viewmodel if I select them. I will figure this out tomorrow. But thanks a lot so far for all the comments, help and suggestions.
Does this Does the Model Binder in ASP.NET MVC Beta Support List<T>? answer your question? The string list is a simpler version.
Have to say this cut off version of your code works as it should. SelectedNames list is successfully filled from listbox after submit. You can check it yourself. Though I have made several changes:
removed all references to ProductionDatabasesViewModel;
changed return type of POST version of Database method to void;
added GET version of Database method
:
public ActionResult Database()
{
return View(new DBViewModel { SelectedNames = { "a", "b", "c" } });
}
So I believe you have a bug somethere else, not in these parts.
Ok, I have found what the issue is. When you have a multi select element in your html that you want to bind the values in the box back to the model, you have to select the items first. Very annoying, but that's the way it seems to want it.
So if you have a select box like:
<select id="selected-ad-users-list" name="SelectedNames" multiple="multiple" size="5"
style="width: 100%">
</select>
And you add items to it, from anywhere really, in my case I had another list/or textbox where they typed a name in, and then I used jQuery to populate this select list. What I needed to do was to add a bit of jQuery script to spin through my list and select all items. So once the items are selected, it will bind them to the model.
Here is a good article on this: select all or some items in a select box
I really hope this helps someone.

Resources