I'm not sure what I am doing wrong. I have never had this problem before or maybe I have, but I've never noticed. I have a page with a partial view. When the page is submitted, the model is checked to see if it has an ID. If it does, it updates the record. If not, it creates a new one. Pretty standard. Once it is done, the model is returned back to the view. The problem I seem to be having is that it isn't updated with any changes to the model. It is just the same model that was posted. Okay so here is some code. I created a brand new project and it still doesn't work.
Also, I used Firebug to look at the raw data coming back and it is still the same model.
Here is the controller:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Test()
{
return this.View(new Test());
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TestDetailPost(Test testin)
{
Test test = new Test();
test.Id = "1";
test.Name = "Guy";
return this.PartialView("TestDetail", test);
}
Here is the "Test" view:
#model WebAppTest.Models.Test
#using (Ajax.BeginForm("TestDetailPost", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "TestDetail" }))
{
<p><input type="submit"/></p>
<div id="TestDetail">
#{ Html.RenderPartial("TestDetail", Model); }
</div>
}
Here is the "Test Detail" view:
#model WebAppTest.Models.Test
<p>#Html.TextBoxFor(a => a.Id)</p>
<p>#Html.TextBoxFor(a => a.Name)</p>
And the model:
public class Test
{
public string Id { get; set; }
public string Name { get; set; }
}
So what I have found is that if I remove the "Test testin" from the TestDetailPost action, it returns the model I created. If I don't, it just returns the same model that was posted. Of course, I am not doing any DB saves or anything, the code above is just for trying to figure out why this is happening.
Here is the details of what I am using:
MVC5
jQuery 1.11.1
jquery.unobtrusive-ajax
I have updated all files to the latest version using NuGet.
Call ModelState.Clear(); in your action method like below:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TestDetailPost(Test testin)
{
ModelState.Clear();
Test test = new Test();
test.Id = "1";
test.Name = "Guy";
return this.PartialView("TestDetail", test);
}
I have given more details in my answer here. I hope this helps.
Related
I've searched all the available tutorials I can find, and I'm still having trouble with Umbraco Surface Controllers. I've created a bare-bones Surface Controller example which sorta works, but has some issues. Here's my code so far, questions to follow:
ContactformModel1.cs:
public class ContactFormModel1
{
public string Email { get; set; }
public string Name { get; set; }
public string HoneyPot { get; set; }
public string Title { get; set; }
public string Last { get; set; }
public string First { get; set; }
public string Addr { get; set; }
public string Phone { get; set; }
public string Time { get; set; }
public string Comment { get; set; }
}
ContactSurfaceController.cs:
public class ContactSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public ActionResult Index()
{
return Content("this is some test content...");
}
[HttpGet]
[ActionName("ContactForm")]
public ActionResult ContactFormGet(ContactFormModel1 model)
{
return PartialView("~/Views/ContactSurface/Contact1.cshtml", model);
}
[HttpPost]
[ActionName("ContactForm")]
public ActionResult ContactFormPost(ContactFormModel1 model)
{
// Return the form, just append some exclamation points to the email address
model.Email += "!!!!";
return ContactFormGet(model);
}
public ActionResult SayOK(ContactFormModel1 model)
{
return Content("OK");
}
}
Contact.cshtml:
#model ContactFormModel1
#using (Html.BeginUmbracoForm<ContactSurfaceController>("ContactForm"))
{
#Html.EditorFor(x => Model)
<input type="submit" />
}
ContactMacroPartial.cshtml:
#inherits Umbraco.Web.Macros.PartialViewMacroPage
#Html.Action("ContactForm", "ContactSurface")
My Questions:
I'm pretty sure that return ContactFormGet(model) is wrong in the
ContactFormPost method, but everything else I've tried throws an error.
When I try return RedirectToCurrentUmbracoPage(), I get Cannot
find the Umbraco route definition in the route values, the request
must be made in the context of an Umbraco request.
When I try return CurrentUmbracoPage(), I get Can only use
UmbracoPageResult in the context of an Http POST when using a
SurfaceController form.
The routing appears to work correctly (when I put a breakpoint inside ContactFormPost, the debugger stops there). But when the form comes back, I get the exact values I submitted. I don't see the !!! appended to the email address. (Note, this bit of code is just for debugging, it's not meant to do anything useful).
How do I call the "SayOK" method in the controller? When I change the BeginUmbracoForm method to point to SayOK, I still get stuck in the ContactFormPost method.
I'm sure I'm missing something incredibly stupid, but I can't figure this out for the life of me.
I wanted to take a moment to say how I resolved this. After playing around some more, I realized that I didn't really state my problem clearly. Basically, all I'm trying to do is embed an MVC form inside a Partial View Macro, so that it could be used in the content of a page (not embedded in the template).
I could get this solution to work, but I really didn't like how much logic the author put inside the View file. So I adapted his solution this way:
Partial View Macro (cshtml) file:
#inherits Umbraco.Web.Macros.PartialViewMacroPage
#using Intrepiware.Models
#{
bool isPostback = !String.IsNullOrEmpty(Request.Form["submit-button"]);
if(isPostback)
{
#Html.Action("CreateComment", "ContactSurface", Request.Form)
}
else
{
#Html.Partial("~/Views/Partials/ContactForm.cshtml", new ContactFormModel())
}
}
Form Partial View (cshtml) file:
#using Intrepiware.Models
#using Intrepiware.Controllers
#model ContactFormModel
<p>
<span style="color: red;">#TempData["Errors"]</span>
</p>
<p>
#TempData["Success"]
</p>
<div id="cp_contact_form">
#using(Html.BeginUmbracoForm("CreateComment", "BlogPostSurface"))
{
#* Form code goes here *#
}
ContactSurfaceController.cs file:
public class ContactSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ubCreateComment(ContactFormModel model)
{
if (processComment(model) == false)
return CurrentUmbracoPage();
else
return RedirectToCurrentUmbracoPage();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateComment(ContactFormModel model)
{
if(processComment(model) == true)
{
TempData["Success"] = "Thank you for your interest. We will be in contact with you shortly.";
ModelState.Clear();
}
return PartialView("~/Views/Partials/ContactForm.cshtml");
}
private bool processComment(ContactFormModel model)
{
// Handle the model validation and processing; return true if success
}
}
The controller is designed so that the form can be embedded either in the template or a Partial View Macro. If it's embedded in a template, the form should post to ubCreateComment; if it's in a macro, post to CreateComment.
I'm almost positive there's a better/more correct way of doing this, but I ran out of time to work on the project. If someone has a better solution, please post it!
One final question/note: You'll notice that the partial view macro posts Request.Form to the ContactSurfaceController.CreateComment, and MVC magically serializes it for me. That's safe, yeah? If so, doesn't MVC rock? :)
You are using a ChildAction because you are specifying #Html.Action("ContactForm", "ContactSurface") and because of this, in your View you need to:
Use Html.BeginForm(...) and not 'Html.BeginUmbracoForm(...)'
Allow the form to post back to the same path and not to the action
If you do this, then the form will post back to itself as expected.
See the documentation here for further help.
Edit:
Just saw the final part to your question. If you intend SayOK to be your 'thank you' message, I would just call it from your HttpPost action instead of returning the initial view.
I am developing an application. I have created a view and a controller. The view has a button, on the click of which I am supposed to do database operations. I have put the database operations in the model, I am creating the object of model in the controller. On clicking the button the action is handled by a method in the controller, and the object of the model is created to get the records from the database. I would like to know if there is any way to display this data in the view.Is the approach correct or the view is supposed to interact with model directly to get the data.
Following is the code in controller that gets invoked on the button click
public ActionResult getRecord()
{
DataModel f_DM = new DataModel();
DataTable f_DT = f_DM.getRecord();
return View();
}
DataModel is the model class with simply a method "getRecord".
Any help will be highly appreciated.
I would like to add that i am using vs2010 and mvc4
Regards
you should write the logic of retrieving data in your controller. Store all your data in view model and pass it to the view.
for eg.
Model
namespace Mvc4App.Models
{
public class Product
{
public string Name { get; set; }
}
public class ProductViewModel
{
public Product Product { get; set; }
public string SalesPerson { get; set; }
}
}
Controller
public class ProductController : Controller
{
public ActionResult Info()
{
ProductViewModel ProductViewModel = new ProductViewModel
{
Product = new Product { Name = "Toy" },
SalesPerson = "Homer Simpson"
};
return View(ProductViewModel);
}
}
View
#model Mvc4App.Models.ProductViewModel
#{ ViewBag.Title = "Info"; }
<h2>Product: #Model.Product.Name</h2>
<p>Sold by: #Model.SalesPerson</p>
This is the best known practice to pass data from controller to the view.
you may use other techniques also like,
1. ViewData
2. ViewBag
3. TempData
4. View Model Object
5. Strongly-typed View Model Object
Yes, it's possible, but actually now very logical way to to this.
Lets follow your way. You have some View were you have a button, that will trigger this action.
For ex:
public ActionResult Index()
{
return View();
}
Inside view you can have a Ajax link, that will trigget your getRecord method:
<div id="GetDataDiv"></div>
<div>
#Ajax.ActionLink("Get Record", "getRecord", "ControllerName", null, new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "GetDataDiv" })
</div>
In the getRecord method you should have:
public ActionResult getRecord()
{
DataModel f_DM = new DataModel();
DataTable f_DT = f_DM.getRecord();
return PartialView(f_DT);
}
And in View it should be:
#model DataTable
#Model.PropertyOne #Model.PropertyTwo
It should works for you.
Actually same exaple here: http://www.dotnetpools.com/Article/ArticleDetiail/?articleId=151
I'm attempting to create a single Controller class to handle all foreseeable surveys that I'll end up creating in the future. Currently I have a 'Surveys' table with fields: Id, SurveyName, Active. On the 'master' Surveys' Index page I list out every SurveyName found in that table. Each SurveyName is clickable, and when clicked on, the page sends the SurveyName as a string to the receiving controller action. Said controller action looks like this:
//
//GET: /Surveys/TakeSurvey/
public ActionResult TakeSurvey(string surveyName)
{
Assembly thisAssembly = Assembly.GetExecutingAssembly();
Type typeToCreate = thisAssembly.GetTypes().Where(t => t.Name == surveyName).First();
object newSurvey = Activator.CreateInstance(typeToCreate);
ViewBag.surveyName = surveyName;
return View(surveyName, newSurvey);
}
Using reflection I am able to create a new instance of the type (Model) designated by the passed-in string 'surveyName' and am able to pass that Model off to a view with the same name.
EXAMPLE
Someone clicks on "SummerPicnic," the string "SummerPicnic" is passed to the controller. The controller, using reflection, creates a new instance of the SummerPicnic class and passes it to a view with the same name. A person is then able to fill out a form for their summer picnic plans.
This works all fine and dandy. The part that I'm stuck at is trying to save the form passed back by the POST method into the correct corresponding DB table. Since I don't know ahead of time what sort of Model the controller will be getting back, I not only don't know how to tell it what sort of Model to save, but where to save it to, either, since I can't do something ridiculous like:
//
//POST: Surveys/TakeSurvey
[HttpPost]
public ActionResult TakeSurvey(Model survey)
{
if (ModelState.IsValid)
{
_db. + typeof(survey) + .Add(survey);
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View();
}
Is there a way to do this, or should I go about this from a whole different angle? My ultimate goal is to have a single Controller orchestrating every simple-survey, so I don't have to create a separate controller for every single survey I end up making down the road.
An alternative solution I can think of is to have a separate method for every survey, and to have which method to call defined inside of every survey's view. For example, if I had a SummerPicnic survey, the submit button would call an ActionMethod called 'SummerPicnic':
#Ajax.ActionLink("Create", "SummerPicnic", "Surveys", new AjaxOptions { HttpMethod = "POST" })
A survey for PartyAttendance would call an ActionMethod 'PartyAttendance,' etc. I'd rather not have to do that, though...
UPDATE 1
When I call:
_db.Articles.Add(article);
_db.SaveChanges();
This is what _db is:
private IntranetDb _db = new IntranetDb();
Which is...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace Intranet.Models
{
public class IntranetDb : DbContext
{
public DbSet<Article> Articles { get; set; }
public DbSet<ScrollingNews> ScrollingNews { get; set; }
public DbSet<Survey> Surveys { get; set; }
public DbSet<Surveys.test> tests { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
You can try something like this,
UPDATE:
The built-in UpdateModel will work with generic model see this post, so we got little more work.
[HttpPost]
public ActionResult TakeSurvey(FormCollection form, surveyName)
{
var surveyType = Type.GetType(surveyName);
var surveyObj = Activator.CreateInstance(surveyType);
var binder = Binders.GetBinder(surveyType);
var bindingContext = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => surveyObj, surveyType),
ModelState = ModelState,
ValueProvider = form
};
binder.BindModel(ControllerContext, bindingContext);
if (ModelState.IsValid)
{
// if "db" derives from ObjectContext then..
db.AddObject(surveyType, surveyObj);
db.SaveChanges();
// if "db" derives from DbContext then..
var objCtx = ((IObjectContextAdapter)db).ObjectContext;
objCtx.AddObject(surveyType, surveyObj);
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View();
}
Check this two know the diff between DbContext and ObjectContext
I ended up with a slightly modified version of Mark's code:
[HttpPost]
public ActionResult TakeSurvey(string surveyName, FormCollection form)
{
//var surveyType = Type.GetType(surveyName);
//var surveyObj = Activator.CreateInstance(surveyType);
// Get survey type and create new instance of it
var thisAssembly = Assembly.GetExecutingAssembly();
var surveyType = thisAssembly.GetTypes().Where(t => t.Name == surveyName).First();
var newSurvey = Activator.CreateInstance(surveyType);
var binder = Binders.GetBinder(surveyType);
var bindingContext = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => newSurvey, surveyType),
ModelState = ModelState,
ValueProvider = form
};
binder.BindModel(ControllerContext, bindingContext);
if (ModelState.IsValid)
{
var objCtx = ((IObjectContextAdapter)_db).ObjectContext;
objCtx.AddObject(surveyName, newSurvey);
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View();
}
I was running into surveyType being 'null' when it was set to Type.GetType(surveyName); so I went ahead and retrieved the Type via Reflection.
The only trouble I'm running into now is here:
if (ModelState.IsValid)
{
var objCtx = ((IObjectContextAdapter)_db).ObjectContext;
objCtx.AddObject(surveyName, newSurvey);
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
When it tries to AddObject I'm getting the exception "The EntitySet name 'IntranetDb.test' could not be found." I just need to figure out to strip off the prefix 'IntranetDb.' and hopefully I'll be in business.
UPDATE
One thing I completely overlooked was passing the Model to the controller from the View...oh bother. I currently have an ActionLink replacing the normal 'Submit' button, as I wasn't sure how else to pass to the controller the string it needs to create the correct instance of Survey model:
<p>
#Ajax.ActionLink("Create", "TakeSurvey", "Surveys", new { surveyName = ViewBag.surveyName }, new AjaxOptions { HttpMethod = "POST" })
#*<input type="submit" value="Create" />*#
</p>
So once I figure out how to turn 'IntranetDb.test' to just 'test' I'll tackle how to make the Survey fields not all 'null' on submission.
UPDATE 2
I changed my submission method from using an Ajax ActionLink to a normal submit button. This fixed null values being set for my Model values after I realized that Mark's bindingContext was doing the binding for me (injecting form values onto the Model values). So now my View submits with a simple:
<input type="submit" value="Submit" />
Back to figuring out how to truncate 'IntranetDb.test' to just 'test'...
Got It
The problem lies in my IntranetDb class:
public class IntranetDb : DbContext
{
public DbSet<Article> Articles { get; set; }
public DbSet<ScrollingNews> ScrollingNews { get; set; }
public DbSet<SurveyMaster> SurveyMaster { get; set; }
public DbSet<Surveys.test> tests { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
objCtx.AddObject(surveyName, newSurveyEntry); was looking for an entry (an "EntitySet") in the IntranetDb class called "test." The problem lies in the fact that I don't have an EntitySet by the name of "test" but rather by the name of "tests" with an 's' for pluralization. Turns out I don't need to truncate anything at all, I just need to point to the right object :P Once I get that straight I should be in business! Thank you Mark and Abhijit for your assistance! ^_^
FINISHED
//
//POST: Surveys/TakeSurvey
[HttpPost]
public ActionResult TakeSurvey(string surveyName, FormCollection form)
{
//var surveyType = Type.GetType(surveyName);
//var surveyObj = Activator.CreateInstance(surveyType);
// Create Survey Type using Reflection
var thisAssembly = Assembly.GetExecutingAssembly();
var surveyType = thisAssembly.GetTypes().Where(t => t.Name == surveyName).First();
var newSurveyEntry = Activator.CreateInstance(surveyType);
// Set up binder
var binder = Binders.GetBinder(surveyType);
var bindingContext = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => newSurveyEntry, surveyType),
ModelState = ModelState,
ValueProvider = form // Get values from form
};
var objCtx = ((IObjectContextAdapter)_db).ObjectContext;
// Retrieve EntitySet name for Survey type
var container = objCtx.MetadataWorkspace.GetEntityContainer(objCtx.DefaultContainerName, DataSpace.CSpace);
string setName = (from meta in container.BaseEntitySets
where meta.ElementType.Name == surveyName
select meta.Name).First();
binder.BindModel(ControllerContext, bindingContext); // bind form values to survey object
if (ModelState.IsValid)
{
objCtx.AddObject(setName, newSurveyEntry); // Add survey entry to appropriate EntitySet
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View();
}
It's kind of bloated but it works for now. This post helped me get the EntitySet from the Survey object itself so I didn't need to worry about establishing some sort of EntitySet naming convention.
The main problem I see is to bind to the model to the TakeSurvey POST method. If you want different types of survey models should be handled by this method and MVC should bind to this model before calling the action, I believe you can have a wrapper model class over all such generic model, say SurveyModel and use custom model binder to bind to these models.
public class SurveyModel
{
public string GetSurveyModelType();
public SummerPicnicSurvey SummerPicnicSurvey { get; set; }
public PartyAttendanceSurvey PartyAttendanceSurvey { get; set; }
}
Then write a custom mobel binder to bind this model. From the request form fields we can see what type of survey model is posted and then accordingly fetch all the fields and initialize the SurveyModel class. If SummerPicnicSurvey is posted then class SurveyModel will be set with this class and PartyAttendanceSurvey will be null. Example custom model binder.
From the controller action TakeSurvey POST method, You can update db like this:
[HttpPost]
public ActionResult TakeSurvey(SurveyModel survey)
{
if (ModelState.IsValid)
{
if(survey.GetSurveyModelType() == "SummerPicnicSurvey")
_db.UpdateSummerPicnicSurvey(survey.SummerPicnicSurvey);
else if (survey.GetSurveyModelType() == "PartyAttendanceSurvey")
_db.UpdateSummerPicnicSurvey(survey.PartyAttendanceSurvey);
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View();
}
Instead of SurveyModel encapsulating the other surveys you can have inheritance and use .net as to typecast with a check and use the Model.
Having said this, I think there is no harm in using different methods for each model. This will enable you to unit test the code well. Too many if else is not healthy to maintain. Or you can transfer the generic model SurveyModel to the repository or data access layer and let it handle that in a polymorphic way. I would prefer more small functions and keep the code clean.
Edit: The inheritance way:
public class SurveyModel
{
public virtual bool Save();
}
public partial class SummerPicnicSurvey : SurveyModel
{
public bool Save(SummerPicnicSurvey survey)
{
using(var _dbContext = new MyContext())
{
_dbContex.SummerPicnicSurveys.Add(survey);
_dbContex.SaveChanges();
}
}
}
[HttpPost]
public ActionResult TakeSurvey(SurveyModel survey)
{
if (ModelState.IsValid)
{
survey.Save();
return RedirectToAction("Index", "Home");
}
return View();
}
Any new Survey model type you add has to implement the SaveChanges or Save method, Which would call the proper dbcontext method. The controller action would just call Save on the generic `SurveyModel' reference passed to it. Thus the action will be closed for modification but open for modification. The open-close design principle.
I'm really new at all of this. I'm currently reading the tutorial "Getting Started with EF using MVC" on the ASP.NET website: (Chapter 6)
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-in-an-asp-net-mvc-application
In the tutorial, at the part titled "Adding Course Assignments to the Instructor Edit Page" The author wrote about how to edit the Course in the instructor page:
public ActionResult Edit(int id)
{
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses)
.Where(i => i.InstructorID == id)
.Single();
PopulateAssignedCourseData(instructor);
return View(instructor);
}
public ActionResult Edit(int id, FormCollection formCollection, string[] selectedCourses)
{
var instructorToUpdate = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses)
.Where(i => i.InstructorID == id)
.Single();
if (TryUpdateModel(instructorToUpdate, "", null, new string[] { "Courses" }))
{
try
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
{
instructorToUpdate.OfficeAssignment = null;
}
UpdateInstructorCourses(selectedCourses, instructorToUpdate);
db.Entry(instructorToUpdate).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
PopulateAssignedCourseData(instructorToUpdate);
return View(instructorToUpdate);
}
Could some one please tell me how to use the same concept (as the author) to accomplish deleting and creating action method? Or if you can direct me to a useful tutorial/site about many to many relationship with EF in MVC, especially on how to create a controller and view for many to many related data, similar to the tutorial mentioned above. I'm a beginner at this, but I still need to get work done, so it would really help if the concepts used coincides, it would be easier for me.
Thanks so much in advance!
Creation and Deletion are usually a bit simpler. I've outlined just the basic structure. The controller for the create entry page is :
public ViewResult CreateInstructor()
{
return View();
}
To generate the create form you can use the scaffolding (just right-click on View and select Add View... and then select the appropriate model and page type).
The post-back of this page is handled by a controller with the [HttpPost] attribute, it will bind the data on the form to the object passed into the controller method and this is then passed to your DBContext Add() method, finally execute the SaveChanges() method to actually hit the database:
[HttpPost]
public ActionResult CreateInstructor(Instructor instructor)
{
db.Instructors.Add(instructor);
db.Instructors.SaveChanges();
return View(); //There will be some other logic here typically such as redirecting on a successful creation or showing specific validation issues with the object .
}
Delete is achieved using the DBContext Remove method, just note that you do not first have to hit the database to load the object and then again to delete it. You will typically be passed the object's id and you can then attach a new instance of the object to the context and delete it.
public ActionResult DeleteInstructor(int instructorId)
{
var instructor = new Instructor {Id = instructorId};
db.Instructors.Attach(instructor);
db.Instructors.Remove(instructor);
db.Instructors.SaveChanges();
return View();
}
I know this is an old thread. But I was trying to do the EXACT same thing
Here's my solution
//
// GET: /Project/Create/
public ActionResult Create()
{
var project = new Project();
ViewBag.Themes = db.Theme.ToList();
return View(project);
}
//
// POST: /Project/Create/
[HttpPost]
public ActionResult Create(Project projet, string[] selectedTheme)
{
var errors = ModelState.Select(x => x.Value.Errors).ToList();
project.Themes = new List<Theme>();
if (TryUpdateModel(project, "", null, new string[] { "Theme" }))
{
try
{
UpdateProjectTheme(selectedTheme, project);
db.Project.Add(project);
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Impossible to create project.");
}
}
return View(project);
}
And in the create view :
#{
List<Project.Models.Theme> themes = ViewBag.Themes;
#:<td>
foreach (var display in themes)
{
<label class="checkbox">
<input type="checkbox"
name="selectedTheme"
value="#display.ThemeID" />
#display.Name
</label>
if (display.Name.Length > 20)
{
#:<br />
}
else
{
if (display.ThemeID % 2 == 0)
{
#:<br />
}
}
}
#:</td>
#: </tr>
}
Hope you find it useful, you can also look on my SO post
This is my post !!
Below Scenario, I think I must see the START text in my form when first loaded.
When I click send data button and submit, I was waiting to see FINISH text in my form.
Buy the START text never changes when I click the button and post the form...
Anybody can tell the problem?
MY CONTROLLER:
namespace MvcApplication1.Controllers
{
public class BuyController : Controller
{
public ActionResult Index(BuyModel model)
{
if (Request.HttpMethod == "GET")
{
model.Message= "START";
return View(model);
}
else
{
BuyModel newModel = new BuyModel();
newModel.Message= "FINISH";
return View(newModel);
}
}
}
}
MY VIEW :
#model MvcApplication1.Models.BuyModel
#using (Html.BeginForm("Index", "Buy", FormMethod.Post))
{
#Html.TextBoxFor(s => s.Message)
<button type="submit" >Send</button>
}
MY MODEL:
public class BuyModel
{
public string Message { get; set; }
}
public class BuyController : Controller
{
public ActionResult Index()
{
BuyModel model = new BuyModel();
model.Message= "START";
return View(model);
}
[HttpPost]
public ActionResult Index(BuyModel model)
{
model = new BuyModel();
model.Message= "FINISH";
ModelState.Clear(); // the fix
return View(model);
}
}
View:
#model MvcApplication1.Models.BuyModel
#using (Html.BeginForm("Index", "Buy"))
{
#Html.TextBoxFor(s => s.Message)
<button type="submit" >Send</button>
}
Your issue is because your original code, that Action Method will only be executed as an HTTP GET request. ASP.NET MVC allows you to specify a post with the [HttpPost] attribute (see above code).
I'm not sure what you are getting at with your POST desired-behavior. It seems like you are just wiping out whatever form values are pushed on the POST. So modify my above code accordingly, but it should give you the general idea.
Edit: it seems to be that the text box is retaining its value after the POST. It's not just with "START", but if you type anything into that text box and hit submit, you'll have a POST with the exact same text in the text box that was there when you submitted the form.
Edit Edit: see the changed code. Call ModelState.Clear() in your POST action method and you'll have the right value reflected.
If you are posting, and not returning a RedirectResult, by default the helpers will use the value from ModelState. You either need to clear ModelState or have a different approach.
The PRG (post redirect get) pattern in MVC is very important. So if its a post, and you aren't redirecting, the helpers assume there is an error that needs to be corrected and the value is pulled from ModelState.