i've a table post(p_id,u_id(FK),date,title,type,viewer)and a Modelclass UserModel.cs with(p_id,u_id,date,title,type). When i to create a new post in a post controller i tried like public ActionResult Create(PostModel p)
{
if (ModelState.IsValid)
{
p.date = DateTime.Today;
post post = new Models.DB.post();
post.u_id = User.Identity.Name;
post.date = p.date;
post.title = p.title;
post.type= p.type;
post.viwer=1;
try{ db.posts.AddObject(post);
db.SaveChanges();
return RedirectToAction("LoggedIndex");
}
catch{ return RedirectToAction("Index"); }
}
return View(p);
}
It is not Working. I think from is not submitting when i submit always view is returned. i i've created stronly typed create view. in create.cshtml i've two hidden field user_id and date of postModel Object. I'm very new at MVC.please help me thanks in advance....
Sending Data from View to the Controler by using the MVC-Model
I understand it like that: you have a mvc3 page and want to send some custom data to your controller:
Controller:
[http-post]
public ActionResult Create(PostModel p)
{
if (ModelState.IsValid)
{
p.date = DateTime.Today;
post post = new Models.DB.post();
post.u_id = User.Identity.Name;
post.date = p.date;
post.title = p.title;
post.type= p.type;
post.viwer=1;
db.posts.AddObject(post);
db.SaveChanges();
return RedirectToAction("LoggedIndex");
}
return View(p);
}
public ActionResult Create()
{
return View(new post());
}
View:
#model post
#using (Html.BeginForm("Create", "Controller-Name", FormMethod.Post, new { id = "FORM" }))
{
#Html.EditorFor(model => model.date)
#Html.EditorFor(model => model.name)
#Html.EditorFor(model => model.title)
#Html.EditorFor(model => model.type)
}
Further informations: http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx
Related
My question is two-fold.
I have a View that gets data on the change of a drop down selection.
The data retrieved is a List property of a ViewModel class using an Ajax call.
This data is shown as a selection of check boxes for the user to select any number of them.
If I return a Partial View from an AJAX call, this is easy enough, but from what I have experienced, this doesn't work for POST'ing back to the controller. Nothing is bound correctly.
From what I have read the correct way is to use EditorFor, So firstly, I cannot figure out how to populate the EditorFor from the AJAX call.
Secondly, If I test by sending initial data from my GET, the EditorFor displays the correct checkbox options, but when I POST, the count of the items is 0.
View:
#model EngineeringAssistantMVC.Controllers.FirmwareController.FirmwareViewModel
#using (Html.BeginForm("Upload", "Firmware", FormMethod.Post, new { #id = "uploadFirmwareForm", #class = "form-horizontal" }))
{
<!-- Device -->
<div class="form-group">
<div class="col-lg-1">
#Html.LabelFor(x => x.Device, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-lg-2">
#Html.DropDownListFor(x => x.Device, ViewBag.Devices as IEnumerable<SelectListItem>, new { #class = "form-control", #id = "Devices" })
</div>
<div class="col-lg-9">
#Html.ValidationMessageFor(x => x.Device, "", new { #class = "text-danger" })
</div>
</div>
#Html.EditorFor(x => x.SelectedModels, "SelectedModels", new { #id = "Models" })
#Html.HiddenFor(x => x.SelectedModels)
}
And the AJAX call:
function GetModels() {
$.ajax({
type: "GET",
url: '#Url.Action("GetModels", "Firmware", null)',
data: { SelectedDevice: $('#Devices').val() },
success: function (dataSet) {
//$('#Models').html(dataSet);
//$('#Models').data(dataSet);
//$('#Models').val(dataSet);
// How do I populate the EditorFor from the dataSet returned?
},
error: function (err) {
console.log("ERROR: " + err.responseText);
},
})
}
SelectedModels EditFor Template:
#model IEnumerable<EngineeringAssistantMVC.ViewModels.ModelViewModel>
#foreach (var item in Model)
{
#Html.CheckBoxFor(x => item.IsSelected)
#Html.Label(item.Description)
#Html.HiddenFor(x => item.ModelId)
#Html.HiddenFor(x => item.IsSelected)
#Html.HiddenFor(x => item.Description)
}
Controller:
[HttpPost]
public ActionResult Upload(HttpPostedFileBase uploadFile, FirmwareViewModel firmwareViewModel)
{
// firmwareViewModel.SelectedModels count is 0 here
}
ModelFirmware Class:
public class ModelFirmware
{
public int ModelFirmwareId { get; set; }
public int FirmwareId { get; set; }
public int ModelId { get; set; }
}
FirmwareViewModel:
public class FirmwareViewModel
{
public int FirmwareViewModelId { get; set; }
[Required]
public string Device { get; set; }
public ICollection<ModelViewModel> SelectedModels { get; set; }
}
I just can't get it to work correctly.
EDIT 1: - Add method that returns the models
[HttpGet]
public ActionResult GetModels(string SelectedDevice)
{
var deviceAbbreviation = _dbContext.Radios.Where(x => x.RadioName == SelectedDevice).Select(x => x.ProjectAbbreviation).FirstOrDefault();
var models = _dbContext.AnatomyModels.Where(x => x.SerialPrefix.StartsWith(deviceAbbreviation.Trim()) && x.ParentId == 0).ToList();
List<ModelViewModel> mvms = models.Select(x => new ModelViewModel()
{
ModelId = x.AnatomyModelId,
Description = x.SerialPrefix,
IsSelected = false,
}).ToList();
return Json(mvms);
}
There are numerous issues with your code.
First your not using the EditorTemplate correctly. Change its name to ModelViewModel.cshtml to match the name of the class, and locate it in the /Views/Shared/EditorTemplates (or /Views/YourControllerName/EditorTemplates) folder. The template is then based on a single object (note also the LabelFor() required to create a label associated with the checkbox, and you need to delete the hidden input for IsSelected)
#model ModelViewModel
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m.IsSelected, Model.Description)
#Html.HiddenFor(m => m.ModelId)
#Html.HiddenFor(m => m.Description)
Refer also Post an HTML Table to ADO.NET DataTable to understand why your foreach loop would never have created the correct name attributes for model binding.
Then in the main view use
<div id="container">
#Html.EditorFor(m => m.SelectedModels)
</div>
and remove the hidden input for SelectedModels (but before you do, inspect the html for that element to understand why its value would never bind). The EditorFor() method will correctly generate the html for each item in your collection.
Next, change your GetModels() method to return a partial view based on FirmwareViewModel since that is what you will be posting back. Note that you could return a JsonResult, but that would mean generating a whole lot of html in the ajax call back that would not be strongly typed.
[HttpGet]
public PartialViewResult GetModels(string SelectedDevice)
{
var deviceAbbreviation = _dbContext.Radios.Where(x => x.RadioName == SelectedDevice).Select(x => x.ProjectAbbreviation).FirstOrDefault();
var models = _dbContext.AnatomyModels.Where(x => x.SerialPrefix.StartsWith(deviceAbbreviation.Trim()) && x.ParentId == 0).ToList();
List<ModelViewModel> mvms = models.Select(x => new ModelViewModel()
{
ModelId = x.AnatomyModelId,
Description = x.SerialPrefix,
IsSelected = false, // not really necessary since its the default
}).ToList();
FirmwareViewModel model = new FirmwareViewModel
{
SelectedModels = mvms
};
return PartialView(model);
}
and your GetModels.cshtml view will be
#model FirmwareViewModel
#Html.EditorFor(m => m.SelectedModels)
Then, modify your ajax call to add the partial view in the success callback
$.ajax({
type: "GET",
url: '#Url.Action("GetModels", "Firmware")', // do not need to add 3rd parameter
data: { SelectedDevice: $('#Devices').val() },
success: function (response) {
$('#container').html(response);
},
error: function (err) {
console.log("ERROR: " + err.responseText);
},
})
The .html() function will replace any elements already existing in the <div id="container"> element
Finally, since your using a view model, make use of it and do not use ViewBag. Your view model should contain a IEnumerable<SelectListItem> Devices property which you populate in the GET method (and use #Html.DropDownListFor(x => x.Device, Model.Devices, new { #class = "form-control" }) in the view (note also that the method generates id="Device"). It should also contain a HttpPostedFileBase property to avoid the additional parameter in the POST method, and allow you to add validation attributes.
I am new in .NET mvc 5 environment.
I have a view:
Index.cshtml
#model Accounts.WebHost.Models.SendUsernameReminderInputModel
#using (Ajax.BeginForm("Index", "SendUsernameReminder", null, new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "validationList", LoadingElementId = "loader", OnSuccess = "onSuccess", OnFailure = "onFailure" }, new { #id = "validationForm", #class = "form-inline" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="form-group hidden">
#Html.TextBoxFor(model => model.Tenant, new { #class = "form-control", #Value = "default" })
</div>
<button type="submit" class="btn btn-default">Submit</button>
}
<hr />
<div id="loader" class="alert" style="display:none">
<img src="~/Content/img/ajax-loader.gif" />
</div>
#Html.Partial("_UsernameValidation")
And a Partial view:
_UsernameValidation.cshtml
#model Accounts.WebHost.Models.SendUsernameReminderInputModel
<div id="validationList">
<table>
<tr>
<td>#Html.ValidationMessageFor(model => model.Email)</td>
<td>#Html.ValidationMessageFor(model => model.Tenant)</td>
</tr>
</table>
</div>
this is my Controller:
SendUsernameReminderController.cs
using Accounts.Entities.Models;
using Accounts.WebHost.Models;
using BrockAllen.MembershipReboot;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace Accounts.WebHost.Controllers
{
public class SendUsernameReminderController : Controller
{
public readonly UserAccountService<MemberAccount> userAccountService;
public SendUsernameReminderController(UserAccountService<MemberAccount> userAccountService)
{
this.userAccountService = userAccountService;
}
[HttpGet]
public ActionResult Index(string signin)
{
ViewBag.Signin = signin;
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(SendUsernameReminderInputModel model)
{
if (ModelState.IsValid)
{
try
{
this.userAccountService.SendUsernameReminder(model.Tenant, model.Email);
return RedirectToAction("Success", model);
}
catch (ValidationException ex)
{
if (ex.ValidationResult.ToString() == "The email address for this account is not yet verified.")
{
try
{
userAccountService.ResetPassword(model.Tenant, model.Email);
return RedirectToAction("Unverified");
}
catch (ValidationException resetex)
{
ModelState.AddModelError("", resetex.Message);
ViewBag.Message = "resetex.Message";
return View();
}
}
ModelState.AddModelError("", ex.Message);
return View();
}
}
return View();
}
public ActionResult Success(SendUsernameReminderInputModel model)
{
ViewBag.Subject = "Username Emailed";
ViewBag.Message = "Your username was emailed at " + model.Email + ". If you don't receive this email within 24 hours, please check your junk mail folder or visit our Help pages to contact Customer Service for further assistance.";
return View();
}
public ActionResult Unverified()
{
ViewBag.Subject = "Email has not been verified";
ViewBag.Message = "You will receive an email from us to confirm your email or cancel your registration. If you don't receive this email within 24 hours, please check your junk mail folder or visit our Help pages to contact Customer Service for further assistance.";
return View();
}
}
}
And this is my Model:
SendUsernameReminderInputModel.cs
using System.ComponentModel.DataAnnotations;
namespace Accounts.WebHost.Models
{
public class SendUsernameReminderInputModel
{
[Required]
[EmailAddress]
public string Email
{
get;
set;
}
[Required]
public string Tenant
{
get;
set;
}
}
}
my aim is that when a user clicks the form submit button only the validation message will display below the form. unfortunately, it outputs the whole Index.cshtml in the partial and the validation message at the bottom.
If this is a bad approach please give me directions.
Thank you in advance.
U need to pass Model like View(model) ; so that the View gets the model with those errors.
And u could also use #Html.ValidationSummary to display all the errors on a fly
this is my Get actionresult :
public ActionResult Add()
{
ViewData["categoryList"]= _categoryRepository.GetAllCategory().
ToSelectList(c => c.Id, c => c.Name);
return View("Add");
}
this my razor that render the categoryList , and I have no trouble with that !
<div>
#Html.LabelFor(b => b.Category)
#Html.DropDownList("Category", ViewData["categoryList"] as IEnumerable<SelectListItem>)
#Html.ValidationMessageFor(b => b.Category)
</div>
finally after submitting the page , category select send via null value to post this action
[HttpPost]
public ActionResult Add(BlogPost blogPost)
{
if (ModelState.IsValid)
{
blogPost.PublishDate = DateTime.Now;
_blogPostRepository.AddPost(blogPost);
_blogPostRepository.Save();
return RedirectToAction("Add");
}
return new HttpNotFoundResult("An Error Accoured while requesting your order!");
}
could anybody tell me why ??
controller
public ActionResult Add()
{
ViewBag.CategoryList = new SelectList(_categoryRepository.GetAllCategory(), "Id", "Name");
// you dont need the specify View name
// like this: return View("Add")
// you need to pass your model.
return View(new BlogPost());
}
view
#Html.DropDownListFor(model => model.CategoryId, ViewBag.CategoryList as SelectList, "--- Select Category ---", new { #class = "some_class" })
controller post action
[HttpPost]
public ActionResult Add(BlogPost blogPost)
{
if (ModelState.IsValid)
{
blogPost.PublishDate = DateTime.Now;
_blogPostRepository.AddPost(blogPost);
_blogPostRepository.Save();
// if you want to return "Add" page you should
// initialize your viewbag and create model instance again
ViewBag.CategoryList = new SelectList(_categoryRepository.GetAllCategory(), "Id", "Name");
return View(new BlogPost());
}
return new HttpNotFoundResult("An Error Accoured while requesting your order!");
}
I'm trying to get the drop down list to have my item selected when there is an item, but it never does. I've Googled this and tried many different methods, but they all seem to use a ViewModel containing the list instead of using ViewBag, but I would like to stick to the ViewBag if possible.
My controller:
[HttpGet]
public ActionResult Index(int? id)
{
ViewBag.SelectList = new SelectList(rep.GetItemList(), "id", "type");
if (id.HasValue)
{
var model = rep.GetItemByID(id.Value);
if ( model != null )
{
return View(model);
}
}
return View();
}
My View:
<div class="editor-field">
#Html.DropDownListFor(model => model.itemID, (SelectList)ViewBag.SelectList)
#Html.ValidationMessageFor(model => model.itemID)
</div>
This doesn't have my item selected in the DropDownList, and I've also tried having a list in the ViewBag and then constructing the SelectList in the View, which some posts say should solve the problem:
<div class="editor-field">
#Html.DropDownListFor(model => model.itemID, new SelectList(ViewBag.SelectList, "id", "type", Model.itemID))
#Html.ValidationMessageFor(model => model.itemID)
</div>
But none of it seems to work. So I was wondering if there is anyone where that is able to spot what I'm doing wrong?
make sure your itemID property is set in the model you are passing to the view
if (id.HasValue)
{
var model = rep.GetItemByID(id.Value);
model.itemID=id.Value;
return View(model);
}
I would try setting the selected value from the begining since SelectList is immutable.
[HttpGet]
public ActionResult Index(int? id)
{
if (id.HasValue)
{
ViewBag.SelectList = new SelectList(rep.GetItemList(), "id", "type", id );
var model = rep.GetItemByID(id.Value);
if ( model != null )
{
return View(model);
}
}
else
{
ViewBag.SelectList = new SelectList(rep.GetItemList(), "id", "type");
}
return View();
}
In your View use it like this:
#Html.DropDownListFor(model => model.itemID, (SelectList)ViewBag.SelectList, "Please select...")
OK, I've been over Google and StackOverflow and ASP.net - am I really the only person who doesn't get this?
Rough problem = I have an Employee entity that references an Office entity. I was previously able to create new employees (beat me with a hammer for forgetting how that code worked) but now I just can't create an employee nor edit an existing one.
Now, here's what I learned;
1) Make sure you add the Offices list to the ViewBag at every step
2) That includes a failed POST/edit; call the function to re-populate the ViewBag with the Offices list
3) I think(!!) that you always want to set the Employee.Office, not the Employee.Office.OfficeID; the latter leads to "is part of the object's key information and cannot be modified" errors
So, what I have is;
A controller that has the following method;
private void AddOfficesToViewBag()
{
Dictionary<string, Office> list = new Dictionary<string, Office>();
foreach (Office office in company.GetAllOffices())
list.Add(office.ToString(), office);
SelectList items = new SelectList(list, "Value", "Key");
ViewBag.OfficeList = items;
}
Create pair looking like;
public ActionResult Create()
{
if (company.Offices.Count() < 1)
return RedirectToAction("Create", "Office", (object) "You need to create one or more offices first");
AddOfficesToViewBag();
return View(new Employee());
}
//
// POST: /Employee/Create
[HttpPost]
public ActionResult Create(Employee emp)
{
if (TryUpdateModel<Employee>(emp))
{
company.Employees.Add(emp);
company.SaveChanges();
return RedirectToAction("Index");
}
else
{
AddOfficesToViewBag();
return View(emp);
}
}
and an Edit pair that looks like;
public ActionResult Edit(int id)
{
Employee emp = company.Employees.Single(e => e.EmployeeID == id);
AddOfficesToViewBag();
return View(emp);
}
//
// POST: /Employee/Edit/5
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
Employee emp = company.Employees.Single(e => e.EmployeeID == id);
if (TryUpdateModel(emp))
{
company.SaveChanges();
return RedirectToAction("Index");
}
else
{
AddOfficesToViewBag();
return View(emp);
}
}
I'll pick the Edit View, which is pretty much the same as the Create View;
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
Employee
#Html.HiddenFor(model => model.EmployeeID)
<div class="editor-label">
#Html.LabelFor(model => model.Office)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Office, (SelectList) ViewBag.OfficeList)
#Html.ValidationMessageFor(model => model.Office)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Age)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
I would say that the Edit, in particular, looks almost there. It manages to bind to the Employee object passed in and sets the dropdown to the appropriate entry.
Viewing the original HTML source shows that the output value is the Office.ToString() value.
The odd thing to me is that some magic is happening that binds Employee->Office to the correct entry, which makes the Edit view work, but there is no corresponding conversion of the selected item (a string, aka object->ToString()) to the original list.
This seems so basic (MVC / EF4 / DropDownList) that I feel I'm missing something incredibly fundamental.
All thoughts appreciated.
Regards
Scott
Based on the following you can
http://forums.asp.net/t/1655622.aspx/1?MVC+3+Razor+DropDownListFor+and+Model+property+from+EFCodeFirst
Do the following:
[HttpPost]
public ActionResult Edit(Guid id, FormCollection collection)
{
CollectionViewModel cvc = new CollectionViewModel();
cvc.Collection = _db.Collections.Where(c => c.CollectionId == id).Include("CollectionType").First();
Guid collectionTypeId = Guid.Parse(collection["CollectionTypeId"].ToString());
cvc.Collection.CollectionType =_db.CollectionTypes.Where(ct =>ct.CollectionTypeId == collectionTypeId).First();
if (TryUpdateModel(cvc))
{
_db.SaveChanges();
return RedirectToAction("Index");
}
}
ViewModel
public class CollectionViewModel
{
public Collection Collection {get; set; }
public Guid CollectionTypeId { get; set; }
public SelectList CollectionTypes { get; set; }
}