So I'm pretty new in MVC, I got Mission model:
public class Mission
{
public ObjectId _id { get; set; }
public string MissionType { get; set; }
public string ElipseNumber { get; set; }
public string MissionDate { get; set; }
public string ReminderNumber { get; set; }
public string Notes { get; set; }
}
When the user is selecting a specific mission, it goes to the view as #ViewBag.SelectedMission
Now, I want to let the user have the option to add a note to a selected mission, so using a modal I added a textbox like so:
<div class="notesLabel">
#Html.LabelFor(model => model.Notes)
</div>
<div class="notesTextBox">
#Html.TextBoxFor(model => model.Notes)
</div>
Not sure exactly what to do, How do I take the input from the textbox and adding it to the SelectedMission.Notes?
Thanks from advance.
I am also a beginner but trying to help. From what I understand you can do something like below
Contoller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Mission model)
{
var notes= model.Notes;
//Set the values to view model accordingly and save to DB eventually
}
View
#model Mission
#using (Html.BeginForm("Create", "ControllerName"))
{
#Html.AntiForgeryToken()
// ALL YOUR HTML FIELD WILL COME HERE
<div class="notesLabel">
#Html.LabelFor(model => model.Notes)
</div>
<div class="notesTextBox">
#Html.TextBoxFor(model => model.Notes)
</div>
<input type="submit" value="save">
}
Try below code. The form will submit the details entered by user on button click. Assumption: the Controller name is Home and Action name which saves the notes data is SaveNotes. When user clicks the submit button, the data is sent to the SaveNotes action in HomeController. In action function, after validation is done, values are saved into to DB. If you don't want to save to DB, you can do anything as per your logic/design. Value will be in objMission.Notes.
<% Html.BeginForm("SaveNotes", "Home", FormMethod.Post); %>
#Html.AntiForgeryToken()
:
:
<div class="notesLabel">
#Html.LabelFor(model => model.Notes)
</div>
<div class="notesTextBox">
#Html.TextBoxFor(model => model.Notes)
</div>
:
:
<input type="submit" name="submit" value="Save" />
<% Html.EndForm(); %>
public class HomeController : Controller
{
:
:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SaveNotes(Mission objMission)
{
//Set the values to view model accordingly and save to DB eventually
if (ModelState.IsValid)
{
db.Missions.Add(objMission);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(objMission);
}
:
:
}
Related
Currently I have a form which I am wanting to place in multiple views. Currently when I submit this form, the model return has null for all it's values and i am unsure why.
When I debug through it is reaching the POST event but the model values are null. (not the model itself).
Contact Model
public class ContactModel : BasePageModel
{
public string Introduction { get; set; }
public ContactForm Form { get; set; }
public ContactModel(TreeNode node, ContactForm form = null) : base(node)
{
Introduction = node.GetEditableTextStringValue("Introduction", String.Empty);
Form = form;
}
}
View Model for the form
public class ContactForm
{
public string Title { get; set; }
public string FirstName { get; set; }
....
}
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SendContact(ContactForm model)
{
// Do stuff
}
This is the view of the page I want to "embed" if you will the contact form I want to submit.
#model MVCApp.Models.PageModels.ContactModel
....
#using (Html.BeginForm("SendContact", "Contact", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.EditorFor(model => model.Form)
}
And the editor template of the Contact Form itself
#model MVCApp.Models.FormModels.ContactForm
....
#Html.LabelFor(model => model.Title)
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title, "")
#Html.LabelFor(model => model.FirstName)
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName, "")
....
<input type="submit" value="Submit" />
The form renders both parts (The surrounding text and fields) as well as the contact form correctly. But as I said above when I click on submit the model that gets passed back in the POST to the controller (which it does hit through debugging) has all it's fields as null.
Any pointers in where I may have gone wrong would be great.
Marking this as the answer since Stephens comment can't be marked as such.
Using Stephens suggestion, I changed the ActionResult to use
public ActionResult SendContact([Bind(Prefix = "Form")]ContactForm model)
And it worked perfectly. The fields and the model are populated correctly.
I am new to MVC and I am trying to understand how this whole Model binds to a view. I understood how to display any complex object using a partial view / views but I am not able to understand how to create an object of the model using a view.
We have a card to which we can add multiple transactions on the go .
Essentially what I am trying to achieve is this view to add transactions. The Add transactions button when clicked adds a partial view to the div tag on the main page. When I hit save all these transactions have to be added to the AcctCardTransaction model and then be sent to the controller. I am not able to add the UI of my page as the site does not allow me to add it . All I am trying to do is to display a partial view that binds to the model and creates a list of transactions so that the model can be used to save to the tables.
[![Add Card # and Transactions][1]][1]
Here is the model for the Card Transactions
public class AcctCardTransaction
{
public int? LastFourAcctNumber { get; set; }
public int LastFourDigCard { get; set; }
public List<Transaction> AssociatedTransactions { get; set; }
}
Transactions:
public class Transaction
{
public bool isSelected { get; set; }
public int Amount { get; set; }
public DateTime TransDateTime { get; set; }
public string Location { get; set; }
public string Desc1 { get; set; }
public string Desc2 { get; set; }
public string Desc3 { get; set; }
}
Here is the partial view to add one transaction - on to the screen
#model UI.Data.Models.Claim.Transactions.Transaction
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="row">
<div class="col-md-1">
<br />
#Html.CheckBoxFor(model => model.isSelected)
</div>
<div class="col-md-2">
#Html.LabelFor(model => model.Amount) <label>:</label>
#Html.EditorFor(model => model.Amount)
</div>
<div class="col-md-2">
#Html.LabelFor(model => model.TransDateTime)
#Html.EditorFor(model => model.TransDateTime)
#Html.ValidationMessageFor(model => model.TransDateTime)
</div>
<div class="col-md-2">
#Html.LabelFor(model => model.Location)
#Html.EditorFor(model => model.Location)
#Html.ValidationMessageFor(model => model.Location)
</div>
<div class="col-md-2">
#Html.LabelFor(model => model.Desc1)
#Html.EditorFor(model => model.Desc1)
#Html.ValidationMessageFor(model => model.Desc1)
</div>
<div class="col-md-1">
<br />
Delete
</div>
</div>
[![enter image description here][1]][1]
Here is the view to add card # and transaction
#model AcctCardTransaction
#{
ViewBag.Title = "Add Transactions";
}
#using (Html.BeginForm("AddTransactions", "Prepaid"))
{
<script type="text/javascript">
$(document).ready(function () {
$("#btnAddTran").click(function () {
$.ajax({
url: '/Prepaid/AddOneTransaction',
contentType: 'application/html; charset=utf-8',
type: 'GET',
dataType: 'html'
}).success(function (result) {
$('#addTransDiv').append(result);
})
.error(function (xhr, status) {
alert(status);
});
});
});
</script>
<div class="form-inline bottom-left">
<div class="row">
#Html.Label("Last 4 digits of the card")
#Html.EditorFor(model => model.LastFourDigCard)
#Html.ValidationMessageFor(model => model.LastFourDigCard)
#* #Html.Partial( "~/Views/Shared/Partials/_addTransaction.cshtml")*#
<input id="btnAddTran" value="Add Transaction" class="btn btn-default pull-right" />
</div>
</div>
<br />
<div class="row" id="addTransDiv">
<hr />
</div>
<input type="submit" value="save" class="btn btn-default pull-right" />
}
Here is my simple controller . AddoneTransaction is the action that adds one transaction partial view to the view. In my httpPost AddTransactions action The model object does not return any transactions.
Here is my exact question. how do i bind these transactions Model objects that are returned from these partial views as a list to the main model object card transactions and from there return this to the controller?
[HttpGet]
public ActionResult AddTransactions()
{
AcctCardTransaction acctCardtran = new AcctCardTransaction();
return View(acctCardtran);
}
[HttpPost]
public ActionResult AddTransactions(AcctCardTransaction cardTrans)
{
return View();
}
public ActionResult AddOneTransaction()
{
Transaction nTran = new Transaction();
return PartialView("~/Views/Shared/Partials/_addTransaction.cshtml",nTran);
}
I tried a lot of find answer for this question and could not understand what others were talking about , I saw lots of posts on how to display an existing model with a list of objects , but here I want to create and not just display.
You are providing two different models to both views and expecting that they would be bound to one Model somehow and would return the single Model on post. It doesn't make any sense.
....but I am not able to understand how to create an object of the model using a view.
Also you are rendering your Partial view using custom javascript. So you have to write a JS method to find the form and build the model from all added partial views(transactions) and then post it to the server.
$('button.submitTransaction').click(function (e) {
// Sample to find all div containing all added transactions type
var form = $('#AddTransactions').find('form');
// validate the form
var v = $(form).valid();
if (v === true) {
var transactionsContainer = $('#AddTransactions').find('row');
// Loop through the transaction div container
// Find your model properties from fields
var transactions = [];
// Fill transaction related information in the array
// e.g. Find Amount's value and other properties in a Row with in the loop
var transaction = {
'Amount': Amount,
'TransDateTime': TransDateTime,
'Location': Location,
'Desc1': Desc1
}
transactions.push(transaction);
// user your actual post url here
// Data would be automatically deserialized to the model i.e. AcctCardTransaction
var jqreq = $.post('/Prepaid',
{
'LastFourAcctNumber': lastFourAccNo,
'LastFourDigCard': lastFourDigCard,
'Description': description,
'AssociatedTransactions': transactions
});
jqxhrjqreq.done(function (data) {
if (data === true) {
alert('Success!!');
} else {
onError(null);
}
});
jqreq.fail(function (e) {
onError(e);
});
}
return false;
});
i'm using razor's listboxfor for the first time, but my Model is always null.
after reading similar posts and tryouts it still won't work.
Person.cshtml
#model SampleApp.Web.ViewModel.PersonViewModel
#{
ViewBag.Title = "Welcome";
}
<article>
<p>
Welcome to example page.
</p>
<p>
<div class="container">
//Post data works as expected, controllers create method write to db successfully
#using (Html.BeginForm("Create", "Person", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Personen</legend>
<div class="editor-label">
#* #Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Surrname)
</div>
</fielset>
</div>
<p>
<input type="submit" value="Create" />
</p>
}
//binding to Model fails, Model is null. Not be able to debug anything in controller action, it stops when "loading" the page
#using (Html.BeginForm("GetListBoxData", "Person"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.ListBoxFor(model => model.ListboxData, Model.ListboxData);
}
</div>
PersonController.cs
[AcceptVerbs(HttpVerbs.Get)]
[ValidateAntiForgeryToken]
public ActionResult GetListBoxData()
{
var data = new List<PersonViewModel>();
data.Add(new PersonViewModel{Name = "Test", Surrname="testsurrname", Age=30});
var viewModel = new PersonViewModel()
{
ListboxData = data.AsEnumerable().Select(s=> new SelectListItem{Value=s.Name ,Text = s.Surrname}),
};
return View(viewModel);
}
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult GetListBoxData(PersonViewModel persondata)
{
//TODO: handle values from View
return View(this);
}
[ValidateAntiForgeryToken]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Include = "Name, Surrname, Age")] PersonViewModel persondata)
{
try
{
PersonService personDataProvider = new PersonService();
personDataProvider.SavePerson(persondata);
return new RedirectResult("SomewhereToGo");
}
catch (DataException ex)
{
//TODO: Log
}
return View(this);
}
PersonViewModel
public class PersonViewModel
{
public int PersonId{ get; set; }
public int Age { get; set; }
public string Name { get; set; }
public string Surrname { get; set; }
public IEnumerable<SelectListItem> ListboxData { get; set; }
}
writing values from editFor to db works as expected without code for listboxfor.
after adding it to my html it should be filled from db on page loading, but I get a ReferenceNotSet Exception on page loading. Model.ListboxData is null, before GetListBoxData action is called.
Thanks a lot for your help!
Your form should submit the data via POST, not GET. And, you don't need to use enctype = "multipart/form-data", unless you want to upload files through your from.
You need two Index Actions in your Controller, one is for sending the data from your Controller to the View, and the other one is for getting the data back from the View, when the form is submitted (POST) to the server.
The first argument you pass to your ListBox (the expression) refers to the Property in your Model that the selected item from your ListBox will be stored in, which in this case is PersonId.
So, your View should look like this:
#model MVCApplication.Web.ViewModel.PersonViewModel
#using (Html.BeginForm("Index", "Person"))
{
#Html.ListBoxFor(model => model.PersonId, Model.ListBoxData)
<input type="submit" value="Save" />
}
Then, in your Controller, you'll have two Actions like this:
public ActionResult Index()
{
var viewModel = new PersonViewModel()
{
ListboxData = data.Select(s => new SelectListItem { Value = s.PersonId.ToString(), Text = s.PersonId.ToString() }).AsEnumerable();
};
return View(viewModel);
}
[HttpPost]
public ActionResult Index(PersonViewModel viewModel)
{
// code to save the data in the database or whatever you want to do with the data coming from the View
}
By the way, in your ViewModel, you don't have to define your ListBoxData property like that, just do this:
public class PersonViewModel
{
public int PersonId{ get; set; }
public IEnumerable<SelectListItem> ListBoxData { get; set; }
}
I've a problem with ViewModel posting back to a controller, but the ViewModel not being mapped correctly from the View to the Controller.
TopicId and Content should contain values, however, when posted back, they do not:
VS Debug:
ViewModels:
public class PostViewModel
{
public int PostId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Author { get; set; }
public DateTime DateOfTopic { get; set; }
}
public class ReplyViewModel
{
public int TopicId { get; set; }
public string Content { get; set; }
}
public class PostListAndReplyVM
{
public List<PostViewModel> PostViewModel { get; set; }
public ReplyViewModel ReplyViewModel { get; set; }
}
View:
#model centreforum.Models.PostListAndReplyVM
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Post</legend>
#Html.HiddenFor(model => model.ReplyViewModel.TopicId)
<div class="editor-label">
#Html.LabelFor(model => model.ReplyViewModel.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ReplyViewModel.Content)
#Html.ValidationMessageFor(model => model.ReplyViewModel.Content)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Generated HTML:
<form action="/Post/List/7/" method="post"><input name="__RequestVerificationToken" type="hidden" value="xxxxxxxxxxxxx" /> <fieldset>
<legend>Post</legend>
<input data-val="true" data-val-number="The field TopicId must be a number." data-val-required="The TopicId field is required." id="ReplyViewModel_TopicId" name="ReplyViewModel.TopicId" type="hidden" value="7" />
<div class="editor-label">
<label for="ReplyViewModel_Content">Content</label>
</div>
<div class="editor-field">
<input class="text-box single-line" id="ReplyViewModel_Content" name="ReplyViewModel.Content" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="ReplyViewModel.Content" data-valmsg-replace="true"></span>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
</form>
As you can see from the generated HTML, the TopicId definitely has a value: value="7"
Can anyone see where the problem is between the form post, and the controller, which is expecting the ReplyViewModel?
Thank you,
Mark
Your input field names are prefixed with ReplyViewModel (because of the model => model.ReplyViewModel.* lambda), so you need to indicate this information to the model binder:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult List([Bind(Prefix = "ReplyViewModel")] ReplyViewModel model)
{
...
}
Alternatively have your List action take the PostListAndReplyVM model:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult List(PostListAndReplyVM model)
{
// obviously only model.ReplyViewModel will be bound here because
// those are the only input fields in your form
...
}
The problem is the fact that your view is typed to PostListAndReplyVM - so it creates names such as ReplyViewModel.Content - but, because your controller action expects a ReplyViewModel, these fields can't be bound (i.e. there is no such thing as ReplyViewModel.ReplyViewModel.Content).
Change your controller action:
public ActionResult List(PostListAndReplyVM reply)
Alternatively - if that's your whole view - just type it to ReplyViewModel instead (and update your HtmlHelper expressions accordingly).
Its null because you bound it to another model
In view
#model centreforum.Models.PostListAndReplyVM
In Action ReplyViewModel
try to bind like
public ActionResult SomeAction(PostListAndReplyVM model)
{
}
This is the model example.cs
namespace View_Partial_Editor.Models
{
public class ExampleView
{
...
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
public string Field4 { get; set; }
public string Field5 { get; set; }
...
}
}
I have this view example.cshtml:
#model View_Partial_Editor.Models.ExampleView
#{Html.RenderPartial("EditExample",Model);}
#Html.TextBoxFor(m => m.Field1)
Then i have this partialView EditExample.cshtml:
#model View_Partial_Editor.Models.ExampleView
#Html.HiddenFor(m => m.Field1)
#using (Ajax.BeginForm("EditExample", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "partial" }))
{
<div>
#Html.EditorFor(m => m, "Editor", null)
</div>
<p>
<input id="buttona" type="submit" value="Save" />
</p>
}
I have this controller ExampleController:
namespace View_Partial_Editor.Controllers
{
public class ExampleController : Controller
{
//
// GET: /Example/
public ActionResult Example()
{
return View();
}
[HttpPost]
public ActionResult EditExample(ExampleView example)
{
example.Field1 ="7";
return View("Example", example);
}
}
}
And this is the editor that is called in the partial editor.cshtml
#model View_Partial_Editor.Models.ExampleView
<div class="editor-label">
#Html.LabelFor(m => m.Field1 )
</div>
<div class="editor-field">
#Html.EditorFor(m => m.Field1)
#Html.ValidationMessageFor(m => m.Field1)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Field2)
</div>
<div class="editor-field">
#Html.EditorFor(m => m.Field2)
#Html.ValidationMessageFor(m => m.Field2)
</div>
My problem is that i want to modify the data of the model in the controller in the ajax call, and return the model modified to the exampleView.But when the ajax called finish the value that i change in the controller is not changed in the model
Edit: The thing that i want is to send the call to the ajax methos, save something in the database, then modify the model, and in the example view i want to have that model with the changes.
In this moment, if i replace the partial view with the result of the ajax, the model in the example view is not modified.Another way is to replace the full example view, so the model is received there, but i have to pass a lot of fields using Html.HiddenFor, is possible to make this without replacing the views only returnng the model with the changes
Try calling ModelState.Clear() in your HttpPost action method. Html helpers use the values in the ModelState first, then the Model. If you change a value in the model on a post therefore, you need to clear the value from the ModelState.