Hi people I am new to this website was having trouble with my controller in C# MVC3 and when I gave up on looking for answers since i spent like 2 weeks on it I decided to join here.
The problem is I want a very simple confirmation message when I create a item in my application. I tried a If statement but I can't get the context correct. Can you kind people please help me thank you. My code:
//
// POST: /News/Create
[HttpPost]
public ActionResult Create(BooksItem booksitem)
{
try
{
using (var db = new BooksForever2())
{
db.NewsItems.Add(booksitem);
db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
The create works fine I can add books and it saves but I want when it saves a message appears so it shows the user its has been saved. I have tried: Viewbag.Message("Saved")
But this does not work. Any help will be truly appreciated
Thank You
Just add this in you controller
TempData["Message"] = "Saved";
then in your view:
#if(TempData["Message"] != null)
{
<p>#TempData["Message"].ToString()</b> #* or whatever element you need to show*#
}
at your view level you can do anything with the message (maybe flash it with jQuery):
jquery: Flash messages
UPDATE: I replaced ViewBag with TempData because I noticed you are doing a redirect, in which case the ViewBag won't persist but TemData would
Where do you want that confirmation message displayed? On the same edit form you are already on, or back on the index/list page?
Right now at the end of your method, you are redirecting to the Index action/page:
return RedirectToAction("Index");
The result of that is that the Index page will be loaded, and it will be completely unaware of where it came from other that something was saved.
Your two options, as I see it, are:
1) Stay on the current page, and display the message. You can add that message to the ViewBag like as has already been mentioned:
ViewBag.Message = "Saved"`
And then display it like this:
#if(ViewBag.Message != null)
{
<p>#ViewBag.Message</p>
}
and then make sure you remove the RedirectToAction and just return the default View, otherwise will still bounce you to the Index page.
2) Or, you can redirect the user back to the Index page, passing the message to be displayed, and then have the Index page look for that message. So when you call RedirectToAction, include a query string parameter:
ViewBag.Message
return RedirectToAction("Index", new { Message="Saved" });
Which will redirect you to ".../yourControllerName/Index?Message=Saved". Then you can add this to your Index action method:
if(!string.IsNullOrEmpty(QueryString["Message"]))
{
ViewBag.Message = QueryString["Message"];
}
And include that same view code in your index view:
#if(ViewBag.Message != null)
{
<p>#ViewBag.Message</p>
}
Related
I need feature that is something similar to Laravel's old input helper but in MVC 5.
https://laravel.com/docs/5.6/requests#old-input
If validation fails, I need to reload all my model data as it was in the previous request except those inputs where user entered something wrong.
The problem is that my form has many disabled inputs and fields that program is fetching within [HttpGet] method, and they're getting lost during submission. So I need to store them in session.
The code below seems to work but is there any more efficient and beautiful way to do so with a less amount of code within each controller?
[HttpGet]
[Route(#"TaskManagement/Edit/{guid}")]
public async Task<ActionResult> Edit(Guid guid)
{
var model = new EditTaskViewModel();
model.Guid = guid;
await model.GetTaskFromRemoteService(new UserInfo(User));
ControllerHelpers.DisplayAlerts(model, this);
TempData["OldModel"] = model;
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
[Route(#"TaskManagement/Edit/{guid}")]
public async Task<ActionResult> Edit(EditTaskViewModel model, Guid guid, string submit)
{
model.Guid = guid;
if (ModelState.IsValid) {
await model.UpdateTaskInRemoteService(new UserInfo(User), submit);
ControllerHelpers.DisplayAlerts(model, this, "Task successfully updated");
if (model.ErrorCode == null)
return RedirectToAction("Edit", new { guid = model.Guid });
return RedirectToAction("Index");
}
if (TempData["OldModel"] != null) {
model = (EditTaskViewModel)TempData["OldModel"];
}
return View(model);
}
Using session state (including TempData) like this may break when you have multiple copies of the page open. You can work around this by generating a unique ID for the session key and storing it in a hidden field.
However, I would try to avoid using session altogether.
A simple approach is to use hidden fields to store the values that aren't sent to the server because they are in disabled fields.
A more robust approach is a separate class (or at least a private method) that knows how to setup your model for the first time and in transition (e.g. failed server validation). I call these classes "composers" and I describe the approach here.
Pseudocode for how an action method with a composer might look:
if( ModelState.IsValid ){
return Redirect();
}
var rebuiltModel = _composer.ComposeEdit( incomingModel );
return View( rebuiltModel );
I think the answer was quite simple. The shortest and easiest way is to populate the object from the database\remote service once more.
The fields that user entered whether they're valid or not will stay as they were before. The rest of them will load once again.
I am creating an CRUD Application in Asp.Net Core
After Add Operation I am redirecting to same view with setting model value as null to get another entry
Below is my code
public IActionResult Add(OptionMasterVM model)
{
try
{
model.QuestionList = context.QuestionMaster.Select(x => new SelectListItem { Text = x.QuestionName, Value = x.QuestionId.ToString() }).ToList();
if (HttpContext.Request.Method == "POST")
{
OptionMaster _optionmaster = new OptionMaster();
_optionmaster = model.OptionMaster;
using (var ctx = new QuestionnaireEntities(_configuration))
{
ctx.OptionMaster.Add(_optionmaster);
ctx.SaveChanges();
}
TempData["Msg"] = "Option Added Successfully , Add Another Option";
model.OptionMaster.OptionValue = string.Empty;
model.OptionMaster.OptionRating = 0;
return View(model);
}
}
catch (Exception ex)
{
logger.LogError(ex);
}
finally
{
}
return View(model);
}
Here I am setting Option Value to empty and rating to Zero to take next entry , but on view it does not show empty and zero , on view it show previously filled value.
After Setting below code these two fields should be reset but they don't
model.OptionMaster.OptionValue = string.Empty;
model.OptionMaster.OptionRating = 0;
Is there any other way to set model object as null in Asp.net Core ?
This can happen because Razor helpers use values from ModelState, rather than the model itself. Your OptionValue is probably displayed using a helper, for example:
#Html.TextBoxFor(m => m.OptionMaster.OptionValue)
When you change model values within an action, you need remove the old values from ModelState before rendering the View.
The easiest way of doing this is to call ModelState.Clear()
model.OptionMaster.OptionValue = string.Empty;
model.OptionMaster.OptionRating = 0;
ModelState.Clear(); // ensure these changes are rendered in the View
return View(model);
The values displayed for bound form fields come from ModelState, which is composed based on values from Request, ViewData/ViewBag, and finally Model. After posting, obviously, you'll have values set in Request, which will therefore be the values in ModelState. It works this way, so that when there's a validation error and the user is returned to the form to correct their mistakes, the values they posted will be there for them to edit.
Long and short, you need to follow the PRG (Post-Redirect-Get) pattern. Essentially, after posting, you only return the view on error. If the post is successful, you redirect. This not only clears ModelState, but also prevents accidental re-posts if the user attempts to refresh the page.
If you want to take the user back to the same view, simply redirect to the same action, but you need to do a redirect, not return the view.
i have the following Action method that return an _error partial view in case an Exception occur:-
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Register(string id, int classid) {
try
{
Thread.Sleep(3000);
User user = r.FindUser(id);
Users_Classes uc = new Users_Classes();
uc.AddedDate = DateTime.Now;
uc.ClassID = classid;
user.Users_Classes.Add(uc);
r.Save();
ViewBag.classid = classid;
return PartialView("_usersearch2", uc);
}
catch (DataException ex)
{
return PartialView("_error");
}
and the following _error partial view:-
<script type="text/javascript">
alert('The user might have been already Assinged, Search Again to get the latest users');
</script>
The above approach is working fine, but does it consider a bad design to return a partial view to display only an alert ? and is there a better way to do this?
The problem is you are now tying your implementation to your user interface. The Controller suddenly decides how an error message should appear on the client.
What if you want to change it from an alert to displaying a red border around a text input with some description next to it?
Determining how something should be displayed is up to your view. Your controller should only return status codes and then your view should decide what to do.
Instead of returning inline js you should have error handling code on your client side within a js library. Rather than returning the hole js only return the message.
In general, I'd say yes. But, sometimes a bad design is just what the doctor ordered ;)
There's a Controller instance method called Javascript that I use to return executable javascript from my controller, on very limited occasions, when taking the time to do it the "right" way isn't feasible:
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Register(string id, int classid)
{
try
{
... stuff
}
catch (DataException ex)
{
return Javascript("alert('The user might have been already Assinged, Search Again to get the latest users');");
}
}
The fact that something like this exists gives me solace that I'm not completely breaking the law.. unless I'm using it wrong, which I probably am.
I have 2 Action methods in one controller,
Index:
public ActionResult Index(string url)
{
// take the url as a param and do long tasks here
ViewBag.PageTitle = "title";
ViewBag.Images = "images";
// and some more view bags
return View();
}
This index view contains a form which post to another method in the same controller.
public ActionResult PostMessage(string msg, string imgName)
{
// save data in the db
// but on error I want to navigate back to the Index view but without losing data the user fielded before submit the form.
// Also need to pass an error message to this index view to show
}
How to return back to Index view if something went wrong in the PostMessage method, and also don't clear the form fields, plus showing an error message which the PostMessage method specified.
I need to know the best practice for doing such a scenario.
The best approach is usually to create a ViewModel type for your form. Add attributes to the properties of that model to define what would make it "wrong." Make your form use methods like #Html.TextBoxFor the various fields. Then have your PostMessage class take an object of that type, rather than taking the message and image name directly. Then you can validate the model and return the view again if the model is invalid.
See http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx for some code examples following this pattern.
You could specify the name of the view you want to return:
public ActionResult PostMessage(string msg, string imgName)
{
if (SomeErrorWhileSavingInDb)
{
// something wrong happened => we could add a modelstate error
// explaining the reason and return the Index view.
ModelState.AddModelError("key", "something very wrong happened when trying to process your request");
return View("Index");
}
// everything went fine => we can redirect
return RedirectToAction("Success");
}
Just redirect back to the Index action
return RedirectToAction("Index");
There are overloads for this method that allows you to pass route values and other information.
I have an edit form, that when posted, if successful should move on to the next record
Here is a snippet of the code in the controller:
if (issues.Count == 0)
{
Service.Save(item);
Service.SaveChanges();
return Edit(NextId, listingName);
}
else
{
ModelState.AddRuleViolations(issues);
}
return Edit(item.id, listingName);
The id for the next record is correctly passed to the action, but the autogenerated form still has the values of the old item, rather than the new one. I have debugged it and the item is getting loaded and passed to the view fine.
Try to do a RedirectToAction instead of returning the View directly.
return RedirectToAction("Edit", new { id = NextId, listingName = listingName });
Also, you are sending the same value of listingName in both cases (validation error and success). Is this correct?
Have you tried to return the Edit View explicitly instead of returning the method call?
Like so:
return View("Edit", NextId);
Perhaps it is still containing the old posted values and tries to repopulate the model accordingly...