Passing viewmodel from one method to another (post) - asp.net-mvc

I have a wizardtype form where i would like to keep the model from the first step to the last.
This is how im doing it now, but i cant seem to keep the model from step 3 to 4.
[HttpPost]
public ActionResult Register(MemberViewModel model)
{
var mobile = model.Mobile;
var xml = MemberclubHelper.CreateVerificationTokenXML(mobile, "47");
MemberclubHelper.SendVerificationToken(xml);
return RedirectToAction("RegisterStep1", new { mobile = mobile });
}
public ActionResult RegisterStep1(string mobile)
{
var model = new MemberViewModel();
model.Mobile = mobile;
return View("Register/Step1", model);
}
[HttpPost]
public ActionResult RegisterStep1(MemberViewModel model)
{
var interests = (from interest in model.Interests where interest.isChecked select interest.value).ToList();
var passing = (from pass in model.Passing where pass.isChecked select pass.value).ToList();
var xml = MemberclubHelper.CreateMemberProfileXML(model.Mobile, model.FirstName, model.FirstName,
model.Email1, model.Zipcode, model.SelectedKid1, model.SelectedKid2, model.SelectedKid3,
model.Gender.ToString(), interests, passing);
model.XmlToSend = xml;
if (xml.Contains("error"))
{
model.ErrorMessage = xml;
return View("Register/Step1", model);
}
return View("Register/Step2", model);
}
[HttpPost]
public ActionResult RegisterStep2(MemberViewModel model)
{
var result = MemberclubHelper.SendCreateUser(model.XmlToSend, model.Password);
if (result.Contains("error"))
{
model.ErrorMessage = result;
return View("Register/Step2", model);
}
else
{
return View("Register/Finished");
}
}

I think you may be better served by creating a separate view model for each step (i.e., MemberViewModelStep1). To me this seems like only some of your MemberViewModel properties will will be set in each step unless you carry a lot of that state between steps via hidden inputs or some other mechanism.
Alternatively, have you considered using JavaScript to build up that state between across your steps and then submitting a single post with your fully populated MemberViewModel?

Related

IEnumerable<Twitter Status> View Output MVC 5

I am trying to output a set of tweets with a certain hashtag.
I have the following code in the controller:
public ActionResult Test() {
var service = new TwitterService("xxx", "xxx");
service.AuthenticateWith("xxx", "xxx");
var options = new SearchOptions { Q = "#test" };
TwitterSearchResult tweets = service.Search(options);
IEnumerable<TwitterStatus> status = tweets.Statuses;
ViewBag.Tweets = status;
//var tweets = service.Search(options);
return View();
}
I want to output the results that are in the IEnumerable in a view.
But I am finding it difficult to output these results in a view. Can anyone help please?
Your question is a bit vague but I think I understand your problem.
You'll want to pass the data into your view from your action.
public ActionResult Test() {
var service = new TwitterService("xxx", "xxx");
service.AuthenticateWith("xxx", "xxx");
var options = new SearchOptions { Q = "#test" };
TwitterSearchResult tweets = service.Search(options);
IEnumerable<TwitterStatus> status = tweets.Statuses;
//var tweets = service.Search(options);
return View(status);
}
Notice I pass in the status object into the view.
Now in your view you can just bind that object.
#model IEnumerable<TwitterStatus>
#foreach(var status in Model){
<div>
#status.Id #*Id is an exmaple property. Use the actual properties inside "TwitterStatus"*#
</div>
}
Edit:
If you want to have multiple things inside your page you'll have to use Partial Views.
You'll need a view that will encompass all your other partial views. To do this, just define a action for your twitter info that will be your parent view.
public ActionResult AllInfo() {
return View();
}
Then your razor:
//AllInfo.cshtml
#Html.Action("Test", "YourController")
In AllInfo.cshtml we call the action "Test" inside "YourController". We'll change "Test" to return a PartialView instead of a View.
public ActionResult Test() {
var service = new TwitterService("xxx", "xxx");
service.AuthenticateWith("xxx", "xxx");
var options = new SearchOptions { Q = "#test" };
TwitterSearchResult tweets = service.Search(options);
IEnumerable<TwitterStatus> status = tweets.Statuses;
return PartialView(status);
}
The razor stays the same for your partial view:
//Test.cshtml
#model IEnumerable<TwitterStatus>
#foreach(var status in Model){
<div>
#Model.Id #*Id is an exmaple property. Use the actual properties inside "TwitterStatus"
</div>
}
You can call #Html.Action() as many times as you want in your AllInfo.cshtml page and add all the PartialViews you need.

MVC, cannot return to the previous URL

I am working on some legacy code.
I have a form which I edit some data and when I click save, if successful I want to return to the previous form.
So my controller methods are;
public ActionResult Edit(int callDiaryId)
{
ViewBag.PreviousUrl = System.Web.HttpContext.Current.Request.UrlReferrer;
var callDiary = this.SCDCallDiaryRepository.Get(callDiaryId);
return this.View("Edit", new DiaryItemViewModel(callDiary));
}
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateOnlyIncomingValuesAttribute]
public ActionResult Edit(DiaryItemViewModel item, string previousUrl)
{
var callDiary = this.SCDCallDiaryRepository.Get(item.SCD_CallDiaryId);
callDiary.Comments = item.Comments;
callDiary.ContractId = item.ContractId;
var opStatus = this.SCDCallDiaryRepository.Update(callDiary);
if (opStatus.Status)
{
this.TempData["SuccessMessage"] = "Details updated successfully.".MessageTime();
return RedirectToAction(previousUrl);
}
this.TempData["ErrorMessage"] = "Details NOT updated.".MessageTime();
ViewBag.PreviousUrl = previousUrl;
return this.View(new DiaryItemViewModel(callDiary));
}
and the incoming value of previousUrl is
http://localhost:58384/LogDiary/Comments?companyId=11033
This works perfectly for my back button.
But after my RedirectToAction command is performed, the Bad Request error that I get is because the Url it is showing is;
http://localhost:58384/LogDiary/http%3a/localhost%3a58384/LogDiary/Comments%3fcompanyId%3d11033
How do I fix this?
I was able to do this in the Controller of my App to return the user to the previous page
public ActionResult ChangePassword()
{
var userId = this.User.Identity.GetUserId();
var viewModel = this._userService.ChangePasswordViewModelForUser(userId);
viewModel.PreviousPage = this.Request.UrlReferrer.AbsoluteUri;
return this.View(viewModel);
}
If I need to use it in a button
#Resource.Button_Cancel
I think I found the answer.
Instead of using RedirectToAction, I am now using Redirect.
You can return to the previous form by doing the below code
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateOnlyIncomingValuesAttribute]
public ActionResult Edit(DiaryItemViewModel item)
{
..your other code..
return View(item);
}
it will return to the Edit page along with the entered data
hope this helps

Edit & Delete object with ViewModel

I've successfully implemented a viewmodel so I can create and return items from my database using two tables. My issue is editing and deleting individual items.
I was able to edit/delete when I was using just one table, but with two, i've run into a snag.
My view uses a viewmodel now. I am not able to figure out how to pass the specific object id when Passing an id and TransactionViewModel Viewmodel into my Edit method Parameters.
Here is my old Edit and Edit post.
public ActionResult Edit(int id = 0)
{
Transactions transactions = _db.Transactions.Find(id);
if (transactions == null)
{
return HttpNotFound();
}
return View(transactions);
}
[HttpPost]
//[ValidateAntiForgeryToken]
public ActionResult Edit(TransactionViewModel viewModel)
{
var transactionType = viewModel.Transaction.TransactionType;
if (ModelState.IsValid)
{
//If the transaction category is an Expense, set it to a negative so we can calculate later.
if (transactionType == Classes.Constants.Expense || (transactionType == Classes.Constants.Payment && viewModel.Transaction.Amount < 0))
{
viewModel.Transaction.Amount *= -1;
}
var transaction = new Transactions()
{
ClientId = viewModel.Transaction.ClientId,
Amount = viewModel.Transaction.Amount,
Date = viewModel.Transaction.Date,
Category = viewModel.Transaction.Category,
Description = viewModel.Transaction.Description,
TransactionType = viewModel.Transaction.TransactionType
};
_db.Entry(transaction).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
I've tried this for my get Edit, but it returns the same thing each time and not the one specified on my view. Ex. If click edit for Client D, it will pull up the edit screen for Client A and I cannot save it. I have an edit and delete button in my viewable table next to each transaction using an #Html.ActionLink().
public ActionResult Edit(TransactionViewModel viewModel)
{
if (ModelState.IsValid)
{
var transactions = from t in _db.Transactions
join c in _db.Clients
on t.ClientId equals c.ClientId
select new TransactionViewModel() { Clients = c, Transaction = t };
return View(transactions.FirstOrDefault());
}
return RedirectToAction("Index");
}
Any help would be appreciated. Thanks!
I bet that view is being cached. There are many different ways to influence caching in the controller. If you want to simply remove cacheing, in your case for editing, then decorate that action with the following:
[OutputCache(NoStore = true, Duration = 0)]
public ActionResult Edit(TransactionViewModel viewModel)
[OutputCache(NoStore = true, Duration = 0)]
public ActionResult Edit(int id = 0)
Note: You will have to clear cache to get the new view with the no cache set above.
Your Get Edit method should still accept an int ID to select the correct record form the database and it should return the view model.
something like this:
public ActionResult Edit(int id = 0)
{
var transactions = from t in _db.Transactions
join c in _db.Clients
on t.ClientId equals c.ClientId
where t.id == id
select new TransactionViewModel() { Clients = c, Transaction = t };
return View(transactions.FirstOrDefault());
}

Asp Net MVC with VM is this good practice? (Code Sample) [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I'm wondering if what I have here is good practice. Using Entity Framework Code First with MVC and View Models.
Below i have code for List, Create, Edit and Delete. Model name Page and 2 ViewModels name ContentViewModel and ContentListViewModel.
private readonly IUserService _userService;
//private readonly MembershipProvider _members;
public ContentController()
{
// _members = Membership.Provider;
_userService = new AspNetMembershipProviderWrapper();
}
//
// GET: /Profile/Content/
public ActionResult Index()
{
using (var db = new BlogContext())
{
IEnumerable<Page> pages;
pages = db.ArticlePages.ToList();
List<ContentListViewModel> model = new List<ContentListViewModel>();
foreach (Page pg in pages)
{
MembershipUser user = _userService.Get(pg.authorId);
model.Add(new ContentListViewModel()
{
PageID = pg.pageID,
UserName = user.UserName,
UserID = (Guid)user.ProviderUserKey,
IsFrontPage = pg.frontpage,
isPublished = pg.published,
PageTitle = pg.titleHeading,
PageUrlName = pg.idName,
PublishedDate = pg.datentime
});
}
return View(model);
}
}
//
// GET: /Profile/Content/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Profile/Content/Create
[HttpPost]
public ActionResult Create(ContentViewModel page)
{
if (ModelState.IsValid)
{
using (var db = new BlogContext())
{
db.ArticlePages.Add(new Page()
{
authorId = (Guid)Membership.GetUser().ProviderUserKey,
datentime = DateTime.Now,
frontpage = page.FrontPage,
published = page.Published,
titleHeading = page.TitleHeading,
pageContent = page.Content,
idName = page.IdName
});
db.SaveChanges();
return RedirectToAction("Index").Success("Page added Successfully.");
}
}
return View(page);
}
//
// GET: /Profile/Content/Edit/5
public ActionResult Edit(int id = 0)
{
if (id == 0)
{
return RedirectToAction("Index").Error("Page Not found.");
}
Page pg = new Page();
using (var db = new BlogContext())
{
pg = (from m in db.ArticlePages where m.pageID == id select m).SingleOrDefault();
}
if (pg == null)
{
return RedirectToAction("Index").Error("Page Not found..");
}
return View(new ContentViewModel()
{
id = pg.pageID,
Content = pg.pageContent,
FrontPage = pg.frontpage,
Published = pg.published,
TitleHeading = pg.titleHeading,
IdName = pg.idName
});
}
// POST: /Profile/Content/Edit/5
[HttpPost]
public ActionResult Edit(ContentViewModel page)
{
if (ModelState.IsValid)
{
using (var db = new BlogContext())
{
var oPage = db.ArticlePages.Single(p => p.pageID == page.id);
oPage.frontpage = page.FrontPage;
oPage.idName = page.IdName;
oPage.pageContent = page.Content;
oPage.published = page.Published;
oPage.titleHeading = page.TitleHeading;
db.SaveChanges();
return RedirectToAction("Index").Success("Page updated");
}
}
return View(page);
}
//
// POST: /Profile/Content/Delete/5
[HttpPost]
public ActionResult Delete(int id)
{
using (var db = new BlogContext())
{
Page page = db.ArticlePages.Find(id);
db.ArticlePages.Remove(page);
db.SaveChanges();
return RedirectToAction("Index").Success("Page deleted");
}
}
I would like to know there are better ways of doing this?
While that method is certainly better than passing the entities directly to the view, I would suggest a number of improvements.
First, I would create a new business layer, and then create a facade class to retrieve your data. Then move all database access to this layer. Thus, you would end up with a call to the service layer rather than doing direct database access like you are doing above.
Second, you should look into using something like AutoMapper to map between your data entities and your view models.

View doesn't refresh after RedirectToAction is done

Here is my problem:
[HttpPost]
public ActionResult AddData(CandidateViewModel viewModel)
{
var newCandidateId = 0;
newCandidateId = this._serviceClient.AddCandidate(viewModel);
return RedirectToAction("DisplayCandidate",new {id=newCandidateId});
}
public ActionResult DisplayCandidate(int id)
{
var candidateViewModel= this._serviceClient.GetCandidate(id);
return View(candidateViewModel);
}
After filling the form viwemodel sends to server. After data were stored, flow is redirected to DisplayCandidate action and it goes there but page didn't refresh. I don't understand why! Help, please.
Because you are using Ajax Post
public ActionResult AddData(CandidateViewModel viewModel)
{
var newCandidateId = 0;
newCandidateId = this._serviceClient.AddCandidate(viewModel);
string ReturnURL = "/DisplayCandidate/"+newCandidateId;
return JSON(ReturnURL);
}
and in your Ajax Post Method:
Onsuccess(function(retURL){ window.location(retURL); })
This will take to the new Action and that Action will return View.
If you're using Ajax, return a script results to execute the navigation
instead of
return RedirectToAction("DisplayCandidate",new {id=newCandidateId});
try
var viewName = "/Path/ViewName";
var id = 1;
var urlNavigate = string.Format("location.href='{0}?id={1}'", viewName, id);
return new JavaScriptResult() { Script = urlNavigate };

Resources