How to render an action link with an image? - asp.net-mvc

I know to use Html.ActionLink() to render textual <a href..."> links to actions.
How do I render a link to an action that has an underlying image as the link?
<img src="asdfasdf"/>

Here is code for the ImageLink HtmlHelper extension I use.
/*
* Image Link HTML helper
*/
/// <summary>
/// return image link
/// </summary>
/// <param name="helper"></param>
/// <param name="imageUrl">URL for image</param>
/// <param name="controller">target controller name</param>
/// <param name="action">target action name</param>
/// <param name="linkText">anchor text</param>
public static string ImageLink(this HtmlHelper helper, string imageUrl, string controller, string action, string linkText)
{
return ImageLink(helper, null, controller, action, linkText, imageUrl, null, null, null, null);
}
/// <summary>
/// return image link
/// </summary>
/// <param name="helper"></param>
/// <param name="imageUrl">URL for image</param>
/// <param name="controller">target controller name</param>
/// <param name="action">target action name</param>
/// <param name="linkText">anchor text</param>
/// <param name="htmlAttributes">anchor attributes</param>
public static string ImageLink(this HtmlHelper helper, string imageUrl, string controller, string action, string linkText, object htmlAttributes)
{
return ImageLink(helper, null, controller, action, linkText, imageUrl, null, null, new RouteValueDictionary(htmlAttributes), null);
}
/// <summary>
/// return image link
/// </summary>
/// <param name="helper"></param>
/// <param name="imageUrl">URL for image</param>
/// <param name="controller">target controller name</param>
/// <param name="action">target action name</param>
/// <param name="linkText">anchor text</param>
/// <param name="htmlAttributes">anchor attributes</param>
/// <param name="routeValues">route values</param>
public static string ImageLink(this HtmlHelper helper, string imageUrl, string controller, string action, string linkText, object htmlAttributes, object routeValues)
{
return ImageLink(helper, null, controller, action, linkText, imageUrl, null, null, new RouteValueDictionary(htmlAttributes), new RouteValueDictionary(routeValues));
}
/// <summary>
/// return image link
/// </summary>
/// <param name="helper"></param>
/// <param name="id">Id of link control</param>
/// <param name="controller">target controller name</param>
/// <param name="action">target action name</param>
/// <param name="strOthers">other URL parts like querystring, etc</param>
/// <param name="strImageURL">URL for image</param>
/// <param name="alternateText">Alternate Text for the image</param>
/// <param name="strStyle">style of the image like border properties, etc</param>
/// <returns></returns>
public static string ImageLink(this HtmlHelper helper, string id, string controller, string action, string linkText, string strImageURL, string alternateText, string strStyle)
{
return ImageLink(helper, id, controller, action, linkText, strImageURL, alternateText, strStyle, null, null);
}
/// <summary>
/// return image link
/// </summary>
/// <param name="helper"></param>
/// <param name="id">Id of link control</param>
/// <param name="controller">target controller name</param>
/// <param name="action">target action name</param>
/// <param name="linkText">anchor text</param>
/// <param name="strImageURL">URL for image</param>
/// <param name="alternateText">Alternate Text for the image</param>
/// <param name="strStyle">style of the image like border properties, etc</param>
/// <param name="htmlAttributes">html attribues for link</param>
/// <returns></returns>
public static string ImageLink(this HtmlHelper helper, string id, string controller, string action, string linkText, string strImageURL, string alternateText, string strStyle, IDictionary<string, object> htmlAttributes, RouteValueDictionary routeValues)
{
// Build the img tag
TagBuilder image = new TagBuilder("img");
image.MergeAttribute("src", strImageURL);
image.MergeAttribute("alt", alternateText);
image.MergeAttribute("valign", "middle");
image.MergeAttribute("border", "none");
TagBuilder span = new TagBuilder("span");
// Create tag builder
var anchor = new TagBuilder("a");
var url = new UrlHelper(helper.ViewContext.RequestContext).Action(action, controller, routeValues);
// Create valid id
anchor.GenerateId(id);
// Add attributes
//anchor.MergeAttribute("href", "/" + controller + "/" + action); //form target URL
anchor.MergeAttribute("href", url);
anchor.MergeAttribute("class", "actionImage");
if (htmlAttributes != null)
anchor.MergeAttributes(new RouteValueDictionary(htmlAttributes));
// place the img tag inside the anchor tag.
if (String.IsNullOrEmpty(linkText))
{
anchor.InnerHtml = image.ToString(TagRenderMode.Normal);
}
else
{
span.InnerHtml = linkText;
anchor.InnerHtml = image.ToString(TagRenderMode.Normal) + " " + span.ToString(TagRenderMode.Normal);
}
// Render tag
return anchor.ToString(TagRenderMode.Normal); //to add </a> as end tag
}

Here is a post about creating strongly typed ActionImage extensions. Should get you started if you don't like those horrible error-prone magic strings.

<%=Html.ActionLink(
Html.Image("~/Images/bigwave.jpg"),
new {controller="Hurr", action="Durr"})) %>
Check here for how to create the Image method
Alternately, just write it in:
<%=Html.ActionLink(
"<img src=\"asdfasdf\"/>",
new {controller="Hurr", action="Durr"}) %>

Two options I can think of, I'll give you the suggested one first:
One: Give the anchor an a unique ID and use CSS to style the link appropriately. This will also give you the ability to easily apply a rollover image using :hover.
<%=Html.ActionLink(" ", "action", "controller", null, new { #class="sample" })%>
<style type="text/css">
a.sample { background-image: url(http://sstatic.net/so/img/replies-off.png); }
a.sample:hover { background-image: url(http://sstatic.net/so/img/logo.png); }
</style>
Two: Create your own HtmlHelper that either doesn't escape the linkText parameter like ActionLink does or takes an image URL.

If you are on ASP.Net MVC 1.0 you can get the futures library and do this:
<%= Html.SubmitImage("controlName", "~/ImagePath/ImageName.jpg") %>
You just need to add this library: Microsoft.Web.Mvc download the dll here
This is also supposed to be part of ASP.Net MVC 2.0 at some point.

I have tested the ImageLink helpers and suggest that they should be made to return MvcHtmlString instead of string to prevent the Razor engine from encoding the actual image URLs.
So I changed all the signatures of the ImageLink functions to return 'MvcHtmlString' instead of plain 'string' and changed the last line of the last version of 'ImageLink' to:
return MvcHtmlString.Create( anchor.ToString(TagRenderMode.Normal)); //to add </a> as end tag

Related

adding a attributes to a custom html helper for drop down list

I have implemented the solution here:
http://www.spicelogic.com/Journal/ASP-NET-MVC-DropDownListFor-Html-Helper-Enum-5
It simply creates a dropdown list from member of enums. However, I want to associate a name with the dropdown list like here:
#Html.TextBox("username", Model.Username, new { id = "username" })
To illustrate, I want to use it in such a way:
#Html.DropDownListFor(m => m.FavoriteColor, new { id = "username" } )
How can I do that? How can I expand the Extention method of the EnumEditorHtmlHelper class?
Here is the definition of EnumEditorHtmlHelper:
namespace LojmanMVC.WebUI.Static
{
public static class EnumEditorHtmlHelper
{
/// <summary>
/// Creates the DropDown List (HTML Select Element) from LINQ
/// Expression where the expression returns an Enum type.
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="expression">The expression.</param>
/// <returns></returns>
public static MvcHtmlString MyEnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
where TModel : class
{
TProperty value = htmlHelper.ViewData.Model == null
? default(TProperty)
: expression.Compile()(htmlHelper.ViewData.Model);
string selected = value == null ? String.Empty : value.ToString();
return htmlHelper.DropDownListFor(expression, createSelectList(expression.ReturnType, selected));
}
/// <summary>
/// Creates the select list.
/// </summary>
/// <param name="enumType">Type of the enum.</param>
/// <param name="selectedItem">The selected item.</param>
/// <returns></returns>
private static IEnumerable<SelectListItem> createSelectList(Type enumType, string selectedItem)
{
return (from object item in Enum.GetValues(enumType)
let fi = enumType.GetField(item.ToString())
let attribute = fi.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault()
let title = attribute == null ? item.ToString() : ((DescriptionAttribute)attribute).Description
select new SelectListItem
{
Value = item.ToString(),
Text = title,
Selected = selectedItem == item.ToString()
}).ToList();
}
}
}
Thanks in advance.
You can do this using same method but it need second parameter to be a collection of SelectListItems and third parameter is for your custom attributes.
#Html.DropDownListFor(m => m.FavoriteColor, (IEnumerable<SelectListItem>)ViewBag.Colors, new {id="username" })

MVC 3 Url Helper Giving Incorrect URL

I am developing a MVC 3 application for a corporate intranet site and I am having some issues with the URL helper sometimes not producing correct URLs. The application is being accessed through an access manager application that is controlled by our IT department which basically provides a standardized URL so that the user does not need to know any information about the server. For example, to access the application directly on the server, I would visit:
http://philsserver/App
Through the access manager, I would use the URL provided by the IT department:
http://secureintranet/PHILSAPP/App/
I am using the MVC URL helper in several places in my application - the issue is that sometimes the "PHILSAPP" part is left out - when I use it within an "<a>" link, it works, but when I use it in elsewhere, it does not.
For example, the code:
<a href="#Url.Action("Index", "FormsAndTemplates")">
correctly creates the link as:
<a href="/PHILSAPP/App/FormsAndTemplates">.
The following code:
#Html.TextBox("lastName", ViewBag.LastName as string, new { #class = "input-mini", #autocomplete = Url.Action("QuickSearch", "Employee") })
produces:
<input autocomplete="/App/Employee/QuickSearch" class="input-mini" id="lastName" name="lastName" type="text" value="" />
Notice that this URL does not contain the "PHILSAPP" part. This also happens if I use the URL helper in javascript or just about anywhere other than an "<a>" tag. Does anyone have any idea why this would be happening? As far as I can tell, both calls to Url.Action are pretty much the same so I cannot figure out why this is happening. I apologize if this question has already been answered but I was not able to find any information about someone having a similar problem. Thanks in advance for any assistance.
Update:
As requested, my routes are below:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
Update 2: The access manager being used is Tivoli Identity Manager if that gives anyone any clues.
As nemesv pointed out above, the answer was that the Url.Action method was always generating the URL as /App/... but the access manager application would recognize certain tags (such as <a href="/App/...">, <form action="/App/...">, etc.) and would add the /PHILSAPP to the beginning. The solution I am exploring is to write some extension methods for the UrlHelper and HtmlHelper to generate absolute URLs rather than relative URLs where the host name including the /PHILSAPP will be specified in the web.config file. If anyone still has any other suggestions to solve this I would be happy to hear them but otherwise I am satisfied with using this as a work-around.
Some boilerplate code to start with:
namespace MvcApplicationNameSpace
{
/// <summary>
/// Extension methods to the UrlHelper class for generating absolute URLs using
/// Web.config settings
/// </summary>
public static class UrlHelperExtensions
{
private static string BaseUrl
{
get
{
return System.Configuration.ConfigurationManager.AppSettings["BaseUrl"];
}
}
/// <summary>
/// Generates a string for the absolute URL to an action method
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static string AbsoluteAction(this UrlHelper url)
{
return BaseUrl + url.Action();
}
/// <summary>
/// Generates a string for the absolute URL to an action method with the
/// specified name
/// </summary>
/// <param name="url"></param>
/// <param name="actionName"></param>
/// <returns></returns>
public static string AbsoluteAction(this UrlHelper url, string actionName)
{
return BaseUrl + url.Action(actionName);
}
/// <summary>
/// Generates a string for the absolute URL to an action method with the
/// specified name and route values
/// </summary>
/// <param name="url"></param>
/// <param name="actionName"></param>
/// <param name="routeValues"></param>
/// <returns></returns>
public static string AbsoluteAction(this UrlHelper url, string actionName, object routeValues)
{
return BaseUrl + url.Action(actionName, routeValues);
}
/// <summary>
/// Generates a string for the absolute URL to an action method with the
/// specified name and route values
/// </summary>
/// <param name="url"></param>
/// <param name="actionName"></param>
/// <param name="routeValues"></param>
/// <returns></returns>
public static string AbsoluteAction(this UrlHelper url, string actionName, RouteValueDictionary routeValues)
{
return BaseUrl + url.Action(actionName, routeValues);
}
/// <summary>
/// Generates a string for the absolute URL to an action method and
/// controller
/// </summary>
/// <param name="url"></param>
/// <param name="actionName"></param>
/// <param name="controllerName"></param>
/// <returns></returns>
public static string AbsoluteAction(this UrlHelper url, string actionName, string controllerName)
{
return BaseUrl + url.Action(actionName, controllerName);
}
/// <summary>
/// Generates a string for the absolute URL to an action method and
/// controller, including route values
/// </summary>
/// <param name="url"></param>
/// <param name="actionName"></param>
/// <param name="controllerName"></param>
/// <param name="routeValues"></param>
/// <returns></returns>
public static string AbsoluteAction(this UrlHelper url, string actionName, string controllerName, object routeValues)
{
return BaseUrl + url.Action(actionName, controllerName, routeValues);
}
/// <summary>
/// Generates a string for the absolute URL to an action method and
/// controller, including route values
/// </summary>
/// <param name="url"></param>
/// <param name="actionName"></param>
/// <param name="controllerName"></param>
/// <param name="routeValues"></param>
/// <returns></returns>
public static string AbsoluteAction(this UrlHelper url, string actionName, string controllerName, RouteValueDictionary routeValues)
{
return BaseUrl + url.Action(actionName, controllerName, routeValues);
}
}
}
We exactly had the same problem behind our secure entry server.
For REST calls, we wanted to generate urls on the server side to make them available in java script. But they didn't include the sub-path added by the secure entry server.
So we came up with a workaround like that (rendered in layout page):
<a id="urlBase" href="/" style="display: none;"></a>
<script type="text/javascript">
baseUrl = document.getElementById('urlBase').getAttribute('href');
</script>
href="/" has been substitued by the entry server by href="/path/", and we could easily concatenate baseUrl with our relative paths when accessing REST services.
Hope it helps in your case too.

Dynatree with ASP.NET MVC

Has anybody got any examples of using the Dynatree plugin with MVC? I have been wrestling with it without much progress. I have an action method which returns a JsonResult (but selects all columns in the underlying table, not sure if this is the problem) and in my initajax call , all I'm doing is calling this method.
If it's not too much trouble, I am looking for sample View and Controller action methods.
Thanks in advance for any help
You need to create an object to serialize the nodes eg.
public interface ITreeItem
{
}
/// <summary>
/// Tree Item Leaf.
/// </summary>
public class TreeItemLeaf :ITreeItem
{
/// <summary>
/// Gets the Title.
/// </summary>
public string title;
/// <summary>
/// Gets the Tooltip.
/// </summary>
public string tooltip;
/// <summary>
/// Gets the key.
/// </summary>
public string key;
/// <summary>
/// Gets the Data.
/// </summary>
public string addClass;
/// <summary>
/// Gets the Children.
/// </summary>
public IList<ITreeItem> children;
/// <summary>
/// Gets the rel attr.
/// </summary>
public string rel;
/// <summary>
/// Gets the State.
/// </summary>
public bool isFolder;
/// <summary>
/// Gets the State.
/// </summary>
public bool isLazy;
/// <summary>
/// Initializes a new instance of the <see cref="TreeItemLeaf"/> class.
/// </summary>
public TreeItemLeaf()
{
children = new List<ITreeItem>();
}
/// <summary>
/// Initializes a new instance of the <see cref="TreeItemLeaf"/> class.
/// </summary>
/// <param name="type">The type of node.</param>
/// <param name="id">The Id of the node.</param>
/// <param name="title">The Title of the node.</param>
/// <param name="tooltip">The Tooltip of the node.</param>
public TreeItemLeaf(String type, Guid id, String title, String tooltip)
{
key = id.ToString();
this.title = title;
isFolder = false;
isLazy = false;
this.tooltip = tooltip;
children = new List<ITreeItem>();
}
}
/// <summary>
/// Tree Item.
/// </summary>
public class TreeItem : TreeItemLeaf
{
/// <summary>
/// Gets the State.
/// </summary>
public new bool isFolder;
/// <summary>
/// Initializes a new instance of the <see cref="TreeItem"/> class.
/// </summary>
public TreeItem() : base()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TreeItem"/> class.
/// </summary>
/// <param name="type">The type of node.</param>
/// <param name="id">The Id of the node.</param>
/// <param name="title">The Title of the node.</param>
/// <param name="tooltip">The tooltip of the node.</param>
public TreeItem(String type, Guid id, String title, String tooltip) : base(type, id, title, tooltip)
{
isFolder = true;
isLazy = true;
}
}
Once you have this, you can return a Json(IList<ITreeItem>) which you will need to build up from your results..
If you go to the Dynatee demo http://wwwendt.de/tech/dynatree/doc/samples.html , you can use Firefox/Firebug to study the HTTP requests to see exactly what is being passed in and returned.
My tree in the view is as follows :
// --- Initialize first Dynatree -------------------------------------------
$("#tree").dynatree({
fx: { height: "toggle", duration: 500 },
selectMode: 1,
clickFolderMode: 1,
children : #Html.Raw(String.Format("{0}", ViewData["tree"]).Replace("\"children\":[],", "")),
onLazyRead: function (node) {
node.appendAjax({
url: "#Url.Action("treedata", "tree")",
type: "GET",
data: { "id": node.data.key, // Optional url arguments
"mode": "all"
},
error: function(node, XMLHttpRequest, textStatus, errorThrown) {
}
}
});
}, //.... cut short for brevity
I am embeding the initial tree state in the "children:" part. And the Ajax reading is being set up in the "onLazyRead:" part.
My Ajax call is:
public JsonResult TreeData(FormCollection form)
{
return GetTreeData(Request.QueryString["id"], Request.QueryString["uitype"]);
}
The GetTreeData() function returns Json(ITreeItem);
I would recommend you use Firefox/Firebug and its "NET" function to see what is going and coming back.
Hope that helps.
I've just found Dynatree and I'm using it on my MVC project. Here's an example of how I did it. I decided to just put the data directly in the View like the basic example.
My data is a list of cities within California, grouped by county.
My controller simply passes a view model to my View and the view model has a CitiesAvailable property:
public IEnumerable<City> CitiesAvailable { get; set; }
My list of City objects is grabbed from the database (EF4) and the actual City object is the following:
In my View I create a ul containing the list of counties and their cities (I'm using Razor but webforms should be easy enough to figure out):
<div id="tree">
<ul id="treedata" style="display: none;">
#foreach (var county in Model.CitiesAvailable.Select(c => c.County).Distinct().OrderBy(c => c))
{
<li data="icon: 'false'">#county
<ul>
#foreach (var city in Model.CitiesAvailable.Where(c => c.County == county).OrderBy(c => c.Name))
{
<li data="icon: 'false'" id="#city.Id">#city.Name</li>
}
</ul>
</li>
}
</ul>
</div>
Then in my JavaScript I use the following:
$("#tree").dynatree({
checkbox: true,
selectMode: 3,
fx: { height: "toggle", duration: 200 }
});
It works great! Here's a sample of the output with a few items checked:
Let me know if anything doesn't make sense.
Note, I use data="icon: 'false'" in my li elements because I don't want the icons.
You can simply convert the object to json string, and send it to server as text
this is the js code:
var dict = $("#tree").dynatree("getTree").toDict();
var postData = JSON.stringify(dict["children"]);
$.ajax({ type: "POST",
url: "/UpdateServer/SaveUserTree",
data: {tree:postData},
dataType: "html"
});
And this is the controller code:
[HttpPost]
public void SaveUserTree(string tree = "")
{
HttpContext.Application["UserTree"] = tree;
}
You can send this string data back to client
if (HttpContext.Application["UserTree"] != null)
ViewBag.TreeData = new HtmlString(HttpContext.Application["UserTree"].ToString());
And finally, you can initial the tree, in the View with this data:
var treeData= #(ViewBag.TreeData)
$(function(){
// --- Initialize sample trees
$("#tree").dynatree({
children: treeData
});
});

Programatically get controller address of ASP.NET MVC application

Say I want to send an email from my MVC application containing a link back to an item.
So I want something in my controller like:
string link = "www.mysite/mycontroller/itemdetails/23";
can I retrieve this programatically so it works on whatever server/configuration i happen stick it on?
eg
string link = GetCurrentActionRoute() + "23";
public ActionResult Index()
{
string link = Url.Action(
(string)RouteData.Values["action"],
(string)RouteData.Values["controller"],
new { id = "23" },
Request.Url.Scheme
);
// TODO: do something with the generated link
return View();
}
I use the extension methods below from my Controller classes to generate links to various actions.
Examples:
string link = this.Action("Play");
string fullLink = this.FullUrlAction("Play", new { id = 1 });
Methods:
/// <summary>
/// Helper Extensions to the Controller class.
/// </summary>
public static class ControllerExtensions
{
/// <summary>
/// Get an action link for a controller.
/// </summary>
/// <param name="controller">Controller instance.</param>
/// <param name="action">Action to provide the link for.</param>
/// <returns>Link Url for the Action.</returns>
public static string Action(this Controller controller, string action)
{
RouteValueDictionary rvd = new RouteValueDictionary
{
{ "controller", controller.GetType().Name },
{ "action", action }
};
return RouteTable.Routes.GetVirtualPath(controller.ControllerContext.RequestContext, rvd).VirtualPath;
}
/// <summary>
/// Get an action link for a controller.
/// </summary>
/// <param name="controller">Controller instance.</param>
/// <param name="action">Action Name.</param>
/// <param name="parameters">Action Parameters.</param>
/// <returns>Link Url for the action with parameters.</returns>
public static string Action(this Controller controller, string action, object parameters)
{
string controllerName = controller.GetType().Name;
if (controllerName.EndsWith("Controller"))
{
controllerName = controllerName.Substring(0, controllerName.Length - 10);
}
return controller.Action(controllerName, action, parameters);
}
/// <summary>
/// Get an action link for a controller.
/// </summary>
/// <param name="controller">Controller instance.</param>
/// <param name="targetController">Target controller for action.</param>
/// <param name="action">Action Name.</param>
/// <param name="parameters">Action Parameters.</param>
/// <returns>Link Url for the action on the given controller.</returns>
public static string Action(this Controller controller, string targetController, string action, object parameters)
{
RouteValueDictionary rvd = new RouteValueDictionary(parameters)
{
{ "controller", targetController },
{ "action", action }
};
return RouteTable.Routes.GetVirtualPath(controller.ControllerContext.RequestContext, rvd).VirtualPath;
}
/// <summary>
/// Get a fully qualified action link for a controller.
/// </summary>
/// <param name="controller">Controller instance.</param>
/// <param name="action">Action Name.</param>
/// <param name="parameters">Action Parameters.</param>
/// <param name="requestUrl">Current request URI.</param>
/// <returns>Fully qualified Link Url.</returns>
public static string FullUrlAction(this Controller controller, string action, object parameters, Uri requestUrl)
{
string controllerName = controller.GetType().Name;
if (controllerName.EndsWith("Controller"))
{
controllerName = controllerName.Substring(0, controllerName.Length - 10);
}
return controller.FullUrlAction(controllerName, action, parameters, requestUrl);
}
/// <summary>
/// Get a fully qualified action link for a controller.
/// </summary>
/// <param name="controller">Controller instance.</param>
/// <param name="targetController">Target controller for action.</param>
/// <param name="action">Action Name.</param>
/// <param name="parameters">Action Parameters.</param>
/// <param name="requestUrl">Current request URI.</param>
/// <returns>Fully Qualified Link Url.</returns>
public static string FullUrlAction(this Controller controller, string targetController, string action, object parameters, Uri requestUrl)
{
string testUrl = VirtualPathUtility.ToAbsolute(controller.Action(targetController, action, parameters));
return new Uri(requestUrl, testUrl).ToString();
}
}
If the link will point to the same location as that of the application ,you may consider using the Url.Action(...) and its overloads.
Eg.
string actionRoute = Url.Action("action method name","controller name");
If you want to get the complete path, you can use :
string domainRoute = HttpContext.Request.Url.AbsolutePath;
and then concatenate the id with that.

ASP.NET MVC: creating controls dynamically

This is the control builder class...
public class ControlBuilder
{
/// <summary>
/// Html Control class for controlbuilder Control .
/// </summary>
protected HTMLControl formControl;
/// <summary>
/// Html Control class for the label.
/// </summary>
private HTMLControl labelControl;
/// <summary>
/// Getting the property for the Control .
/// </summary>
/// <history>
/// [LuckyR] 10/8/2009 Created
/// </history>
public HTMLControl Form
{
get { return formControl; }
}
/// <summary>
/// Creating a label for the Control.
/// </summary>
/// <history>
/// [LuckyR] 10/8/2009 Created
/// </history>
public HTMLControl Label
{
get { return labelControl; }
}
/// <summary>
/// Creating a construtor for the controlbuilder taking in Zero
/// arguments it creates a labl for the Control .
/// </summary>
/// <history>
/// [LuckyR] 13/8/2009 Created
/// </history>
public ControlBuilder() { }
/// <summary>
/// A construtor for the controlbuilder which
/// creates a label for the Control .
/// </summary>
/// <history>
/// [LuckyR] 10/8/2009 Created
/// </history>
public ControlBuilder(string labelName)
{
Label label = new Label();
label.Text = labelName;
label.Width= 200;
labelControl = new HTMLControl(label);
}
/// <summary>
/// Control build property that is used to biuld the Html
/// markup for the created Control.
/// </summary>
/// <history>
/// [LuckyR] 10/8/2009 Created
/// </history>
public string BuildControl()
{
this.CreateControl();
this.SetAttribute();
return this.RenderHTML();
}
/// <summary>
/// Render Html tags for the Control with label .
/// </summary>
/// <history>
/// [LuckyR] 10/8/2009 Created
/// </history>
public string RenderHTML()
{
return labelControl.RenderHTML() + ": " + formControl.RenderHTML();
}
/// <summary>
/// Used to Set Attributes for the Control .
/// </summary>
/// <history>
/// [LuckyR] 13/8/2009 Created
/// </history>
protected virtual void SetAttribute() { }
/// <summary>
/// Used to create the Control .
/// </summary>
/// <history>
/// [LuckyR] 13/8/2009 Created
/// </history>
protected virtual void CreateControl() { }
/// <summary>
/// A list of all the Controls that will be created during the
/// program run .
/// </summary>
private IList<ControlBuilder> Controls = new List<ControlBuilder>();
/// <summary>
/// A property to add Control to the ControlBuilder that are created by
/// the user.
/// </summary>
/// <history>
/// [LuckyR] 13/8/2009 Created
/// </history>
/// <param name="Control">Controls from the controlbuilder class</param>
public void AddControl(ControlBuilder Control)
{
Controls.Add(Control);
}
/// <summary>
/// A property to display the Controls that are created by
/// the user.
/// </summary>
/// <history>
/// [LuckyR] 13/8/2009 Created
/// </history>
public string Display()
{
string Html = string.Empty;
foreach (ControlBuilder builder in Controls)
{
Html += builder.BuildControl();
Html += "<br /><br />";
}
return Html;
}
}
}
this is how i build a control
public class TextBoxBuilder : ControlBuilder
{
/// <summary>
/// Creating a web Control textBox.
/// </summary>
private TextBox textBox;
/// <summary>
/// Creating an Id to add as an attribute .
/// </summary>
private string Id;
/// <summary>
/// Creating an Value to add as an attribute .
/// </summary>
private string Value;
/// <summary>
/// Creating a Textbox constructor which takes in LabelName and Id.
/// to create a label for the Control.
/// </summary>
/// <history>
/// [LuckyR] 10/8/2009 Created
/// </history>
public TextBoxBuilder(string labelName, string id , string value): base(labelName)
{
this.Id = id;
this.textBox = new TextBox();
this.Value = value;
}
/// <summary>
/// Used to Set properties for the Control .
/// </summary>
/// <history>
/// [LuckyR] 10/8/2009 Created
/// </history>
protected override void SetAttribute()
{
this.textBox.ID = this.Id;
this.textBox.Text = this.Value;
}
/// <summary>
/// Used to create the Control . That is done by calling the HtmlControl class
/// which inturn renders the particular Control for us .
/// </summary>
/// <history>
/// [LuckyR] 10/8/2009 Created
/// </history>
protected override void CreateControl()
{
this.formControl = new HTMLControl(this.textBox);
}
}
}
In my home controller i did this ...
public ActionResult Create()
{
///Where i am contacting the linq to sql classs for performing ths operagtion
foreach (var control in Rep.GetData(ScreenName))
{
string Type = control.Type;
string value = null;
if (id != Guid.Empty)
{
value = DataObj.GetValue(control.TableName, control.ControlName, id);
}
switch (Type)
{
case ("TextBox"):
/// Buliding a textBox box
controlbuilder.AddControl(new TextBoxBuilder(control.Field, control.ControlName, value));
break;
case ("CheckBox"):
/// Bulidig a CheckBox .
controlbuilder.AddControl(new CheckBoxBuilder(control.Field, control.ControlName , value));
break;
case ("DatePicker"):
/// Bulidig a DatePicker .
controlbuilder.AddControl(new DatePicker(control.Field, control.ControlName, value));
break;
case ("DropDownList"):
///Building a dropdownlist.
List<string> list = DataObj.GetDropDownValues(control.Id);
controlbuilder.AddControl(new DropDownListBuilder(control.Field, control.ControlName, list,value));
break;
case ("TextArea"):
/// Building a textBox area .
controlbuilder.AddControl(new TextArea(control.Field, control.ControlName , value));
break;
default:
break;
}
}
return View(controlbuilder);
}
The view page looks like this ...
<% using (Html.BeginForm())
{%>
<fieldset>
<legend>Fields</legend>
<p>
<%= ViewData.Model.Display() %>
</p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index")%>
</div>
since i am passing my class into the view i can retrieve all the data there with .display .
There is no concept of controls in ASP.NET MVC any longer.
You have two options:
When the user clicks a button, you handle this POST request in a controller action, set some sort of flag in your view model to now show a textbox, then return the same view which in its turn will look at the flag and generate a text box if required. This will incur a complete round-trip which will be somewhat similar to the postback in WebForms.
You do it in-place with JavaScript. You intercept a click event on a button and you inject an input/textarea HTML element into your document structure.

Resources