I am outputting a textbox to the page using the Html helpers. I want to add the disabled attribute dynamically based on whether or not a boolean value in my model is true or false.
My model has a method that returns a boolean value:
<% =Model.IsMyTextboxEnabled() %>
I currently render the textbox like follows, but I want to now enabled or disable it:
<% =Html.TextBox("MyTextbox", Model.MyValuenew { id = "MyTextbox", #class = "MyClass" })%>
If the return value of Model.IsMyTextboxEnabled() == true I want the following to be output:
<input class="MyClass" id="MyTextbox" name="MyTextbox" type="text" value="" />
If it == false, I want it to output as:
<input class="MyClass" id="MyTextbox" name="MyTextbox" type="text" value="" disabled />
What is the cleanest way to do this?
This here should do the trick:
<%= Html.TextBox("MyTextbox", Model.MyValuenew,
(Model.IsMyTextboxEnabled() ? (object) new {id = "MyTextbox", #class = "MyClass"}
: (object) new {id = "MyTextbox", #class = "MyClass", disabled="true" })) %>
In your helper would you have a check in the code, when you are generating the html, that simply checks the bool and then either adds the disabled attribute or leaves it out?
This is a simply example and not well structrued but...
if (disabled)
return string.Format(CultureInfo.InvariantCulture, "<input type=text disabled/>", new object[] { HttpUtility.HtmlAttributeEncode(s), myTextBox });
Is this what you were asking?
EDIT:
Wait, I see now. I think you'll need to either create your own helper or extend the MVC textbox helper so that you can do it.
Either that or you can I think do something like;
<%= Html.TextBox("mytextbox","", new { disabled="true" } %>
The above is untested but something like that should work.
EDIT 2:
<% if (condition) {%>
<%= Html.TextBox("mytextbox", "", new {#readonly="readonly"}) %>
<%} else {%>
<%= Html.TextBox("mytextbox", "") %>
<%}
Too late maybe but hope it will help:
I´ve been working with ASP MVC recently and (as I refused to have one combination of Anonymous types for each possible set of attributes) realized that, as of MVC 2, every Input Extension method has two forms: one with attributes as Objects and one as IDictionary<string, Object> element. See the msdn API
So, I ended up coding the following, which personally I find far more convenient that creating multiple objects (actually, for multiple option or checkbox controls you can use just one Dictionary and add or remove properties at will):
<%
IDictionary<string, Object> radioAttrs = new Dictionary<string, Object>();
radioAttrs.Add("class", "radioBot");
if (Model.EnabledRegistro)
{
radioAttrs["onclick"] = "updateControlsForInfoNom(true)";
}
else
{
radioAttrs["disabled"] = "disabled";
}
%>
<%: Html.RadioButtonFor(model => model.Accion.calculoRegistro, "true", radioAttrs)%>
...
With this method you can supply multiple attributes if needed
#Html.TextBox("mytextbox", new {}, new { #class = "myclass", disabled = "true" })
Related
I'm trying to do this: Editing a variable length list, ASP.NET MVC 2-style
In the post he mentions that it could be done with less code using Html.EditorFor(), but that it would be more difficult because of the indexes. Well, that's exactly what I want to do, and I don't know where to begin.
I'm an ASP.NET novice who just completed the Nerd Dinner tutorial before jumping into a project at work, so any help would be appreciated.
Update 1: Instead of generating a GUID for each item in the collection, I'd like to generate incremental indexes starting with 0. Right now the field names look like "gifts[GUID].value"; I would like them to be "gifts[0].value","gifts1.value" etc. but I don't understand how the collection keeps track and generates these indices.
In response to your update about generating indexes instead of GUIDs, the original linked article had a few comments from others that tried to solve the same issue but none of them worked for me. What I found was the collection with index was referenced in the following location:
html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix
So I wrote a helper function to parse out the index (and if there is a problem then the GUID would be generated)
public static string GetCollectionItemIndex(this HtmlHelper html, string collectionName)
{
int idx;
string sIdx;
if (Int32.TryParse(Regex.Match(html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix, #"\d+").Value, out idx))
{
sIdx = idx.ToString();
}
else
{
sIdx = Guid.NewGuid().ToString();
}
return sIdx;
}
I edited the BeginCollectionItem(..) function to call this helper function when setting the item index:
string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : GetCollectionItemIndex(html, collectionName);
Hope this helps someone else!
Well, you begin by defining an editor template (~/Views/Shared/EditorTemplates/Gift.ascx):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyApp.Models.Gift>" %>
<div class="editorRow">
<% using(Html.BeginCollectionItem("gifts")) { %>
Item: <%= Html.TextBoxFor(x => x.Name) %>
Value: $<%= Html.TextBoxFor(x => x.Price, new { size = 4 }) %>
<% } %>
</div>
And then replace the RenderPartial call with EditorForModel:
<% using(Html.BeginForm()) { %>
<div id="editorRows">
<%= Html.EditorForModel() %>
</div>
<input type="submit" value="Finished" />
<% } %>
Once you've tried this you may come back and ask if you have any problems by explaining the symptoms.
Early yesterday, the following validation notice was working correctly. Then we converted the Index view where the request for this action originates to use a partial view, and the Delete ActionLink is now inside that partial view, and now the string argument to the JavaScript method call is rendered literally and as the only content on the 'destination' Delete view.
public ActionResult Delete(int id)
{
var perm = JobCardService.CheckBusinessRules(id);
if (!string.IsNullOrEmpty(perm))
{
return JavaScript("NotifyFailure('You may not delete this Installation: " + perm + "', false, 2000);");
}
JobCardViewData viewData = ViewDataFactory.CreateBaseViewData<JobCardViewData>("Installation List");
return View("Delete", viewData);
}
The Filter action returns the partial view, and is requested as below:
<div class="editor-field">
<% using (Ajax.BeginForm("Filter", "JobCard", new AjaxOptions { UpdateTargetId = "jobList" }))
{ %>
<%= Html.DropDownListFor(model => model.RequesterId, new SelectList(Model.RequesterList, "RequesterID", "CompanyName", Model.RequesterId), new { onchange = "$('#Select_Save').click();" })%>
<input id="Select_Save" type="submit" value="Save" style="display: none" />
<%
}%>
</div>
If the action method is responsible for returning a view, seems like the response shouldn't be returning a JavaScript if in error because no underlying ASP.NET page would be served, which means that you would see it as literal text.
Consider assigning the method call to ViewData, and in your client do something like:
<% if (ViewData["X"] != null) { %>
<script type="text/javascript">
<%= ViewData["X"] %>
</script>
<% } %>
Calling VIewData["X"] like I do should render the JavaScript code directly and get directly executed when parsed.
I think that might work; you can always utilize other mechanisms like eval to parse content, or do whatever else you might need....
Refer to the comment of this question ASP.NET MVC Javascript ActionResult
The other aspect is that using this return type is considered to be an anti-pattern and should be avoided. The suggested approach is to use a Json result.
Working example for JavaScriptResult in asp.net mvc
http://devlicio.us/blogs/billy_mccafferty/archive/2009/02/07/beware-of-asp-net-mvc-javascriptresult.aspx
Edit:
Since javascript is being returned from the Controller, an alternative would be to send script back to the browser that redirects the user to the correct page.
public ActionResult Delete(int id)
{
var perm = JobCardService.CheckBusinessRules(id);
if (!string.IsNullOrEmpty(perm))
{
return JavaScript("NotifyFailure('You may not delete this Installation: " + perm + "', false, 2000);");
}
// you may need to do a bit more to create a URL in the form of http://...
UrlHelper u = new UrlHelper(this.ControllerContext.RequestContext);
string url = u.Action("ActionName","ControllerName", new{id=1}); // the new Action will return the delete view
return Javascript(String.Format("window.location =""{0}"",url);
}
Refer to Creating a URL in the controller .NET MVC for more on the UrlHelper.
This may not be the best way to do this, but every other answer I have come across has required extensive rework to achieve. This requires one small, simple change and works exactly as required. All I had to do was change the Delete action link from this:
<%= Html.ActionLink("Delete", "Delete", new { id = item.InstallationDBNumber }) %>
to this:
<%= Ajax.ActionLink("Delete", "Delete", new { id = item.InstallationDBNumber }, new AjaxOptions { HttpMethod = "Get" }) %>
In my controller I generated a SelectList that I pass to the dropdown helper:
<%= Html.DropDownList("abc123", Model.SomeList) %>
I look at the querystring for a value, which is a ID.
I then loop through all the items in the SelectList and if it is equal to the ID, I do:
item.Selected = true;
The controller action then passes this SelectList to the view and then to the Html helper.
In debug mode I can see the value does get set to true, but the html renders without selecting the item.
What can the issue be?
I don't know what you are doing wrong as you've shown 0 code but this definitely works:
public ActionResult Index(int? id)
{
var model = new SelectList(new[]
{
new { Id = 1, Name = "item 1" },
new { Id = 2, Name = "item 2" },
}, "Id", "Name", id);
return View(model);
}
and in your view:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<SelectList>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.DropDownList("abc123", Model) %>
</asp:Content>
Now if you navigate to /home/index/1 the first item is selected, if you navigate to /home/index/2 the second item item selected.
Also if you are using ASP.NET MVC 2.0 I would recommend you the strongly typed DropDownListFor helper instead of DropDownList.
This seems to be a common MVC problem:
Html.DropDownListFor not behaving as expected ASP.net MVC
I am struggling to get to grips with a particular form setup in my asp.net MVC application.
Currently I have a page which displays a chunk of data. On this page is a simple form that calls into an action method that returns a partialview when posted (through ajax - jform).
This is all very well until I try and add paging support to the search results.
I have a chunk of code that that will paginate an IQueryable, but Im not sure how to implement this in my current setup.
Heres some code:
[Authorize]
public ActionResult AssetSearch(string RoomID, string type, string keyword, string risks)
{
//check values passed in
Guid? r = null;
if (RoomID != "Any" && RoomID != null)
r = new Guid(RoomID);
string t = type == "Any" ? null : type;
string risk = risks == "Any" ? null : risks;
var assets = surveyRepository.GetAssetsSearch(r, t, keyword, risk);
if (Request.IsAjaxRequest())
{
return PartialView("AssetListControl", assets);
}
else
{
return View("AssetListControl", assets);
}
}
This action method returns a partial view which gets rendered out in a div through the following jquery.
$(document).ready(function() {
$("#searchForm").submit(function() {
$("#searchForm").ajaxSubmit({ target: '#results', beforeSubmit: PreSub, success: Success });
return false;
});
});
function Success(responseText, statusText) {
$("#loadingMessage").html("done");
$('#resultsTable').tablesorter();
$("#results").slideDown("slow");
}
function PreSub(formData, jqForm, options) {
$("#loadingMessage").html("loading...").fadeIn();
$("#results").slideUp("fast");
return true;
}
And my form looks as follows:
<form id="searchForm" action="<%=Url.Action("AssetSearch") %>" method="post">
<fieldset>
<label for="RoomID">
Room Name</label>
<%= Html.DropDownList("RoomID") %>
<label for="Type">
Asset Type</label>
<%= Html.DropDownList("Type") %>
<label for="Risks">
Risk Level</label>
<%= Html.DropDownList("Risks") %>
<label for="Keyword">
Keyword</label>
<%= Html.TextBox("Keyword") %>
<input type="submit" name="sumbit" id="searchBtn" value="Search" />
</fieldset>
</form>
Sorry for the code overload :-)
I have a feeling that I have configured my controller and view in such a way that paging won't be easy to implement. All advice welcome!
Thanks in advance!
Ok, so I managed to get it working with AJAX and POST in a not so attractive way.
Firstly, I dropped a couple of anchor tags in my paged results partial view that, if there are previous or next pages, show up. These links fire off a javascript function and pass a page value. The navigation looks as follows:
<% if (Model.HasPreviousPage)
{ %>
Back
<%} %>
<% if (Model.HasNextPage)
{ %>
Forward
<%} %>
The function looks as follows:
function PageResults(page) {
var form = document.forms["searchForm"];
form.elements["page"].value = page;
$("#searchForm").ajaxSubmit({ target: '#results', beforeSubmit: PreSub, success: Success });
return false;
}
I have also tweaked my controller to accept a page parameter, which is used to retrieve the correct set of results:
var paginated = new PaginatedList<Asset>(assets, Page ?? 0, 10);
This seems to do the trick, although its not great :)
I am passing a query string with name "RowTobeHighLighted" from my Asp.net mvc action result. What I have to do is, I have to get the query string value from that controller action to a script of type text/javascript. I have tried to use simple Request.Querystring() under javascript. But that is not working.
Is it possible to get the querystring value from controller action.Or, is it possible to get the value of viewdata under <script type="text/javascript"> tag.
Well no, Request.QueryString won't work, because it's server side only.
You have a few options
You could use Request.QueryString to embed the value in a script
var myValue = <% = HttpUtilityRequest.HtmlEncode(QueryString["myValue"]") %>
You could either pass the query string value as view data to the view and then use it in your javascript like so
var myValue = <% HttpUtilityRequest.HtmlEncode(ViewData["myValue"]) %>
Or you could look at the query string in javascript
var qs = new Querystring()
var myValue = qs.get("myValue")
Of course with all of these you should watch for Cross Site Scripting attacks.
On the client side: use the Querystring.
On the server side: (provide value to JS):
<%= "var RowTobeHighLightedUrl = '" + Request.QueryString["RowTobeHighLighted"] + "';"%>
If the RowTobeHighLighted should be JavaScript Escape (NOT HtmlENcode!).
Use TempData for this sort of temporary message.
In your controller:
TempData["RowToHighlight"] = rowNumber;
And then in the view:
<% foreach (var row in Model) { %>
<tr>
<td id="row_<%= row.id %>"<%= (row.id == (int)TempData["RowToHighlight"]) ? " class="highlighted" : "" %>>my row</td>
</tr>
<% } %>
And then if you were using jQuery for example to fade out or whatever (inside your of jQuery document.ready):
<% if (TempData["RoToHighlight"] != null) { %>
$("#row_<%= (int)TempData["RowToHighlight"] %>").fadeOut();
<% } %>
Of course, be sure to use any necessary escaping and encoding etc.