I want to return to the same page in the page list after save. But now after save it will return to page 1 and not return to page 2, or 3..etc - where the item is that I selected.
I try it like this:
if (SaveDbChanges())
{
// Record an audit trail event for an updated product.
{
ATEvent atEvent = AuditTrailHelper.NewEvent(ATEventType.ProductUpdated, HttpContext, db.Schema, entry.Product);
atEvent.StringArg = entry.Product.Name;
ATEventLogger.Current.LogEvent(atEvent);
}
AddDelayedNotification(Resources.Entity.Environment.ItemSavedMessage, Notification.NotificationType.Success);
return RedirectToAction("Index", new { id = entry.Product.Id });
}
So it has to go back to the Index view but then page number 2 in this case. But it goes back to Index view but then on page 1.
Thank you
I try it like this:
Index view:
<i class="fa fa-fw fa-edit"></i> #Resources.Action.Navigation.Edit
and index method(post):
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Edit(EditProductModel entry, int page)
{
entry.Product.ModificationDate = DateTime.UtcNow;
if (ModelState.IsValid)
{
db.Entry(entry.Product).State = EntityState.Modified;
db.Entry(entry.Product).Property(model => model.Guid).IsModified = false;
db.Entry(entry.Product).Property(model => model.CreationDate).IsModified = false;
db.Entry(entry.Product).Property(model => model.IsProduction).IsModified = false;
entry.Product.IsProduction = StateHelper.IsTestMode() ? false : true;
HandleProductSelections(entry.Product);
SerializeAuthenticationSettings(entry);
SerializePaymentSettings(entry);
SerializeConnectors(entry);
SerializePrefillMappings(entry);
if (SaveDbChanges()) {
// Record an audit trail event for an updated product.
{
ATEvent atEvent = AuditTrailHelper.NewEvent(ATEventType.ProductUpdated, HttpContext, db.Schema, entry.Product);
atEvent.StringArg = entry.Product.Name;
ATEventLogger.Current.LogEvent(atEvent);
}
AddDelayedNotification(Resources.Entity.Environment.ItemSavedMessage, Notification.NotificationType.Success);
//return RedirectToAction("Index", new { id = entry.Product.Id });
//return RedirectToAction("Index", HttpContext.Request.UrlReferrer.AbsoluteUri);
//return Redirect(HttpContext.Request.UrlReferrer.AbsoluteUri);
//return Redirect(Request.UrlReferrer.ToString());
return RedirectToAction("Index", new { page = page });
}
}
AddDelayedNotification(Resources.Entity.Environment.ItemNotSavedError, Notification.NotificationType.Error);
return Edit(entry.Product.Id,2,2);
}
and get:
public ActionResult Edit(int? id, int ID, int page)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Product product = db.Products.Find(id);
if (product == null)
{
throw new HttpException((int) HttpStatusCode.NotFound, null);
}
SetCreateEditProductLists(product, customerSchema);
EditProductModel editModel = new EditProductModel();
editModel.Product = product;
editModel.Db = db;
//editModel.AuthenticationProviders = AuthenticationProviders.GetProviders(customerSchema);
//editModel.PaymentProviders = PaymentProviders.GetProviders(customerSchema);
//editModel.ConnectorProviders = ConnectorProviders.GetProviders(customerSchema);
DeserializeAuthenticationSettings(editModel);
DeserializePaymentSettings(editModel);
DeserializeConnectors(editModel);
DeserializePrefillMappings(editModel);
ViewBag.Model = editModel;
ViewBag.CurrentPage = page;
return View(editModel);
}
But if I do this:
<i class="fa fa-fw fa-plus"></i> #Resources.Entity.Product.EditProduct
I get this message:
The parameters dictionary contains a null entry for parameter 'page' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Edit(System.Nullable`1[System.Int32], Int32, Int32)' in ''. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
My edit looks now like this:
[HttpGet]
public ActionResult Edit(int? id, int page)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Product product = db.Products.Find(id);
if (product == null)
{
throw new HttpException((int) HttpStatusCode.NotFound, null);
}
SetCreateEditProductLists(product, customerSchema);
EditProductModel editModel = new EditProductModel();
editModel.Product = product;
editModel.Db = db;
//editModel.AuthenticationProviders = AuthenticationProviders.GetProviders(customerSchema);
//editModel.PaymentProviders = PaymentProviders.GetProviders(customerSchema);
//editModel.ConnectorProviders = ConnectorProviders.GetProviders(customerSchema);
DeserializeAuthenticationSettings(editModel);
DeserializePaymentSettings(editModel);
DeserializeConnectors(editModel);
DeserializePrefillMappings(editModel);
ViewBag.Model = editModel;
ViewBag.CurrentPage = page;
return View(editModel);
}
and my post like this:
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Edit(EditProductModel entry, int page)
{
entry.Product.ModificationDate = DateTime.UtcNow;
if (ModelState.IsValid)
{
db.Entry(entry.Product).State = EntityState.Modified;
db.Entry(entry.Product).Property(model => model.Guid).IsModified = false;
db.Entry(entry.Product).Property(model => model.CreationDate).IsModified = false;
db.Entry(entry.Product).Property(model => model.IsProduction).IsModified = false;
entry.Product.IsProduction = StateHelper.IsTestMode() ? false : true;
HandleProductSelections(entry.Product);
SerializeAuthenticationSettings(entry);
SerializePaymentSettings(entry);
SerializeConnectors(entry);
SerializePrefillMappings(entry);
if (SaveDbChanges()) {
// Record an audit trail event for an updated product.
{
ATEvent atEvent = AuditTrailHelper.NewEvent(ATEventType.ProductUpdated, HttpContext, db.Schema, entry.Product);
atEvent.StringArg = entry.Product.Name;
ATEventLogger.Current.LogEvent(atEvent);
}
AddDelayedNotification(Resources.Entity.Environment.ItemSavedMessage, Notification.NotificationType.Success);
return RedirectToAction("Index", new { page = page });
}
}
AddDelayedNotification(Resources.Entity.Environment.ItemNotSavedError, Notification.NotificationType.Error);
return Edit(entry.Product.Id,92);
}
and my Edit view like this:
#using (Html.BeginForm(new { page = ViewBag.CurrentPage })) {
#Html.AntiForgeryToken()
Oke, I solved, like this:
public ActionResult Edit(int? id, int? page)
both in get and post method. but page is always null
The problem is if I do this:
[HttpGet]
public ActionResult Edit(int? id, int? page)
{
ViewBag.CurrentPage = 2;
it will always return to the second page
Why it works if I do it hardcode, like this: ViewBag.CurrentPage = 2;
but if I do this: ViewBag.CurrentPage = page; then every time page is null
Thank you
The most efficient way of getting back to page 2 (or 3,4,5) would be to add a hidden variable to your edit page with the page number in it. You will have to keep passing the page number to every page after the index page and use it when you need it.
Another thing that you could do, which will put a lot of strain on your database would be to retrieve a list of all the items, then count where your productID is in the list and then calculate which page it should be on, then go to that page:
var ProductIds = db.Products.Select(x=>x.ProductId).ToArray();
int MyProductIndex = ProductIds.IndexOf(id);
int itemsperpage = 30;//or whatever the number of items per page
var pagenum = Math.Ceiling(myproductIndex/itemsperpage);
I solved like this:
in the Index I added:
var id = Session["id"];
Session["id"] = id;
Related
I'm new to MVC. In the view I am trying to send the assetId and the libraryId from the view to the controller however the libraryId is not picking up, I have tried to find a solution but not having any luck
In the View
#using
(Html.BeginForm("PlaceCheckout",
"Catalog", FormMethod.Post))
{
#Html.HiddenFor(a=>a.AssetId)
<div>
Please insert a Library Card ID.
#Html.TextBoxFor(a => a.LibraryCardId)
</div>
div>
<button type="submit" class="btn btn-success btn-lg">Check out</button>
</div>
}
Controller Code, LibraryCardId is left out and is set when the user inputs an ID for that card
public ActionResult Checkout(int id)
{
var asset = AssetService.Instance.GetByID(id);
var model = new CheckoutModel
{
AssetId = id,
ImageUrl = asset.ImageUrl,
Title = asset.Title,
LibraryCardId = "",
IsCheckedOut = CheckOutService.Instance.IsCheckedOut(id)
};
return View(model);
}
[HttpPost]
public ActionResult PlaceCheckout(int assetId, int libraryId)
{
CheckOutService.Instance.CheckoutItem(assetId, libraryId);
return RedirectToAction("Details", new { id = assetId });
}
These are my extension methods
public void CheckoutItem(int id, int libraryCardId)
{
using( var context = new LibraryContext())
{
if (IsCheckedOut(id))
return;
var item = context.LibraryAssets.Include(a => a.Status).First(a => a.Id == id);
context.Entry(item).State = EntityState.Modified;
UpdateAssetStatus(id, "Available");
var now = DateTime.Now;
var libraryCard = context.LibraryCards.Include(c => c.Checkouts).FirstOrDefault(c => c.Id == libraryCardId);
var checkout = new Checkout
{
LibraryAsset = item,
LibraryCard = libraryCard,
Since = now,
Until = GetDefaultCheckoutTime(now)
};
context.Checkouts.Add(checkout);
var checkoutHistory = new CheckoutHistory
{
CheckedOut = now,
LibraryAsset = item,
LibraryCard = libraryCard
};
context.CheckoutHistories.Add(checkoutHistory);
context.SaveChanges();
}
Your view (#Html.TextBoxFor(a => a.LibraryCardId)) is sending LibraryCardId not libraryId and your controller PlaceCheckout action is expecting two non-nullable parameters - assetId and libraryId (public ActionResult PlaceCheckout(int assetId, int libraryId)). You are getting the exception because libraryId is not supplied.
Please modify your controller PlaceCheckout action to take in LibraryCardId as below:
[HttpPost]
public ActionResult PlaceCheckout(int assetId, string libraryCardId )
{
// This extension method takes int version of libraryCardId
// So, am really not sure the datatype of libraryCardId
CheckOutService.Instance.CheckoutItem(assetId, libraryCardId );
return RedirectToAction("Details", new { id = assetId });
}
From the other action Checkout that you pasted here, I see that libraryCardId is string. So, have updated data type of second parameter of PlaceCheckout action. but your extension method says, libraryCardId is int. So, am really not sure about the data type of libraryCardId. So, please fix it accordingly.
I'm currently having an issue with my RedirectToAction redirecting to the Dispose() method included in a generated controller. I'm not sure why it's going to this method instead of the one I specified. What I'm trying to do is add an entry to one of my models (OwnGame, which is succeeds at) then I want to redirect to an action result that deletes those entries from a previous model/table (Cart) once they've been added to the Model/DB Table I mentioned. Below is the first action result which adds then redirects.
//GET: OwnGame/Create
[CustomAuthorize(Roles = "Member")]
public ActionResult Create(string userEmail)
{
List<int> GameIDs = new List<int>();
GameIDs = (List<int>)TempData["CheckoutGameIDs"];
ViewBag.Email = userEmail;
for (int i = 0; i < GameIDs.Count; i++)
{
ViewBag.GameID = GameIDs[i];
OwnGame ownedGames = new OwnGame();
ownedGames.Email = userEmail;
ownedGames.GameID = GameIDs[i];
db.OwnGames.Add(ownedGames);
db.SaveChanges();
}
return RedirectToAction("EmptyCart");
}
And if it's relevant I've included the method I wanted to redirect to but it's failing.
public ActionResult EmptyCart(string userEmail)
{
var cartItems = db.Carts.Where(o => o.Email.Contains(userEmail));
foreach (Cart singleItem in cartItems)
{
Cart cartSingleItem = db.Carts.Find(singleItem.CartID);
db.Carts.Remove(cartSingleItem);
}
db.SaveChanges();
return RedirectToAction("Index", new { userEmail = userEmail });
}
Also I haven't done anything to the Dispose() method, it's standard. All of this is supposed to be taking place in the same controller.
Because the EmptyCart has a parameter and you have to specify it's value when you call it from RedirectToAction:
return RedirectToAction("EmptyCart", new { userEmail = "" });
Or as an alternative, you can make that parameter optional:
public ActionResult EmptyCart(string userEmail = "")
{
var cartItems = db.Carts.Where(o => o.Email.Contains(userEmail));
....
....
}
I have below controllers:
// GET: /MaterialPaymentRequestSbuItem/CreateChild
public ActionResult CreateChild(int? parentId)
{
if (parentId==null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var parenetRequest = (from request in db.MaterialPaymentRequests
where request.Id==(int)parentId
select request);
ViewBag.MaterialPaymentRequestId = new SelectList(parenetRequest, "Id", "Description", (int)parentId);
ViewBag.ParentID = parentId;
if (parenetRequest!=null && parenetRequest.First()!=null)
ViewBag.ParentTitle = parenetRequest.First().Description;
return View();
}
// POST: /MaterialPaymentRequestSbuItem/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateChild([Bind(Include = "Id,Name,Unit,UnitPrice,MaterialPaymentRequestId,Quantity")] MaterialPaymentRequestSubItem materialpaymentrequestsubitem)
{
if (ModelState.IsValid)
{
try
{
db.MaterialPaymentRequestSubItems.Add(materialpaymentrequestsubitem);
db.SaveChanges();
}
catch (Exception e)
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
updateTotalPriceOfParentPaymentRequest(db, db.MaterialPaymentRequests.Find(materialpaymentrequestsubitem.MaterialPaymentRequestId));
return RedirectToAction("List", new { id = materialpaymentrequestsubitem.MaterialPaymentRequestId });
}
ViewBag.MaterialPaymentRequestId = new SelectList(db.PaymentRequests, "Id", "Description", materialpaymentrequestsubitem.MaterialPaymentRequestId);
//need to becheked
ViewBag.ParentID = materialpaymentrequestsubitem.MaterialPaymentRequestId;
if (Request != null && Request["parentID"] != null)
{
try
{
int id = Int32.Parse(Request["parentID"]);
ViewBag.ParentTitle = db.MaterialPaymentRequests.Find(id).Description;
}
catch(Exception e)
{
}
}
return View(materialpaymentrequestsubitem);
}
My main problem is that user is allowed to select model.MaterialPaymentRequestId from drop-down and he/she may leave it with no value selected. MaterialPaymentRequestId is used in first controller (befor post) to find Parent title from db and pass it to view using ViewBag, however if user does not select MaterialPaymentRequestId dropdown items, after postback, I lost MaterialPaymentRequestId. Currently I read Request variable and look inside url to find parameters to lookup for parentID.
My url calls are like http://localhost:46813/Admin/MaterialPaymentRequestSbuItem/CreateChild?parentId=23.
However this practice seems like a bad practice than I cannot pass v variable between two controller methods a process like this:
Controller method(get) ---> View ---> Controller method(post)
Currently I feel a bit stuck in MVC!
i hope i got your point right, you can use an #Html.hiddenfor(model => model.ParentId) in your view it will store ParentId value from query string and when user submits form will be posted to POST method so you dont need to look into url to get it. use a viewmodel with ParentId property and do as below
public class MaterialPaymentsViewModel {
//other properties
public int ParentId {get;set;}
}
public ActionResult CreateChild(int? parentId)
{
var model = new MaterialPaymentsViewModel{ParentId = parentId};
//other stuff
return View(model);
}
//View
#using (Html.beginform()){
//
#html.hiddenfor(m => m.ParentId)
//submit
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateChild(MaterialPaymentsViewModel model)
{
if(model.ParentId != null)
{
//
}
//
}
I have this controller:
[Authorize]
public class CheckoutController : Controller
{
ShoppingCartContext storeDB = new ShoppingCartContext();
const string PromoCode = "FREE";
[HttpPost]
public ActionResult AddressAndPayment(FormCollection values)
{
var order = new Order();
TryUpdateModel(order);
try
{
if (string.Equals(values["PromoCode"], PromoCode,
StringComparison.OrdinalIgnoreCase) == false)
{
return View(order);
}
else
{
order.Username = User.Identity.Name;
order.OrderDate = DateTime.Now;
//Save Order
storeDB.Orders.Add(order);
storeDB.SaveChanges();
//Process the order
var cart = Models.ShoppingCart.GetCart(this.HttpContext);
cart.CreateOrder(order);
return RedirectToAction("Complete",
new { id = order.OrderId });
}
}
catch
{
//Invalid - redisplay with errors
return View(order);
}
}
public ActionResult Complete(int id)
{
// Validate customer owns this order
bool isValid = storeDB.Orders.Any(
o => o.OrderId == id &&
o.Username == User.Identity.Name);
if (isValid)
{
return View(id);
}
else
{
return View("Error");
}
}
}
And I have created a View called AddressAndPayment under Checkout, so it goes to localhost/Checkout/AddressAndPayment but I only get a 404 error, even if I right click on the View and click on view in Page Inspector. I don't know why its not even showing the view when it is created.
You need a corresponding HttpGet method, as your current one only accepts a HttpPost request. Add the following:
[HttpGet]
public ActionResult AddressAndPayment()
{
return View();
}
Here is an example method I have that deletes a record from my app:
[Authorize(Roles = "news-admin")]
public ActionResult Delete(int id)
{
var ArticleToDelete = (from a in _db.ArticleSet where a.storyId == id select a).FirstOrDefault();
_db.DeleteObject(ArticleToDelete);
_db.SaveChanges();
return RedirectToAction("Index");
}
What I would like to do is show a message on the Index view that says something like: "Lorem ipsum article has been deleted" how would I do this? Thanks
Here is my current Index method, just in case:
// INDEX
[HandleError]
public ActionResult Index(string query, int? page)
{
// build the query
var ArticleQuery = from a in _db.ArticleSet select a;
// check if their is a query
if (!string.IsNullOrEmpty(query))
{
ArticleQuery = ArticleQuery.Where(a => a.headline.Contains(query));
//msp 2011-01-13 You need to send the query string to the View using ViewData
ViewData["query"] = query;
}
// orders the articles by newest first
var OrderedArticles = ArticleQuery.OrderByDescending(a => a.posted);
// takes the ordered articles and paginates them using the PaginatedList class with 4 per page
var PaginatedArticles = new PaginatedList<Article>(OrderedArticles, page ?? 0, 4);
// return the paginated articles to the view
return View(PaginatedArticles);
}
One way would be to use TempData:
[Authorize(Roles = "news-admin")]
public ActionResult Delete(int id)
{
var ArticleToDelete = (from a in _db.ArticleSet where a.storyId == id select a).FirstOrDefault();
_db.DeleteObject(ArticleToDelete);
_db.SaveChanges();
TempData["message"] = ""Lorem ipsum article has been deleted";
return RedirectToAction("Index");
}
and inside the Index action you could fetch this message from TempData and make use of it. For example you could pass it as a property of your view model which will be passed to the view so that it can show it:
public ActionResult Index()
{
var message = TempData["message"];
// TODO: do something with the message like pass to the view
}
UPDATE:
Example:
public class MyViewModel
{
public string Message { get; set; }
}
and then:
public ActionResult Index()
{
var model = new MyViewModel
{
Message = TempData["message"] as string;
};
return View(model);
}
and inside the strongly typed view:
<div><%: Model.Message %></div>