It's possible to add HTML elements dynamically in a WebPart's CreateChildControls() method, like so:
protected override void CreateChildControls()
{
base.CreateChildControls();
. . .
HtmlGenericControl _breakingSpace = new HtmlGenericControl("br");
this.Controls.Add(_breakingSpace);
}
Is it possible to also add CSS rules programatically? For example, I want to make "labels" (LiteralControls) block elements so that their width value can be set. Is something like the following pseudocode possible?
CSSRule displayInlineBlock = new CSSRule("display: inline-block");
CSSRule width20em = new CSSRule("width: 20em");
reqDateStr.ApplyCSSRule(displayInlineBlock);
reqDateStr.ApplyCSSRule(width20em);
?
I've tried applying those CSS rules inline to the Literal Control itself like this:
LiteralControl reqDateStr = new LiteralControl("<span class=\"finaff-webform-field-label\" style=\"display: inline-block\"; width:200px\">Requester Date:</span>");
...but it doesn't work any differently than what I had before, which was:
LiteralControl reqDateStr = new LiteralControl("<span class=\"finaff-webform-field-label\">Requester Date:</span>");
You can see how the form looks here
UPDATE
In answer to ceej's inquiry as to what HTML is generated, here it is, straight from the browser's "Show Source" ("inline" is there, but seems to have no effect):
<h1>UCSC - Direct Payment Form</h1>
<table>
<tr>
<td colspan="4"><h2 class="finaff-webform-field-label">Section 1: Payment Information</h2></td>
<td colspan="2"><h2 class="finaff-webform-field-label">Section 2: Requester Information</h2></td>
</tr>
<tr>
<td><span class="finaff-webform-field-label" style="display: inline-block"; width:200px">Requester Date:</span></td>
<td><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl11" type="text" value="4/23/2015" class="finaff-webform-field-input" /></td>
<td><span class="finaff-webform-field-label">Payment Amount:</span></td>
<td><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl14" type="text" class="finaff-webform-field-input" /></td>
<td><span class="finaff-webform-field-label">Requester Name:</span></td>
<td><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl17" type="text" class="finaff-webform-field-input" /></td>
</tr>
<tr>
<td><span class="finaff-webform-field-label">Payee Name:</span></td>
<td colspan="3"><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl21" type="text" size="64" class="finaff-webform-field-input" /></td>
<td><span class="finaff-webform-field-label">Dept / Div Name:</span></td>
<td><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl24" type="text" class="finaff-webform-field-input" /></td>
</tr>
<tr>
<td><span class="finaff-webform-field-label">Remit Address:</span></td>
<td colspan="3"><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl28" type="text" size="64" class="finaff-webform-field-input" /></td>
<td><span class="finaff-webform-field-label">Phone:</span></td>
<td><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl31" type="text" class="finaff-webform-field-input" /></td>
</tr>
<tr height="2em">
<td><span class="finaff-webform-field-label"> OR</span></td>
</tr>
<tr>
<td><span class="finaff-webform-field-label">Mail Stop:</span></td>
<td colspan="3"><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl37" type="text" size="64" class="finaff-webform-field-input" /></td>
<td><span class="finaff-webform-field-label">Email:</span></td>
<td><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl40" type="text" class="finaff-webform-field-input" /></td>
</tr>
<tr>
<td><span class="finaff-webform-field-label">Last 4 Digits SSN or ITIN:</span></td>
<td><input name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl44" type="text" class="finaff-webform-field-input" /></td>
</tr>
<tr>
<td colspan="5"><input id="ctl00_ctl24_g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c_ctl47" type="checkbox" name="ctl00$ctl24$g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c$ctl47" /><label for="ctl00_ctl24_g_5f7ce2fb_5653_4cc9_b9b8_b00ee0d0910c_ctl47"><span class="finaff-webform-field-label">204 submitted or on file. <strong>NOTE:</strong> If not on file, complete a Payee_Setup_204</span></label></td>
</tr>
</table>
This should be possible. What is the generated HTML that is produced? Is the in-line style actually being output? Is the HTML malformed?
I think it might be as simple as having incorrectly specified the style in your line that applies the styles inline in the constructor of the LiteralControl. You are closing the style after inline-block - should this not be `style=\"display: inline-block; width:200px\? This would make the complete line
LiteralControl reqDateStr = new LiteralControl("<span class=\"finaff-webform-field-label\" style=\"display: inline-block; width:200px\">Requester Date:</span>");
You can certainly add dynamic controls within a web part and it should be done in the CreateChildControls method. Personally I would use a LiteralControl rather than an HtmlGenericControl for putting static text or mark up such as <br> on the page.
As for CSS and styling - most web controls have a CssClass property and a Style property. However, the control you have chosen (LiteralControl) does not. Have you considered using a Label control? This will generate a <span> and you can set the Style property. You would have something like
var reqDateStr = new Label
{
CssClass= "finaff-webform-field-label",
Text = "Requester Date:"
};
reqDateStr.Style.Add("display", "inline-block");
reqDateStr.Style.Add("width", "200px");
this.Controls.Add(reqDateStr);
You can even set an AssociatedControlId property, which will result in a <label for="textboxId"> being output. The value should be the Id of the input control, e.g. your text box. This might be desirable in your scenario.
Hope this helps...
Related
I'm trying to add some rows data in a datatable, first via Pug and then later on via javascript.
I add the first rows getting data via controller call, and then adding it via pug parse:
<div class="x_content">
<table id="datatable-buttons" class="table table-striped table-bordered bulk_action">
<thead>
<tr>
<th>
<th>Aprovado</th>
</th>
<th>Nome</th>
<th>Email</th>
<th>Data de nascimento</th>
<th>Cidade</th>
<th>Gênero</th>
<th>Escolaridade</th>
<th>Instituição de ensino</th>
<th>Semestre</th>
<th>Token</th>
<th>Selection Status</th>
</tr>
</thead>
<tbody>
for candidate in candidates
- var formatedCandidate = candidateService.formatCandidateForDataTable(candidate, newTrueCheckbox, newFalseCheckbox);
<tr>
<td>
<th>
if formatedCandidate.isCandidateApproved
<input type="checkbox" id="check-all" class="flat" checked>
else
<input type="checkbox" id="check-all" class="flat">
</th>
</td>
<td>
= formatedCandidate.name
</td>
<td>
= formatedCandidate.email
</td>
<td>
= formatedCandidate.bornDate
</td>
<td>
= formatedCandidate.city
</td>
<td>
= formatedCandidate.gender
</td>
<td>
= formatedCandidate.educationLevel
</td>
<td>
= formatedCandidate.educationInstitution
</td>
<td>
= formatedCandidate.educationSemester
</td>
<td>
= formatedCandidate.token
</td>
<td>
= formatedCandidate.selectionStatus
</td>
</tr>
</tbody>
</table>
This way, it manages to render the checkbox with the right style:
Later on, I try to update the rows via a "reload" button, getting data via a get request and then adding rows via javascript:
$.get("candidates/getCandidatesForTable", function(candidatesArray){
candidateTable.clear().draw();
candidatesArray.forEach((candidate, index) => {
debugger;
if (candidate[1]) {
candidate[1] = `<th>
<input type="checkbox" id="check-all" class="flat" checked/>
</th>`;
} else {
candidate[1] = `<th>
<input type="checkbox" id="check-all" class="flat"/>
</th>`;
}
candidateTable.row.add(candidate).draw();
});
});
Although I inserted the HTML code via javascript using the same properties as it was added via pug, the checkbox was rendered different: it is rendered, but the css style is now gone:
How should I add the a checkbox via javascript and still get the correct css styling?
I have one table in my web page. It has column headers as well as row headers. In every cell there is a checkbox. It's not possible to provide visual labels to all the check boxes, so I am providing the labels using 'aria-label' property.
When I am navigating using the table shortcut keys (Alt+Ctrl+Arrow keys) the screen reader is announcing- row headers, column headers and 'aria-label' text.
Eg.'Action 1 checkbox not checked select action 1 for all event column 2', which is redundant.
So if I remove both the table headers, screen reader will announce only 'aria-label' text, which is meaningful and enough to identify the purpose of the checkbox. But as per the WCAG guideline(1.3.1 Info and relationship) table must have header associated with the table data.
So here are my questions:
If I remove the table headers-
Will it violate the WCAG compliance?. What is the interaction of the screen reader users with table?, Do they always need headers for navigation?. Will the screen reader users be able to complete the table activity by hearing 'aria-label' text only?.
Please see the code snippet:
<table>
<tr>
<th scope="col" width="40%">Events</th>
<th scope="col" align="left">Action 1</th>
<th scope="col" align="left">Action 2</th>
<th scope="col" align="left">Action 3</th>
</tr>
<tr>
<th scope="row">Select All</th>
<td><input type="checkbox" name="Action11" id="Action11" aria-label="Select action 1 for all event" /></td>
<td><input type="checkbox" name="Action12" id="Action12" aria-label="Select action 2 for all event" /></td>
<td><input type="checkbox" name="Action13" id="Action13" aria-label="Select action 3 for all event" /></td>
</tr>
<tr>
<th scope="row">Event 1</th>
<td><input type="checkbox" name="Action21" id="action21" aria-label="Select action 1 for event 1" /></td>
<td><input type="checkbox" name="Action22" id="action22" aria-label="Select action 2 for event 1" /></td>
<td><input type="checkbox" name="Action23" id="Action23" aria-label="Select action 3 for event 1" /></td>
</tr>
<tr>
<th scope="row">Event 2</th>
<td><input type="checkbox" name="Action31" id="action31" aria-label="Select action 1 for event 2" /></td>
<td><input type="checkbox" name="Action32" id="action32" aria-label="Select action 2 for event 2" /></td>
<td><input type="checkbox" name="Action33" id="Action33" aria-label="Select action 3 for event 2" /></td>
</tr>
</table>
Thanks in advance!
Keep the table headers. When navigating as a table (CTRL+ALT+arrows), the typical screen reader behavior is to only announce the header when a new row or column is reached, which is to prevent unnecessary repetition. However some things, such as announcing row and column numbers, can be customized by the user. Using aria-label here slightly begins to mess with those preferences by forcing repetitive speech.
Instead, use aria-labelledby to associate both the row and column headers with each checkbox as follows:
<table>
<tr>
<th scope="col" width="40%">Events</th>
<th id="a1" scope="col" align="left">Action 1</th>
<th id="a2" scope="col" align="left">Action 2</th>
<th id="a3" scope="col" align="left">Action 3</th>
</tr>
<tr>
<th id="sa" scope="row">Select All</th>
<td><input type="checkbox" name="Action11" id="Action11" aria-labelledby="sa a1" /></td>
<td><input type="checkbox" name="Action12" id="Action12" aria-labelledby="sa a2" /></td>
<td><input type="checkbox" name="Action13" id="Action13" aria-labelledby="sa a3" /></td>
</tr>
<tr>
<th id="e1" scope="row">Event 1</th>
<td><input type="checkbox" name="Action21" id="action21" aria-labelledby="e1 a1" /></td>
<td><input type="checkbox" name="Action22" id="action22" aria-labelledby="e1 a2" /></td>
<td><input type="checkbox" name="Action23" id="Action23" aria-labelledby="e1 a3" /></td>
</tr>
<tr>
<th id="e2" scope="row">Event 2</th>
<td><input type="checkbox" name="Action31" id="action31" aria-labelledby="e2 a1" /></td>
<td><input type="checkbox" name="Action32" id="action32" aria-labelledby="e2 a2" /></td>
<td><input type="checkbox" name="Action33" id="Action33" aria-labelledby="e2 a3" /></td>
</tr>
</table>
I agree with Adam. This table appears to be used for layout rather than for displaying structured tabular data.
There's nothing wrong with layout tables, but you should NOT use table heading <th> elements (use <td> instead), and remove all of your aria markup as well to avoid confusing screen-reader users. Use standard HTML form labels instead of the aria-labelledby attribute.
Putting additional data table markup (i.e. table headers, aria markup) would actually cause it to be less accessible, regardless of what any automated testing tools may tell you.
WebAIM has a pretty good explanation of layout tables vs. data tables, if you're interested in learning more about this subject.
http://webaim.org/techniques/tables/data
If I remove the table headers- Will it violate the WCAG compliance?
When you can consider that you are not displaying tabular data and use the table tag for layout purpose, WCAG lets you use a table tag for layout tables.. (as long as it can be linearized)
IMHO, what you are showing is a list of events with 3 actions. You may consider that it's not a data table.
In your case, the problem is that I don't see how, by removing table headers and without visual label for the checkboxes, you would help people without a screenreader know the intent of the checkboxes. aria-label is of no use for people not using a screenreader. WCAG require visual instructions.
Edit for clarity:
WCAG focuses mainly on data tables (where headings are required) but does not forbid layout tables (where headings are forbidden). All the question here is to understand if your table is really a data table or a layout table.
For instance, here, you could have used an ul list:
Events
<ul>
<li>Event 1
<input type="checkbox" title="Action1" aria-label="Action1" />
<input type="checkbox" title="Action2" aria-label="Action2" />
<input type="checkbox" title="Action3" aria-label="Action3" />
</li>
<li>Event 2
<input type="checkbox" title="Action1" aria-label="Action1" />
<input type="checkbox" title="Action2" aria-label="Action2" />
<input type="checkbox" title="Action3" aria-label="Action3" />
</li>
</ul>
And this makes me think that your table is not a data table, and that you use the table tag only for design for vertical alignment.
This is quite conceptual
EDIT 2: This alternative use of ul vs td (which is just to illustrate that you are not really using a data table) does not solve the problem of a visible label (also, curiously, this not a requirement in WCAG).
My opinion is that a visible label next to the checkbox is the best thing. If you can't, you have two options :
relying on javascript to display the title attribute when the field is focused
use small icons next to each checkbox (with correct alternative text which could be used to label the field)
I have a simple password reset dialog, which enables users to set a custom password.
<form id="resetPassword"
action="XXXXX">
<fieldset><input type="hidden" name="userId" value="${user.id}" />
<table>
<tbody>
<tr>
<td><input id="resetCustomPassword" class="ui-widget" type="checkbox"></td>
<td><label>Set Custom Password</label></td>
</tr>
</tbody>
<tbody style="display: none;">
<tr>
<td><label for="newPassword"> New Password: </label></td>
<td><input id="newPassword" class="ui-widget" type="password"></td>
</tr>
<tr>
<td><label for="reTypeNewPassword"> Retype New Password: </label></td>
<td><input id="reTypeNewPassword" class="ui-widget" type="password"></td>
</tr>
</tbody>
Now, if a user checks for "Set Custom password", I dynamically show the new password fields. The problem is in my this label in the above form:
<td><label>Set Custom Password</label></td>
This gets dynamically adjusted to the RIGHT side, so it aligns with the new password fields.
How can I let my above label be static, and not adjust itself dynamically?
Thanks!
Try this:
<td align="left"><label>Set Custom Password</label></td>
You're far better off using styled unordered lists as containers for forms, rather than tables.
See: http://www.alistapart.com/articles/multicolumnlists
I was wondering if any one could help me out; I have a table which looks something like the following:
<table id="Table1" border="0">
<tr>
<td><b>1.</b> Question 1</td>
</tr><tr>
<td style="border-width:5px;border-style:solid;"></td>
</tr><tr>
<td align="left" style="width:1000px;"><input id="Radio1" type="radio" name="Group1" value="Radio1" /><label for="Radio1">Answer1</label></td>
</tr><tr>
<td align="left" style="width:1000px;"><input id="Radio1" type="radio" name="Group1" value="Radio1" /><label for="Radio1">Answer2</label></td>
</tr><tr>
<td align="left" style="width:1000px;"><input id="Radio1" type="radio" name="Group1" value="Radio1" /><label for="Radio1">Answer3</label></td>
</tr><tr>
<td align="left" style="width:1000px;"><input id="Radio1" type="radio" name="Group1" value="Radio1" /><label for="Radio1">Answer4</label></td>
</tr><tr>
<td style="height:30px;"></td>
</tr><tr>
<td><b>2.</b> Question 2</td>
</tr><tr>
<td style="border-width:5px;border-style:solid;"></td>
</tr><tr>
<td align="left" style="width:1000px;"><input id="Radio2" type="radio" name="Group2" value="Radio2" /><label for="Radio2">yes</label></td>
</tr><tr>
<td align="left" style="width:1000px;"><input id="Radio2" type="radio" name="Group2" value="Radio2" /><label for="Radio2">no</label></td>
</tr><tr>
<td style="height:30px;"></td>
</tr>
</table>
How do I go about looping through each group of radio buttons and getting the text of the selected radio button?
The code displayed above is created dynamically ... in my aspx file I have the following code:
<asp:Table ID="Table1" runat="server">
</asp:Table>
If you want to access the rows in ASP.NET (on the server side), you need to convert the table, rows and the cells to server control (using runat="server") and iterate through the controls in the table.
EDIT : :- If you are adding the rows, cells and radionbuttons following way, all of them will be the server controls (and are runat=server) so that you can access them the way I mentioned above:--
// Create new row and add it to the table.
TableRow tRow = new TableRow();
table1.Rows.Add(tRow);
for (cellCtr = 1; cellCtr <= cellCnt; cellCtr++)
{
// Create a new cell and add it to the row.
TableCell tCell = new TableCell();
RadioButton rdb = new RadioButton();
rdb.ID = "rdb_" + cellCtr.ToString();
rdb.Text = "radio button";
rdb.GroupName = "rdbGroup";
tCell.Controls.Add(rdb);
tRow.Cells.Add(tCell);
}
EDIT:-
You can find the controls in each cell.Something like below:-
foreach(TableCell cell in tableRow.Cells)
{
foreach(Control ctrl in cell.Controls)
{
if(ctrl is RadioButton)
{
if(ctrl.Selected)
{
string rdValue=ctrl.Text;
}
}
}
}
Or If you want to iterate on the client side using Javascript, have a look here and you dont have to apply runat="server".
It sounds like you're starting with a barebones <table> in your markup page, and dynamically adding those <input> afterwards.
Consider taking this approach:
Add the runat="server" attribute to your table.
In the code where you're adding those <input> tags, add a new RadioButton control. Use an ID here that you can predict later. Perhaps you can use a RadioButtonList instead, if the choices are logically grouped!
It's unclear if you're manually adding those <tr> and <td> as strings. Consider the option of new TableRow() and new TableCell(). Then add the new RadioButton to the TableCell.Controls collection with tc.Controls.Add(myNewRadioButton);
In your postback code, simply refer to your RadioButton controls by id, or even loop through the Controls collection property of the Table1.
foreach (Control x in Table1.Controls)
{
if (x.GetType().ToString().Equals("System.Web.UI.WebControls.RadioButton"))
{
if (((RadioButton)x).Checked)
{
//proceed.
}
}
}
Convert all controls to server controls (by adding the runat="server" attribute). You can then programatically access what you need o. The server.
I am having problems getting my form to Post to my Save method in a controller. I am new to MVC, and have followed several examples to try to get this to work. Here is my html markup:
<form action="Edit/Save" method="post">
<fieldset>
<legend>Personal Information</legend>
<table class="editGrid">
<tr>
<td><label for="txtFirstName">First Name:</label></td>
<td><input type="text" id="txtFirstName" value="<%=user.FirstName %>" name="FirstName" /></td>
</tr>
<tr>
<td><label for="txtLastName">Last Name:</label></td>
<td><input type="text" id="txtLastName" value="<%=user.LastName %>" name="LastName" /></td>
</tr>
<tr>
<td><label for="txtNtLogin">NT Login:</label></td>
<td><input type="text" id="txtNtLogin" value="<%=user.NtLogin %>" name="NtLogin" /></td>
</tr>
<tr>
<td><label for="txtHireDate">Hire Date:</label></td>
<td><input type="text" id="txtHireDate" value="<%=string.Format("{0:d}",user.HireDate) %>" name="HireDate" /></td>
</tr>
</table>
</fieldset>
<fieldset>
<legend>Job Information</legend>
<table class="editGrid">
<tr>
<td><label for="CostCenters">Cost Center:</label></td>
<td><%=Html.DropDownList("CostCenters")%></td>
</tr>
<tr>
<td><label for="Managers">Manager:</label></td>
<td><%=Html.DropDownList("Managers")%></td>
</tr>
<tr>
<td><label for="Responsibilities">Responsibility:</label></td>
<td><%=Html.DropDownList("Responsibilities")%></td>
</tr>
<tr>
<td><label for="Departments">Department:</label></td>
<td><%=Html.DropDownList("Departments")%></td>
</tr>
<tr>
<td><label for="Active">Active:</label></td>
<td><%=Html.CheckBox("Active",user.Active) %></td>
</tr>
<tr>
<td><label for="txtHireDate">Hire Date:</label></td>
<td><%=Html.TextBox("txtHireDate",string.Format("{0:d}",user.HireDate)) %></td>
</tr>
<tr>
<td><label for="txtReleaseDate">Release Date:</label></td>
<td><%=Html.TextBox("txtReleaseDate",string.Format("{0:d}",user.ReleaseDate)) %></td>
</tr>
</table>
</fieldset>
<input type="submit" value="Save Changes" />
</form>
This form routes to a Save method in my EditController. Here is the code for my EditController's Save method:
public class EditController : Controller
{
public ActionResult Save()
{
//Save code goes here
}
I have tried using the html form tag, and also the Html helper code:
using (Html.BeginForm("Save", "Edit"))
Here is the entry from my RegisterRoutes method in the Global.asax file:
routes.MapRoute("EditSave", "{controller}/Save",
new { controller = "Edit", action = "Save" });
No matter what I do, the submit button does not trigger the Save method. Yet, if I manually key in the Url, The code breaks right into the Save method.
Edit:
Per Craig Stuntz's comment, I checked the source of the page. The page actually contains 2 forms, although only 1 is coded on the page by myself: Here is the HTML that appears prior to my form tag:
<form name="aspnetForm" method="post" action="44" id="aspnetForm">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNjM3OTAyNTUzZGQrHhVn9+t78aHxN0vHvKUJ8DQWlQ==" />
</div>
<div id="nav">
<span id="navLinks">
Placeholder Link
</span>
<span id="userName">
<span id="ctl00_lblUserName" class="UserName">Welcome, Test User</span>
</span>
</div>
<div id="Content">
<div id="formContainer">
<form action="Edit/Save" method="post">
I didn't think MVC generated viewstate or additional form tags. I am pulling data and populating it into this form using another method from the same controller. Am I doing something wrong here?
Ok, got the answer. And thanks Craig for having me look at the HTML again! My master page had generated a form tag in it without my knowing it, so I essentially had nested forms on the same page. After I removed the form from the Master Page, everything worked perfectly.