Within my layout page, I want to either show a Login box, OR the details about the logged in person.
<div>
#if (Request.IsAuthenticated)
{
#Html.ViewBag.UserDisplay
#Html.ActionLink("[Logout]", "LogoutUser", "User")
}
else
{
#Html.Partial("_Login")
}
<hr />
#RenderBody()
</div>
My login partial view:
#model BasicFinanceUI.Models.LoginModel
#using (Html.BeginForm("LoginUser", "User"))
{
#Html.ValidationSummary()
<p>
Username: #Html.TextBoxFor(x => x.Username)
Password: #Html.TextBoxFor(x => x.Password)
Remember Me: #Html.DropDownListFor(x => x.RememberMe, new[]
{
new SelectListItem() { Text = "Yes", Value = "true"},
new SelectListItem() {Text = "No", Value = "false"}
}, "Select")
<input type="submit" value="Login" />
#Html.ActionLink("[Register]", "Register", "User")
</p>
}
When I load the screen, and login, it works fine.
However, when I click 'Register', it loads the register screen. The login box is still visible in the Layout.
My registration screen is displayed:
#model BasicFinanceUI.Models.RegisterationModel
#{
ViewBag.Title = "Register";
Layout = "~/Views/Shared/SiteLayout.cshtml";
}
<h2>Register</h2>
#using (Html.BeginForm("Register", "User"))
{
<p>#Html.ValidationSummary()</p>
<p>Username: #Html.TextBoxFor(x => x.Username)</p>
<p>Password: #Html.PasswordFor(x => x.Password1)</p>
<p>Retype Password: #Html.PasswordFor(x => x.Password2)</p>
<p>Firstname: #Html.TextBoxFor(x => x.Firstname)</p>
<p>Surname: #Html.TextBoxFor(x => x.Surname)</p>
<p>Email: #Html.TextBoxFor(x => x.Email)</p>
<p><input type="submit" value="Register"/></p>
}
When I click the Register button, things go wrong.
I get the error:
The model item passed into the dictionary is of type
'BasicFinanceUI.Models.RegisterationModel', but this dictionary
requires a model item of type 'BasicFinanceUI.Models.LoginModel'.
It seems because there are two forms on the screen, they're getting mixed up. What am I doing wrong?
Related
I am having an form which insert a record whenever a post request is made,but the problem is that if someone clicks submit button more than 1 times than duplicate post request are made and at the end same records are getting inserted. I dont want to check that the record is already present or not because the record would be different always. I tried using ValidateAntiForgeryToken filter in controller but it is failing to validate the requests, Below is my View Code.
#using (Html.BeginForm("Create", "Home",FormMethod.Post,new { onkeydown = "return event.keyCode!=13" }))
{
#Html.AntiForgeryToken()
<div class="right-col">
#Html.TextBoxFor(model => model.Name, new { placeholder = "Name", #class = "small-box" })
</div>
<div class="left-col">Email Id :</div>
<div class="right-col">
#Html.TextBoxFor(model => model.EmailId, new { placeholder = "Email Id", #class = "small-box",id="resumeemailid" })
#Html.ValidationMessageFor(model => model.EmailId)
</div>
<div class="left-col">Address :</div>
<div class="right-col">
#Html.TextAreaFor(model => model.Address, new { placeholder = "Address", #class = "small-box" })
</div>
<div class="buttons resume-threebutton">
<input type="submit" id="register-button" class="gradient-btn" value="#T("Account.Passport.Register.Button.Upload", "Upload")" name="Command" />
<input type="submit" id="register-button" class="gradient-btn" value="#T("Account.Passport.Button.UploadandAdd", "Upload And Add New")" name="Command" />
<input type="button" id="register-button" class="gradient-btn" value="#T("Account.Passport.Register.Button.Cancel", "cancel")" name="register-button" onclick="location.href='#Url.Action("SelectTemplate", "CustomerTemplate")'" />
</div>
}
and below is my controller Post method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ProductModel model)
{
//To do add the product here...
}
One of the properties of my ViewModel is an array which, unfortunately, is null every time I post back to the controller. I figured a simple hack where I place the values into a coma-delimited string.
This works great for our paging plugin, which posts back to our Index method, using a RouteValueDictionary. However, it is not working in the Html.BeginForm helper which posts back to a different controller action (the Update method).
View
#*Since we can't send arrays or complex objects break array down into string for RouteValueDictionary*#
var channelCodes = "";
for (int i = 0; i < Model.searchChannelCode.Length; i++)
{
channelCodes += Model.searchChannelCode[i];
if (i + 1 < Model.searchChannelCode.Length)
{
channelCodes += ",";
}
}
#*The 'searchChannelCodesPagin' variable from this RouteValueDictionary always posts back as null
using (Html.BeginForm("Update", "ZipCodeTerritory", new RouteValueDictionary()
{
{"searchChannelCodesPaging", channelCodes }
}, FormMethod.Post, new {id = "UpdateForm"}))
{
#Html.HiddenFor(model => model.searchZip)
#Html.HiddenFor(model => model.searchTerritory)
#Html.HiddenFor(model => model.searchState)
#Html.HiddenFor(model => model.searchActiveOnly)
#Html.HiddenFor(model => model.zipCodeTerritory)
<div id="cloneBox">
<div id="rw1">
#Html.LabelFor(model => model.newTerritory)
#Html.TextBoxFor(model => model.newTerritory, new { style = "width: 30px;padding-left:10px;", maxLength = 3 })
#Html.LabelFor(model => model.newDescription)
#Html.TextBoxFor(model => model.newDescription, new { style = "width: 250px;padding-left:10px;", maxLength = 30 })
#Html.LabelFor(model => model.newEffectiveDate)
#Html.TextBoxFor(model => model.newEffectiveDate, new { style = "width: 80px;padding-left:10px;" })
<div id="rw2" style="padding-top: 10px;">
#Html.LabelFor(model => model.newChannelCode)
#Html.DropDownListFor(model => model.newChannelCode, Model.ChannelCodes, " ")
#Html.LabelFor(model => model.newStateCode)
#Html.DropDownListFor(model => model.newStateCode, Model.StateCodes, " ")
#Html.LabelFor(model => model.newEndDate)
#Html.TextBoxFor(model => model.newEndDate, new { style = "width: 80px;" })
</div>
</div>
</div>
<br/>
<div id="buttonDiv">
<button type="submit" id="CloneButton" name="button" value="clone">Apply New Data</button>
<button type="submit" id="deleteButton" name="button" value="delete">Delete Selected Items</button>
<button type="submit" id="removeButton" name="button" value="removeErrors">Remove Selected Errors</button>
</div>
}
Controller
The forma above posts to this controller action. The searchChannelCodePaging variable is null each time.
[HttpPost]
public ActionResult Update(ZipCodeIndex updateZip, string button, string searchChannelCodesPaging)
{
Since you are doing a post, the simplest way to get it to the backend would be add a hidden field:
#Html.HiddenFor("searchChannelCodesPaging", searchChannelCodesPaging);
As a routing value, you may need to get it explicitly within the control via one of the two following approaches. These objects are directly accessible within the Controller class.
RouteData.Values("searchChannelCodesPaging")
Request.QueryString.Get("searchChannelCodesPaging");
You don't have to serialize a array type model parameter to a CSV string to get it to post to your controller. You can do this instead:
#for (var i = 0; i < Model.searchChannelCode.Length; i++)
{
#Html.HiddenFor(m => m.searchChannelCode[i]);
}
I have a layout page, and want it to have a Login Box, OR display the logged in user, along with a Logout link.
At the moment, my SiteLayout.cshtml file has this:
<body>
<h1>Basic Finance</h1>
<div>
#if (Request.IsAuthenticated)
{
#Html.ViewBag.UserDisplay
#Html.ActionLink("[Logout]", "LogoutUser", "User")
}
else
{
#Html.Partial("_Login")
}
<hr />
#RenderBody()
</div>
</body>
Then, i my Views/Shared/, I have the _Login.cshtml file:
#model BasicFinanceUI.Models.LoginModel
#using (Html.BeginForm())
{
#Html.ValidationSummary()
<p>
Username: #Html.TextBoxFor(x => x.Username)
Password: #Html.TextBoxFor(x => x.Password)
Remember Me: #Html.DropDownListFor(x => x.RememberMe, new[]
{
new SelectListItem() { Text = "Yes", Value = "true"},
new SelectListItem() {Text = "No", Value = "false"}
}, "Select")
<input type="submit" value="Login" />
</p>
}
This code was moved from a standard view. I had it then there was simply a 'Login' link, instead of the login box in the Layout page. I want to display a login box instead.
My login code is still in a controller I created called 'UserController'. But, I have no idea how to tell my login box to use that controller. Is this the right way to do what I want (or should there be a controller for my login partial). Is it OK to use my 'UserController'? And if so, how?
Change:
#using (Html.BeginForm())
{
#Html.ValidationSummary()
<p>
Username: #Html.TextBoxFor(x => x.Username)
Password: #Html.TextBoxFor(x => x.Password)
Remember Me: #Html.DropDownListFor(x => x.RememberMe, new[]
{
new SelectListItem() { Text = "Yes", Value = "true"},
new SelectListItem() {Text = "No", Value = "false"}
}, "Select")
<input type="submit" value="Login" />
</p>
}
To:
#using (Html.BeginForm("Login", "User"))
{
#Html.ValidationSummary()
<p>
Username: #Html.TextBoxFor(x => x.Username)
Password: #Html.TextBoxFor(x => x.Password)
Remember Me: #Html.DropDownListFor(x => x.RememberMe, new[]
{
new SelectListItem() { Text = "Yes", Value = "true"},
new SelectListItem() {Text = "No", Value = "false"}
}, "Select")
<input type="submit" value="Login" />
</p>
}
Where "User" is your controller and "Login" is your action method that handles the Login's POST.
http://msdn.microsoft.com/en-us/library/dd492590(v=vs.118).aspx
I want to create a page that has a next button and previous button that switches the image displayed.
For that purpose I created an Ajax.BeginForm and inserted into it, an image and two submit buttons.
Can I (should I) have multiple submit buttons inside an Ajax.BeginForm?
How would the controller handle each submit separately?
Try this,
View
#model TwoModelInSinglePageModel.RegisterModel
#using (Ajax.BeginForm("DYmanicControllerPage", "Test", FormMethod.Post,null, new { id = "frmSignUp" }))
{
<div>
<input type="hidden" id="" name="hidden2" id="hdasd" />
#Html.HiddenFor(m => m.hidden1)
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
#Html.ValidationMessageFor(m => m.Name)
</div>
<br />
<div>
#Html.LabelFor(m => m.Address)
#Html.TextBoxFor(m => m.Address)
#Html.ValidationMessageFor(m => m.Address)
</div>
<br />
<div>
#Html.LabelFor(m => m.PhoneNo)
#Html.TextBoxFor(m => m.PhoneNo)
#Html.ValidationMessageFor(m => m.PhoneNo)
</div>
<input type="submit" value="Save" id="btnSave" name="ButtonType"/>
<input type="submit" value="Next" id="btnNext" name="ButtonType" />
}
Controller
[HttpPost]
public ActionResult DYmanicControllerPage(RegisterModel model, string ButtonType)
{
if(ButtonType == "Next")
{
// Do Next Here
}
if (ButtonType == "Save")
{
//Do save here
}
return JavaScript("REturn anything()");
}
I would recommend that you have two buttons and then depending on what button was clicked you could set the action on the form:
Razor
$(function (){
$("#btn-prev").click(function() {
$("#form").attr
(
"action",
"#Url.Action("Action", "Controller", new {area="Area" })",
).submit();
});
$("#btn-next").click(function() {
$("#form").attr
(
"action",
"#Url.Action("Action", "Controller", new {area="Area" })",
).submit();
});
});
I am using jQuery here to do this, but I think you can get the idea.
I had the same requirement/issue and tried both solutions here and they both work for me. I LIKE the idea of setting the action via jquery when clicking so I can keep my actions separate so they can be used by other views.
HOWEVER, I've found that when I do this while I debug, it posts TWICE and BOTH the OnSuccess and OnFailure are triggered. It only happens when debugging though. Keep this in mind when picking.
I've done some research on this and seem to find posts that are either outdated or don't quite work in my situation. I may be using wrong keywords when searching though... =/
On my web page I have Tabs containing Group boxes that contain Lines which in turn contain Items.
So it is lists of lists 4 levels.
The problem:
When posting back, ViewModel.Tabs is null and I can't save anything.
Everything displays quite nicely, but nothing is posted back.
The code
Views/Shared/EditorTemplates/Tab.cshtml
#model AWMCCRM.Web.ViewModels.Tab
#Html.HiddenFor(vm => vm.Name)
<div id="tab-#Model.Name.Replace(" ", string.Empty)" class="tab-content two">
#Html.EditorFor(vm => vm.Groups)
</div>
Views/Shared/EditorTemplates/Group.cshtml
#model AWMCCRM.Web.ViewModels.Group
#Html.HiddenFor(vm => vm.Name)
<fieldset>
<legend>#Model.Name</legend>
#Html.EditorFor(vm => vm.Lines)
</fieldset>
Views/Shared/EditorTemplates/Line.cshtml
#model AWMCCRM.Web.ViewModels.Line
<div class="_100Max">
#Html.HiddenFor(vm => vm.Name)
#Html.EditorFor(vm => vm.Items)
</div>
Views/Shared/EditorTemplates/Item.cshtml
#model AWMCCRM.Web.ViewModels.Item
<div class="_#Model.DisplaySize" title="#Model.Description">
<p>
#Html.HiddenFor(x => x.DataType)
#Html.HiddenFor(x => x.Description)
#Html.HiddenFor(x => x.DisplaySize)
#Html.HiddenFor(x => x.DisplayType)
#Html.HiddenFor(x => x.IDsPiped)
#Html.HiddenFor(x => x.ItemType)
#Html.HiddenFor(x => x.Name)
#Html.LabelFor(vm => vm.Value, Model.Name)
#switch (Model.DisplayType.ToLower().Replace(" ", string.Empty))
{
case "checkbox":
#Html.CheckBoxFor(vm => Convert.ToBoolean(vm.Value))
break;
case "dropdownlist":
#Html.DropDownListFor(vm => vm.Value, Model.ValueOptionListItems)
break;
case "multiselectlist":
#Html.ListBoxFor(
x => x.SelectedValueList,
Model.ValueOptionListItems,
new { id = "itemValuesMultiSelect", multiple = "multiple", Size = 15 })
break;
case "radiobutton":
#Html.RadioButtonFor(vm => vm.Value, Model.Value)
break;
case "textarea":
#Html.TextAreaFor(vm => vm.Value)
break;
default:
#Html.TextBoxFor(vm => vm.Value)
break;
}
</p>
</div>
The ViewModel (cut down version)
namespace AWMCCRM.Web.ViewModels
{
public class PersonEditViewModel
{
public List<Tab> Tabs { get; set; }
//Other properties
//...
}
}
The View (cut down version)
#using (Html.BeginForm("Edit", "Person", FormMethod.Post, new { id = "validate-form", #class = "block-content form" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(x => x.PersonID)
#foreach (var tab in Model.Tabs)
{
#Html.EditorFor(vm => tab)
}
<input class="close-toolbox button" type="submit" value="Save">
}
Any suggestions?
Thanks
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
It's an old article, but it still applies.
I had this exact problem, but basically due to the model binding system you need to use an explicit for loop instead of a foreach loop, and reference your elements by their index.
#using (Html.BeginForm("Edit", "Person", FormMethod.Post, new { id = "validate-form", #class = "block-content form" }))
{
Html.AntiForgeryToken()
Html.HiddenFor(x => x.PersonID)
for (int i = 0; i<Model.Tabs.Count; i++)
{
Html.EditorFor(x => Model.Tabs[i])
}
<input class="close-toolbox button" type="submit" value="Save">
}