Hi everyone I am trying to pass information between diferent page, but I don't know how.
I have this form with Html.ActionLink inside
<% using (Html.BeginForm("Save", "Envi"))
{%>
<%: Html.ValidationSummary(true)%>
<div class="editor-label">
<%: Html.Label("Description:")%>
</div>
<div class="editor-field">
<%: Html.TextBox("info", lp.Description)%>
...
<div>
<%: Html.ActionLink("Change Image", "ChangeImg", "Envi", new {id=lp}, new {id="cambio"})%>
...
<p>
<input type="submit" value="Save" name="<%= lp.Id %>"/>
</p>
<% } %>
<% } %>
When I click the Html.ActionLink I show other page (dialog with fancyBox) where I select an Image.
I want to pass all data from the Form to this page. Now when I show the form again I have the new data, no the old data.
How can I do that???
Thanks.
You are suggested to use TempData dictionary. This will be available for only the next request.
Quoting from MSDN:
An action method can store data in the controller's TempDataDictionary
object before it calls the controller's RedirectToAction method to
invoke the next action. The TempData property value is stored in
session state. Any action method that is called after the
TempDataDictionary value is set can get values from the object and
then process or display them. The value of TempData persists until it
is read or until the session times out. Persisting TempData in this
way enables scenarios such as redirection, because the values in
TempData are available beyond a single request.
Hope this gives your answer.
Ideally, I believe the form should submit to a single action.
So the controller may look like this:
public class HomeController : Controller
{
public ViewResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(ItemModel itemModel, string submit)
{
//I'm not sure why I need this but the fields display with empty results on my machine otherwise
ModelState.Clear();
if (submit == "edit")
{
this.TempData.Add("item", itemModel);
return View("ChangeImage", new ImageModel { ImageName = itemModel.ImageName });
}
else
{
//perform save here
return RedirectToAction("ViewAfterSavePerformed");
}
}
[HttpPost]
public ViewResult Image(ImageModel imageModel)
{
ItemModel itemModel = (ItemModel)this.TempData["item"];
itemModel.ImageName = imageModel.ImageName;
return View("Index", itemModel);
}
}
With the following view models:
public class ItemModel
{
public string Description { get; set; }
public string ImageName { get; set; }
}
public class ImageModel
{
public string ImageName { get; set; }
}
And the following views:
Index:
<h2>Index</h2>
#using (Html.BeginForm())
{
<p>Description: #Html.EditorFor(m => m.Description)</p>
<p>Image: #Html.EditorFor(m => m.ImageName)</p>
<input type="submit" name="submit" value="edit" />
<input type="submit" name="submit" value="save" />
}
Change Image:
<h2>ChangeImage</h2>
#using (Html.BeginForm("Image", "Home"))
{
<p>Image: #Html.EditorFor(m => m.ImageName)</p>
<input type="submit" name="submit" value="save image" />
}
Hopefully this should may sense even though i've used razor syntax.
Related
I have a jQueryUI tabbed html page, and in its content area for one of the tabs, I have put as follows:
<div id="tabs-1ua">
#RenderPage("~/Views/Admin/Create.cshtml")
</div>
The Create.cshtml page does correctly appear within my tab, however when I create the user (this view is a basic user creation page) and click the button, nothing happens. No user is created and no error is presented. The "this" html with the tabs is in a different controller which does not have any model associations. The user creation is inside the AdminController, pertinent methods shown below:
public ActionResult Create()
{
return View();
}
[HttpPost]
public async Task<ActionResult> Create(CreateModel model)
{
if (ModelState.IsValid)
{
AppUser user = new AppUser { UserName = model.Name, Email = model.Email};
IdentityResult result = await UserManager.CreateAsync(user,
model.Password);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
else
{
AddErrorsFromResult(result);
}
}
return View(model);
}
I put a breakpoint at the beginning of the Post method, but it was never hit when I accessed the create page from within my other page.
When I access this page directly and create a user, I get the expected behavior for new creation and validation. The model is as follows:
public class CreateModel
{
[Required]
public string Name { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
And the Create.cshtml view is as follows:
#model IdentityDevelopment.Models.CreateModel
#{ ViewBag.Title = "Create User";}
<h2>Create User</h2>
#Html.ValidationSummary(false)
#using (Html.BeginForm())
{
<div class="form-group">
<label>Name</label>
#Html.TextBoxFor(x => x.Name, new { #class = "form-control" })
</div>
<div class="form-group">
<label>Email</label>
#Html.TextBoxFor(x => x.Email, new { #class = "form-control" })
</div>
<div class="form-group">
<label>Password</label>
#Html.PasswordFor(x => x.Password, new { #class = "form-control" })
</div>
<button type="submit" class="btn btn-primary">Create</button>
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn btn-default" })
}
My questions are, is it possible to do what I am trying to do? If so what changes do I need to make in order to reuse the existing available code?
Thank you.
You may explcitly specify which action method the form should post to when submit button is clicked.
You can use this overload of Html.BeginForm method to do so.
public static MvcForm BeginForm(
this HtmlHelper htmlHelper,
string actionName,
string controllerName
)
So update your Create view.
#model IdentityDevelopment.Models.CreateModel
#using (Html.BeginForm("Create","Admin"))
{
#Html.TextBoxFor(x => x.Name, new { #class = "form-control" })
<button type="submit" class="btn btn-primary">Create</button>
}
Now nomatter where you include this view, it will always post to Admin/Create
You should move your create form into a partial view which you can then render with RenderPartial. Then in your parent html page form do an ajax post to the partial views controller that defines the create method. Then you can use your partial anywhere you like with the logic centralized into the partial views controller.
I am trying to add two numbers in MVC.
My requirement is "I have 2 text boxes in View from which I have to retrieve data to controller"
View :
#using (Html.BeginForm("Addition", "Addition", FormMethod.Post))
{
<input id="Text1" type="text" value=#ViewBag.a name="firstNum" />
<input id="Text2" type="text" value=#ViewBag.b name="secondNum" />
<input id="Text3" type="text" value=#ViewBag.result />
<input type="submit" value="Submit" />
}
Controller Name : Addition
Action Name: Addition
[HttpPost]
public ActionResult Addition(FormCollection fc)
{
string[] keyss = fc.AllKeys;
ViewBag.a = fc.Keys[0];
ViewBag.b = fc.Keys[1];
ViewBag.total = ViewBag.a + ViewBag.b;
return View();
}
Now, from this form collection I want to retrieve values of textboxes.
Thanks.
One of the powers of MVC is the model binder - which you are completely ignoring here. Create a view model to match the expected content of your view
public class AdditionViewModel
{
public int A { get; set; }
public int B { get; set; }
public int Result { get; set; }
}
Use this as the expected parameter in your action
[HttpPost]
public ActionResult Addition(AdditionViewModel model)
{
model.Result = model.A + model.B;
return View(model);
}
Then finally in your view
#model AdditionViewModel
#using (Html.BeginForm("Addition", "Addition", FormMethod.Post))
{
#Html.EditorFor(x => x.A)
#Html.EditorFor(x => x.B)
#Html.DisplayFor(x => x.Result)
<input type="submit" value="Submit" />
}
Assuming you get the data in to ur controller , afterwards you just add Addition view and use
#ViewBag.total simple or you also can use viewdata or tempdata in case if u required .
The better way is
[HttpPost]
public ActionResult Addition(int firstNum, int secondNum )
{
ViewBag.Result=firstNum+secondNum;
return View();
}
Make sure you are doing a Numeric validation at client side
I have a Fairly Complex Form that I need to post to my MVC controller.
Here is the View model which I initially pass to the view on creation:
public class EditViewModel
{
public Service service { get; set; }
public bool sms { get; set; }
public bool email { get; set; }
public string userId { get; set; }
}
Here is my View (simplified):
#model IList<Service_Monitor_Web_Interface.Models.ViewModels.EditViewModel>
#{
ViewBag.Title = "Configure User Notifications";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>#ViewBag.Title</h2>
#using (Html.BeginForm("Edit", "Users", FormMethod.Post, new { #class = "stdform stdform2", role = "form" }))
{
#Html.AntiForgeryToken()
<hr />
<p>
<label><u> Service:</u> </label>
<span class="field">
<u>Notification Methods:</u>
</span>
</p>
for (int i = 0; i < Model.Count; i++)
{
<p>
<label>#Model[i].service.Name</label>
<span class="field">
#Html.CheckBoxFor(model => model[i].sms)
SMS
#Html.CheckBoxFor(model => model[i].email)
Email
</span>
</p>
}
<br clear="all" /><br />
<p class="stdformbutton">
<button class="submit radius2">Save</button>
<input type="reset" class="reset radius2" value="Reset Form" />
</p>
}
And here is my Action method in my controller:
//
// POST: /Users/Edit
[HttpPost]
public ActionResult Edit(IList<EditViewModel> viewModel)
{
return View(viewModel);
}
How Can I bind my view model when receiving it on the controller?
Currently when I debug the action method receives a ViewModel which looks like so:
How can I get service and userId not to be null?
Note that in your helpers' lambdas, say in model => service.sms right part (service.sms) formally is not derived from the left part (model). That causes all name attributes of resulting inputs to be the same, and gives you request parameters that you did not expect.
The standard practice is to use for instaed of foreach in loop cases. That way name attributes for resulting html are generated correctly:
for(int i=0; i<Model.Count; i++)
{
<p>
<label>#Model[i].service.Name</label>
<span class="field">
#Html.CheckBoxFor(model => model[i].sms)
SMS
#Html.CheckBoxFor(model => model[i].email)
Email
</span>
</p>
}
Note that this requires Model to be of type implementing IList rather than IEnumerable.
Update. For other values, that do not have any UI for them, you can use hidden fields, so that they are not visible for the user and are nevertheless posted to the server:
<label>#Model[i].service.Name</label>
<span class="field">
#Html.CheckBoxFor(model => model[i].sms)
SMS
#Html.CheckBoxFor(model => model[i].email)
Email
#Html.HiddenFor(mode => model[i].userId)
#Html.HiddenFor(mode => model[i].service.Name)
...other field of service you want to be posted...
</span>
I'm having a problem with partial views. I have an index view of Announcements and I'm trying to add a partial view to create a new Announcement within the same page.
I can display the partial view, and submit the form to create a new record. The record gets submitted into the database, but when re-rendering the page, I get the error: Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper', {"Child actions are not allowed to perform redirect actions."} on my Html.Action statement in my index page.
I've been struggling to make this work, and have firstly changed the Html.Partial to a Html.Action statement as the controller methods weren't firing, then secondly, after I read that this error is because while rendering the page, .NET doesn't know what my redirect action is doing so automatically stops it, tried changing the Html.Action to Html.RedirectAction inside a code block, but still get the same error detailed above.
My model is quite simple:
public class Announcement
{
public Announcement()
{
AnnouncementDate = System.DateTime.Now;
}
[Key]
public int AnnouncementID { get; set; }
public string Title { get; set; }
public string Type { get; set; }
}
My Controller methods:
public ViewResult Index(string searchString, int? page)
{
var Announcements = from a in db.Announcements
select a;
if (!String.IsNullOrEmpty(searchString))
{
Announcements = Announcements.Where(s => (s.Title.ToUpper().Contains(searchString.ToUpper()) || s.AnnouncementText.ToUpper().Contains(searchString.ToUpper())));
}
Announcements = Announcements.OrderBy(s => s.Title);
int pageSize = 10;
int pageNumber = (page ?? 1);
return View(Announcements.ToPagedList(pageNumber, pageSize));
}
//
// GET: /Announcement/Create
public ActionResult Create()
{
Announcement announcement = new Announcement();
return PartialView(announcement);
}
//
// POST: /Announcement/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Announcement announcement)
{
if (ModelState.IsValid)
{
db.Announcements.Add(announcement);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(announcement);
}
Index.cshtml
#model PagedList.IPagedList<Project.Models.Announcement>
#using PagedList.Mvc;
#using PagedList;
#using (Html.BeginForm())
{
#Html.TextBox("SearchString", ViewBag.CurrentFilter as string, new { #class = "search-query", placeholder = "Search by name" })
<input type="submit" value="Search" class="btn" />
}
#item.Title
#item.Type
#Html.Action("Create"); // This is the line causing errors after I submit the Create form. Have tried changing to Html.RedirectAction
Create.cshtml:
#model Project.Models.Announcement
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.TextBoxFor(model => model.Title, new { #style = "width:250px" })
#Html.TextBoxFor(model => model.Type, new { #style = "width:250px" })
<input type="submit" value="Create" class="btn btn-small" />
}
After doing some testing locally...
You can keep
#Html.Action("Create")
However, you have to change one small thing. Define what action the POST points to in your form :)
#model Project.Models.Announcement
#using (Html.BeginForm("Create"))
{
#Html.AntiForgeryToken()
#Html.TextBoxFor(model => model.Title, new { #style = "width:250px" })
#Html.TextBoxFor(model => model.Type, new { #style = "width:250px" })
<input type="submit" value="Create" class="btn btn-small" />
}
Recently I posted a question about the html helper dropdownlist and got it working (here). But now I have decided it was alot smarter to switch to ModelView Patterns so I have acces to strongly typed methods in my views etc. What I did was I made some adjustments to the code in my other topic in the following way:
VacatureFormViewModel:
public class VacaturesFormViewModel
{
public Vacatures Vacature { get; private set; }
public SelectList EducationLevels { get; private set; }
public SelectList Branches { get; private set; }
public SelectList CareerLevels { get; private set; }
Repository repository;
// Constructor
public VacaturesFormViewModel(Vacatures vacature)
{
this.Vacature = vacature;
this.repository = new Repository();
this.EducationLevels = new SelectList(repository.GetAllEducationLevels(),"ID","Name",vacature.EducationLevels);
this.Branches = new SelectList(repository.GetAllBranches(),"ID","Name",vacature.Branches);
this.CareerLevels = new SelectList(repository.GetAllCareerLevels(), "ID", "Name", vacature.CareerLevels);
}
}
BanenController:
//
// GET: /Banen/Create
public ActionResult Create()
{
Vacatures vacature = new Vacatures();
return View(new VacaturesFormViewModel(vacature));
}
//
// POST: /Banen/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Vacatures vacatureToAdd)
{
if (ModelState.IsValid)
{
try
{
// TODO: Add insert logic here
repository.AddToVacatures(vacatureToAdd);
repository.SaveChanges();
// Return to listing page if succesful
return RedirectToAction("Index");
}
catch (Exception e)
{
return View();
}
}
}
And my Create.aspx view (part of it):
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<p>
<label for="Title">Title:</label>
<%= Html.TextBox("Title", Model.Vacature.Title) %>
<%= Html.ValidationMessage("Title", "*") %>
</p>
<p>
<label for="Content">Content:</label>
<%= Html.TextArea("Content", Model.Vacature.Content) %>
<%= Html.ValidationMessage("Content", "*") %>
</p>
<p>
<label for="EducationLevels">EducationLevels:</label>
<%= Html.DropDownList("EducationLevels", Model.EducationLevels)%>
<%= Html.ValidationMessage("EducationLevels", "*") %>
</p>
<p>
<label for="CareerLevels">CareerLevels:</label>
<%= Html.DropDownList("CareerLevels", Model.CareerLevels)%>
<%= Html.ValidationMessage("CareerLevels", "*")%>
</p>
<p>
<label for="Branches">Branches:</label>
<%= Html.DropDownList("Branches", Model.Branches)%>
<%= Html.ValidationMessage("Branches", "*")%>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
For guiding I have used the NerdDinner tutorial by ScottGu and I have read various topics here.
My question is if it is possible to let MVC ASP set my careerlevel, educationlevel and branche (dropdownlists) automatically as it currently is returning an ID string which is not what I want. When I change the creation of the SelectList to:
this.CareerLevels = new SelectList(repository.GetAllCareerLevels(), vacature.CareerLevels);
So without the "ID" and "Name" it does not save either (I guess it is still returned as a string in the post method, and not the object itself) and next to this, it lists in the view as: vacature.EducationLevels etc. So not the Names but the object itself is listed.
Final question
So, in short, my question is if it is possible to use this approach to set my branche, educationallevel and careerlevel. So not automatically?
In which case I still have to use things like:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection form)
{
Vacatures vacatureToAdd = new Vacatures();
// Retrieve the education level by its ID
if (!form["EducationLevels"].Equals(""))
{
Guid educationID = new Guid(form["EducationLevels"]);
vacatureToAdd.EducationLevels = repository.GetEducationLevelByID(educationID);
}
In my controller? Or are there other, smoother options.
Edited to use Guid:
With dropdownlists I use a slightly different approach. It might be possible to get your viewmodel working, but for me it is easier this way:
public class VacaturesFormViewModel
{
public IEnumerable<SelectListItem>EducationLevels{ get; set; }
public Guid EducationLevelID{ get; set; }
}
The EducationLevelID will have the selected id of your Dropdown.
This is the view:
<%= Html.DropDownList("EducationLevelID", Model.EducationLevels)%>
Controller
IEnumerable<SelectListItem> educationLevelList =
from level in GetLevelList()
select new SelectListItem
{
Text = level .Name,
Value = level.Uid.ToString()
};
model.EducationLevels = educationLevelList ;
I'm not for sure but I think you should create model binders. (David Hayden wrote an simple model binder)
You could bind educationID parameter automatically:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Guid? educationID, FormCollection form)
{
Vacatures vacatureToAdd = new Vacatures();
if (educationID != null)
{
vacatureToAdd.EducationLevels =
repository.GetEducationLevelByID(educationID.Value);
}