what is the best and most simplest way to create tooltip text for textboxes
With JavaScript and probably with a framework like jQuery that fits very well with ASP.NET MVC. Using the framework means that someone's alread done the hard work and written a plugin for it!
qtip
tooltip
List of some tooltip plugins
There is of course the title attribute on text inputs that shows as a popup tip in some browsers.
I found this to be the simplest and easy to maintain approach:
Create description using data annotation for the property of your model
Example:
[Display(Name="MyTextBox", Description = "Title for your entry")]
public string MyTextBox{ get; set; }
Then in your view access the description above using:
#Html.TextBoxFor(model => model.MyTextBox, new { title = ModelMetadata.FromLambdaExpression(model => model.MyTextBox, ViewData ).Description })
Just use the title tag :
<input type="text" title="Hello I'm the tool-tip"/>
Mvc way :
#Html.TextBoxFor(t => t.NameOfCustomer, new{ title= "Hello I'm the tool-tip" })
It's not fully customizable as is, but it does not require extra javascript nor a framework.
Use the data annotations on your model to put the tooltip in the Description property of the DisplayAttribute.
Then write your own Html Helper function that puts the Description property into the title attribute of the TextBox input field. You can call the helper TextBoxWithTooltipFor
In your view definition you can then replace the call to #(Html.TextBoxFor(...)) with the call to #(Html.TextBoxWithTooltipFor(...))
Here is the code that is tested and works.
Related
Using ASP.NET MVC and Razor, I'm trying to pass a ViewBag item from the controller to a HiddenFor field (using Razor). I get the following message: Extension methods cannot by dynamically dispatched.
#Html.HiddenFor(m=>m.PortfolioId, ViewBag.PortfolioId);
You are getting this error because ViewBag is dynamic type. You can use ViewModel instead of ViewBag to solve this problem.
Alternatively you can use following or plain html as suggested by iceburg:
#Html.Hidden("id", (string)ViewBag.PortfolioId)
I'm not sure how to do it with the helper but you can achieve the same markup useing plain html:
<input type="hidden" name="PortfolioId" id="PortfolioId" value="#ViewBag.PortfolioId" />
#Html.HiddenFor(i =>i.PortfolioId, htmlAttributes: new { #Value = ViewBag.PortfolioId })
will solve your problem if your "PortfolioId" is really a property model.
I've been looking for the solution and I haven't find a way to get my head around it. So I hope you could give me some clues to achieve that.
Basically I need to change a value of a _Layout from its rendered PartialView. I use to do this using webforms .aspx master pages and FindControl method but I cannot find a solution to do this in MVC Razor engine.
My Layout page has an ActionLink and a div tag place-holder to display the partial-views, Now I need to know how to change the value of Text1 from the partial-view pages within the DIV tag:
Is JavaScript the only way that I can do this ?
<input id="Text1" type="text" />
<div>
#Ajax.ActionLink("Personal Info", "Personal", "Portal", new { area = "Resume" },
new AjaxOptions { UpdateTargetId = "result", HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
OnBegin = "blockUi",
OnSuccess = "onTabChanged(this, 'Personal Information')"
},
new { #class = "text-strong" })
</div>
<div id="result">#RenderBody()</div>
Appreciate your contributions in advance.
Javascript is the way this is handled I think.
You might be able to do some trickery with controllers and the ViewBag (like how the page title is set with the ViewBag in a default MVC project).
You could also maybe set it to some global variable or something, and have your partial view change that variable.
Both those solutions though would require a page reload.
But using javascript is probably the best, you could do it in the onTabChanged function.
<script>
function onTabChanged(param1, param2) {
var el = document.getElementById("Text1");
el.value = "Whatever you want here";
}
</script>
I think the easiest way is using a ViewBag that you play around with in your controller/view/partial view.
In WebForms you can use the FindControl method because a PostBack was made. So the entire page was rendered again.
In the example you posted, I assumed that the request made by Ajax.ActionLink that update the div result, returns a view that may use the same Layout, but is in another context so you don't have access to the same input text from the rendered page where Ajax.Action link was triggered.
So, if you have multiples Ajax.ActionLink that updates the <div id="result">, you need to handle the success method on onTabChanged, like #Kyle Gobel suggested.
In my application I have a lot of UI elements (particuarly buttons) where I am repeating the same code over and over.
For example in multiple views I might have an edit button that is created with the following code:
#Html.ActionLink("Edit", "Edit", "SomeController", null, new { #class="button large blue" });
The problem here is that I am hard coding the label and styling, so if I want to make changes to the button styling or label, I would have to make them in multiple views. This would be tedious to do, as I would have to track down every button.
So now I am looking at creating a templating mechanism, where I can define a button template in a central area and bring it in to any view I want to use it in.
I have considered two options, which I have tried to sketch out in semi-real world code below.
My question is, am I on the right track here? Which option would be better and for which reasons? Is there already something out there I could consider using, or is there another way which I haven't thought of?
Thanks for your help.
Web.Config Templates
Create a custom class that can bring in template configuration from web.config file. For example:
<ui.HtmlTemplates>
<add templateKey="FormCancel" tag="a" class="form-button large black" />
<add templateKey="FormSave" tag="input" type="submit" class="form-button large green" />
</ui.HtmlTemplates>
And then could call them in with syntax such as this (method signature is contrived)
#HtmlTemplates.Build("FormCancel", Url.Action("Index", "Home"))
Partial View Templates
Create strongly typed partial views with the template I want.
ViewModel
public class UiButtonModel
{
public string Url{ get; set; }
}
Partial View
// Assume the file is called "_Button_FormCancel"
#Model path.to.model.directoy.UiButtonModel
Cancel
Use
#Html.Partial("_Button_FormCancel", new UiButtonModel(){Url = Url.Action("Index", "Home"));
Another option is to create extension methods off of HtmlHelper to create prepackaged HTML output using code:
using System.Web.Mvc;
using System.Web.Routing;
public static class MyHtmlExtensions
{
public static string SaveButton(this HtmlHelper helper, string title = "Save", IDictionary<string, object> htmlAttributes = null)
{
var builder = new TagBuilder("button");
builder.Attributes.Add("type", "button");
builder.AddCssClass("form-button");
builder.AddCssClass("large");
builder.AddCssClass("green");
if (htmlAttributes != null) builder.MergeAttributes(htmlAttributes);
builder.SetInnerText(helper.Encode(title));
return builder.ToString();
}
public static string CancelButton(this HtmlHelper helper, string title = "Cancel", string actionName, string controllerName, RouteValueDictionary routeValues = null, IDictionary<string, object> htmlAttributes = null)
{
var urlHelper = new UrlHelper(helper.ViewContext.RequestContext, helper.RouteCollection);
var builder = new TagBuilder("a");
builder.Attributes.Add("href", urlHelper.Action(actionName, controllerName, routeValues));
builder.AddCssClass("form-button");
builder.AddCssClass("large");
builder.AddCssClass("green");
if (htmlAttributes != null) builder.MergeAttributes(htmlAttributes);
builder.SetInnerText(helper.Encode(title));
return builder.ToString();
}
}
Then just make sure the namespace of MyHtmlExtensions is either added to your page directly, or included in all pages via web.config, and use it like this in your view (razor syntax):
<div class="form-buttons">
#Html.CancelButton("Index", "Home")
#Html.SaveButton()
</div>
This method is particularly well suited for creating output consistently across several solutions, as all you need to do is reference the containing assembly and import the namespace.
I create these kinds of templates and put them in my Views/Shared folder.
I have templates like:
AddButton.cshtml
DeleteButton.cshtml
SaveButton.cshtml
...
Then, when I need to call one of them in whatever View, I just call this for example:
#Html.Partial("SaveButton");
Using T4MVC, it gets even better with compile time checking (no more literal strings):
#Html.Partial(MVC.Shared.Views.SaveButton)
Doing so I have a common/central place to change a specific button config. No need to go view after view to change something.
This is the problem that css was designed to handle. I fail to understand the problem. If you want to make changes, you change the CSS and it affects all the buttons that have that styling.
Part of your problem is that you're using style like "blue". If you want to change it to red, you have to change it everywhere.
Instead, you should have a class for the button, then you can simply change the button style and you don't have to worry about redefining blue to red.
I have a blogpost edit page where you can either save your edits or upload an image (multiple submits in a single form). When you upload an image, the image link gets appended to a TinyMCE content area.
The fields for the form are in a viewusercontrol(shared with create page). Both the viewpage and usercontrol inherit from BlogPost so the model's being passed directly using <% Html.RenderPartial("Fields", Model); %>
So here's the weird thing; in my controller, when I append the image link to the textarea, nothing happens to the textarea in the view
On my viewpage I have a label for Model.Title and within the usercontrol I have the textbox for editing Model.Title.
If I update the label in the controller - model.Title = "New Title" - the updated model data changes for the label in the viewpage but not the textbox in the usercontrol.
My Controller is like this:
// /edit/{id}
public ViewResult Edit(int id, BlogPost model, string submit)
{
if (ModelState.IsValid)
{
switch (submit)
{
case "Upload":
var files = UploadFiles(Request.Files); // uploading works
model.Content += files[0].Link; // model is updated but not cascaded at runtime
model.Title = "Test"; // Force a title change to reproduce the issue
return View(model);
default:
repository.Update(model);
break;
}
}
return View(model);
}
Any ideas as to what's causing this and how to fix it? Thanks.
I am using 4.0 and MVC 2
Turns out that this behaviour is by design and has been answered by Phil Haack here:
Possible bug in ASP.NET MVC with form values being replaced.
There's also a blog post about this here:
ASP.NET MVC’s Html Helpers Render the Wrong Value!
For my scenario (appending an image to tinymce), I think it's safe to clear the ModelState because we're explicitly appending to a textarea and not doing any validation yet.
Is there any chance that there is code in the top level view that is changing the value of Model.Title before the RenderPartial is called?
I have a textbox that I am defining as
<%= Html.TextBox("Username", Model.Form.Username,
new { #class = "textbox", #disabled = "disabled" })%>
The action is defined as
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult EditLogin(LoginForm post) {
...
return View(model);
}
When I POST to this, Username will be blank. All other properties bind correctly, but if I change #disabled="disabled" to #readonly="readonly" the username binds properly and everything works.
It looks like model binding ignores values in disabled fields. Is there a way around this? I still need the field's value to bind to the model. I can use readonly but would prefer to use disabled so it is visually apparent to the user that they cannot edit the value of the field.
I believe a form field that is disabled does not submit anything. If you have a form and disable the foo field in that form, when you post the post will not have the value for the foo field. This is simply the nature of disabling a field in HTML and is not a MVC issue.
use readonly - will disable input but you'll still have it in the binding.
You could apply a style on the div to make it looked greyed out maybe?
<div class="editor-label">
#Html.LabelFor(model => model.FileName)
</div>
<div class="editor-field-greyed-out">
#Html.TextBoxFor(model => model.FileName, new { #readonly = true })
#Html.ValidationMessageFor(model => model.FileName)
</div>
If you want the value to be sent back, but not be editable, consider placing it in a hidden field. Obviously, don't do this for anything that requires a degree of security, since a user can tamper with it.
You can do a workaround by adding a hidden field with the same value ;)
<%= Html.Hidden("Username", Model.Form.Username)%>
As suggested in the comments, readonly instead of disabled can be an option but it will not work for select boxes. Instead of creating a hidden input, you can keep the inputs or selects as disabled and still pass the data by changing the disabled property with JavaScript at the submit.
Using jQuery it'd look like this:
$('form').on('submit', function(){
$('input, select').prop('disabled',false);
return true;
});
Easiest way to submit disabled fields is to copy them over to an invisible, non disabled control before submit. Some people create those controls manually and hook up to the on change event in jQuery to copy them on demand, but this solution below is generic, easy and less chatty - although one rule: you must create (render) a clean page after postback (so
$('#submitBtn').closest('form').one('submit', function() {
var $form = $(this);
// input, textarea, select, option, ----- button, datalist, keygen, output, optgroup
$form.find('input:disabled, textarea:disabled, select:disabled, option:disabled').each(function () {
var $item = $(this);
var hiddenItem = $item.clone();
hiddenItem.removeAttr('id');
hiddenItem.removeAttr('disabled');
hiddenItem.attr('style', 'display: none');
$item.after(hiddenItem);
});
});
#readonly = true does not work on my page. I did additional research. Here is the article that explains it
ReadOnly attribute doesn't work in ASP.NET MVC Models