Asp.Net MVC2 Clientside Validation and duplicate ID's problem - c#

I'm using MVC2 with VS2010
I have a view that has two partial views in it: "Login" and "Register"
both partial views contains the Email address field i use the following in both partial views:
<%: Html.TextBoxFor(model => model.EmailAddress ) %><br /><%: Html.ValidationMessageFor(model => model.EmailAddress) %>
if i use both partial views on one page, it ends up having duplicate id's so validation happens across both views (even thopugh they are in seperate forms)
how can i go about eliminating this

For some controls you can specify the HTML attributes in an overload like this:
<%: Html.TextBoxFor(model => model.EmailAddress, new { id = 'my-unique-id" }) %>
<br />
<%: Html.ValidationMessageFor(model => model.EmailAddress, new { id = 'my-unique-id" }) %>
You can also either write your HTML by hand or use the older HTML helpers so you can add your own ID that way (you need to do this for Html.LabelFor() helpers)
<%: Html.TextBox( "EmailAddress", Model.EmailAddress, new { id = 'my-unique-id" } ) %>

Related

Use model on SharePoint application page .aspx

I am working on SharePoint to create a Feedback questionnaire form using an application page that is basically a aspx page.
I wish to do this by emulating MVC as far as possible. I've set up my model in the code-behind:
public List<QuestionViewModel> modelQuestions = new List<QuestionViewModel>();
Next, I need to display each question and an appropriate input depending on the question type (e.g. single line, multi line, single selection, multiple selection).
I've got it displaying the questions correctly:
<fieldset class="what-went-wrong">
<% for (int i = 0; i < modelQuestions.Count; i++) { %>
<p>
<label for="QuestionText">
<% if (modelQuestions[i].Required) { %>
<span class="req-field indicator">*</span>
<% } %>
<%= modelQuestions[i].QuestionText %>
<% if (modelQuestions[i].Required) { %>
<span class="req-field right">* Required field</span>
<% } %>
</label>
</p>
<% } %>
</fieldset>
This give's me the question text. I'm now trying to construct the appropriate input, but this <% %> tags is not working for this:
<% if(modelQuestions[i].QuestionTypeId == QuestionType.SingleLine) { %>
<input id="modelQuestions_<% i %>" name="modelQuestions[<% i %>]" type="text" placeholder="<% modelQuestions[i].Placeholder %>" />
<% } %>
I can't seem to get it to construct the html element using details from the model (in the value for id, name, placeholder etc.)
Also, I've no idea how to go about posting this back to the server when I get to that point.
Is there any merit in continuing? Are there other controls/methods more appropriate to use in this case with aspx?
You cannot generate HTML markup like this. Even data-binding expressions will not help, because they bind ASP.NET controls' attributes values, not the plain output HTML in the page.
You should generate the markup in the "code behind", like this:
Page markup:
<div id='AnswersPanel'>
<div>
Page code behind:
protected void PageLoad(...)
{
AnswersPanel.InnerHtml = "";
AnswersPanel.InnerHtml += string.Format("<input id='modelQuestions_{0}' name='modelQuestions[{0}]' type='text' placeholder='{1}' />",
i.ToString(),
modelQuestions[i].Placeholder);
}

From DropDownList to Textbox

I have DropDownList and Textbox on my page.
DropDownList show data from DataBase(Table "List").
When I choose one line in DropDownList I want to see it in Textbox, make changes and save this line into DataBase(Table "Text") after press "OK".
Please tell me, how to do this?
Code:
Controller.cs:
public ActionResult Create(Model model)
{
var viewModel = new ISMSViewModel
{
Model = new Model(),
};
return View(viewModel);
}
[HttpPost]
public ActionResult Create(Model model, int i)
{
try
{
sysDB.AddToActives(model);
sysDB.SaveChanges();
return RedirectToAction("Browse");
}
}
ListText.ascx:
<%: Html.EditorFor(model => model.Model, new { Lists = Model.Lists } %>
<%: Html.Label("List") %>
<%: Html.DropDownList("ListId", new SelectList(ViewData["Lists"] as IEnumerable, "ListId", "Name", Model.ListId)) %>
<%: Html.Label("TextBox") %>
<%: Html.TextBoxFor(model => model.TextBox) %>
<%: Html.ValidationMessageFor(model => model.TextBox) %>
For this you need to write some JavaScript.
handle the onchange event for dropdown
<%: Html.DropDownList("ListId", new SelectList(ViewData["Lists"] as IEnumerable, "ListId", "Name", Model.ListId), new {#onchange="setVal(this)"}) %>
on your view
inside head block
<script type="text/javascript">
function setVal(obj)
{
document.getElementById("TextBox").value=obj.value;
}
</script>

Issue with <%: ... %> vs. <%= %> when displaying generated text

I am writing an MVC application with C#. In this one particular section, I have a conditional switch for the navigation to highlight the appropriate tab. Here is the code for that:
<script type="text/C#" runat="server">
string oController;
string oAction;
const string current = "class=\"current_page\"";
protected override void OnLoad(EventArgs e)
{
oController = ViewContext.RouteData.Values["controller"].ToString();
oAction = ViewContext.RouteData.Values["action"].ToString();
base.OnLoad(e);
}
</script>
<div id="menu">
<ul>
<li <%= (oController.Equals("Home") ? current : "") %>>Home</li>
<li>Customer Manager</li>
<!-- <%: oController.Equals("Home") %> -->
<!-- <%: oAction %> -->
</ul>
</div>
On this line (<li <%= (oController.Equals("Home") ? current : "") %>>Home</li>) if I use the <%: %> ASP nugget instead of <%= %> (as is recommended, since the latter is being phased out soon), the generated text comes out as
<li class="current_page">Home</li>
Instead of
<li class="current_page">Home</li>
Any suggestions and/or reasons why this is happening? Thanks!
Because <%: is intended to encode data such as user input. In your case, that is self-generated (trusted) html, so you don't want to encode it; <%= is the correct usage.
<%: is for things like <%:user.Name%>, which conveniently prevents issues for malicious text with xss etc in it.
You could just have the class be empty when the value is not Home. Clearly you are trying to omit it all together, but it would be a solution none the less.
const string current = "current_page";
<li class="<%: (oController.Equals("Home") ? current : "") %>">Home</li>

Asp.Net MVC EditorTemplate Model is lost after Post

I have a controller with two simple Methods:
UserController Methods:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Details(string id)
{
User user = UserRepo.UserByID(id);
return View(user);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Details(User user)
{
return View(user);
}
Then there is one simple view for displaying the details:
<% using (Html.BeginForm("Details", "User", FormMethod.Post))
{%>
<fieldset>
<legend>Userinfo</legend>
<%= Html.EditorFor(m => m.Name, "LabelTextBoxValidation")%>
<%= Html.EditorFor(m => m.Email, "LabelTextBoxValidation")%>
<%= Html.EditorFor(m => m.Telephone, "LabelTextBoxValidation")%>
</fieldset>
<input type="submit" id="btnChange" value="Change" />
<% } %>
As you can see, I use an editor template "LabelTextBoxValidation":
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>
<%= Html.Label("") %>
<%= Html.TextBox(Model,Model)%>
<%= Html.ValidationMessage("")%>
Showing user information is no problem. The view renders perfectly user details.
When I submit the form, the object user is lost. I debugged on the row "return View(User);" in the Post Details method, the user object is filled with nullable values. If I dont use the editor template, the user object is filled with correct data. So there has to be something wrong with the editor template, but can't figure out what it is. Suggestions?
I would re-architect a little bit - change your LabelTextBoxValidation editor to an Html helper, and then make one EditorTemplate for your data model. That way you could do something like this:
<% using (Html.BeginForm("Details", "User", FormMethod.Post))
{%>
<fieldset>
<legend>Userinfo</legend>
<% Html.EditorFor(m => m); %>
</fieldset>
<input type="submit" id="btnChange" value="Change" />
<% } %>
And your editor template would be something like:
<%= Html.ValidatedTextBoxFor(m => m.Name); %>
<%= Html.ValidatedTextBoxFor(m => m.Email); %>
<%= Html.ValidatedTextBoxFor(m => m.Telephone); %>
where ValidatedTextBoxFor is your new html helper. To make that, it would be fairly easy:
public static MvcHtmlString ValidatedTextBoxFor<T>(this HtmlHelper helper, Expression thingy)
{
// Some pseudo code, Visual Studio isn't in front of me right now
return helper.LabelFor(thingy) + helper.TextBoxFor(thingy) + helper.ValidationMessageFor(thingy);
}
That should set the names of the form fields right I believe, as that seems like the source of the problem.
EDIT: Here is the code that should help you out:
public static MvcHtmlString ValidatedTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
return MvcHtmlString.Create(
html.LabelFor(expression).ToString() +
html.TextBoxFor(expression).ToString() +
html.ValidationMessageFor(expression).ToString()
);
}

Where is the erroneous "Id" coming from?

I'm experimenting with the MVC beta 2 and have the following method in a controller:
[HttpPost]
public ActionResult Create(Issue issue) {
if(TryUpdateModel(issue, "Model", new [] {"Title", "Description"})) {
ServiceCaller.PutIssue(issue);
return RedirectToAction("Index");
}
return RedirectToAction("Create");
}
TryUpdateModel always fails and ModelState has an error under a Key called "Id" which says that "A value is required". The View contains no Id input field and I understood that my "include" argument on the TryUpdateModel should have ignored anything other than the explicitly included fields anyway. Changing the method signature to the following fixes the problem but I'd like to understand how the "Id" field is getting included in the first place.
public ActionResult Create([Bind(Exclude = "Id")]Issue issue)
For completeness, here's the View (it's a shared view in the EditorTemplates folder):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Tracker.Processing.Model.Issue>" %>
<% using (Html.BeginForm(Model.Id > 0 ? "Edit" : "Create", "Issue", FormMethod.Post)) { %>
<p>
<%= Html.LabelFor(i => i.Title) %>
<%= Html.EditorFor(i => i.Title) %>
</p>
<p>
<%= Html.LabelFor(i => i.Description) %>
<%= Html.TextArea("Description", Model.Description, new{ style = "width: 100%;" }) %>
</p>
<p>
<input type="submit" value="Save" />
</p>
<% } %>
Any ideas?
Its attempting to match the Id in the route to the one on your object
as the one in the route is null and the Id on your object is not nullable you get the error
Irritating isn't it

Categories