Asked by:
Tables still appear in (some) templated membership controls

Question
-
User-1385398420 posted
First off, I appreciate the efforts of the team in making the CSS adapters!I was glad to see that membership controls were added to the latest beta release. However, I did notice that all of them (with one exception) still put a TABLE wrapper around the content when using a templated control. It happens on the Login and PasswordRecovery controls, which generate output like this:
<div class="AspNet-Login"><table id="ctl00_content_LoginForm" cellspacing="0"
cellpadding="0" border="0" style="border-collapse:collapse;">
<tr>
<td>
<!-- actual content from LayoutTemplate here --> </td>
</tr>
</table>
</div>Although I like the effort of the table-less designs, I prefer forms that use tags like FIELDSET and LEGEND, and that can be designed to more closely mirror the other forms on my sites, hence my desire to use templates. Why do the Login and PasswordRecovery controls continue to add the TABLE wrapper? It seems it something more internal to the .Net Framework that the current CSS adapters aren't filtering out, because there are definitely no TABLE tags being created by the adapters.
Ironically, the CreateUserWizard did not add a table wrapper around the CreateUserWizardStep -- but it did add it around the CompleteWizardStep.
I did some stepping through of code and stack traces to see if I could find anything different; the only thing of interest was that the CreateUserWizard called the CreateChildControls method during the Init phase, whereas the Login and PasswordRecovery called it during the PreRender phase (apparently the Wizard class does this via EnsureChildControls). Does't explain why the TABLE is around the Completed step and not the Create step.
Is there something I'm missing, or am I looking for functionality (i.e. no TABLEs around templated controls) that isn't here yet?
Thursday, September 14, 2006 6:27 PM
All replies
-
User-534056067 posted
Well stated. And much appreciated.
I've duplicated the problem here and I see exactly what you are talking about. I'll add it to the to-do list to fix in the next update.
Thursday, September 14, 2006 9:56 PM -
User-1385398420 posted
Thanks, Russ! I guess I'll go back to my control hack that removes TABLE (and related tags) via regular expressions. :)
Since my post yesterday, I tinkered some more. For the life of me I can't find any place where the TABLE is added to the control hierarchy. I looked at the Control.Controls collection at the Render() phase of the adapter, and there were no TABLE (or related) tags to be seen. Very weird.
Friday, September 15, 2006 9:23 AM -
User-534056067 posted
Please allow me to allow to try to help you to fix this in the adapter kit, instead.
The adapters that handle the membership controls follow a similar pattern in their implementation. Let's look at the LoginAdapter as an example, http://www.asp.net/CSSAdapters/srcviewer.aspx?inspect=%2fCSSAdapters%2fMembership%2fLogin.aspx. In particular, I want you to look at line 125 where the template container is being rendered. I'm considering changing that from:
container.RenderControl(writer);
To:
foreach (Control c in container.Controls)
{
c.RenderControl(writer);
}It would be helpful if you could try that fix out locally and let me know if it works well for you. Remember that the other membership control adapters are doing something similar in many cases so we'll need to make this fix in a few files, not just LoginAdapter.cs. And, of course, we'll ultimately want to do it equally in VB and C#. I noticed from your article on the reg expression solution that you gave a C# example so I figured you were a C#-sort-of-person so I've given the proposed code to you in C#, naturally.
Good luck, however you end up working around this for now. Best regards,
Friday, September 15, 2006 1:29 PM -
User-1385398420 posted
Your suggestion did the trick for the Login control.
I used a similar approach to the CreateUserWizard adapter. Since this adapter only added the table in the Completed step, I made the following change in the RenderContents() method (around line 181):
activeStep.RenderControl(writer);
changes to:
if (activeStep.StepType == WizardStepType.Complete)
foreach (Control c in activeStep.Controls[0].Controls[0].Controls[0].Controls[0].Controls)
{
c.RenderControl(writer);
}
else
activeStep.RenderControl(writer);For the PasswordRecovery control, there's three places to change -- each instance of the RenderControl() method in the RenderContents() method should be commented out and replaced by the foreach loop.
//passwordRecovery.UserNameTemplateContainer.RenderControl(writer);
foreach (Control c in passwordRecovery.UserNameTemplateContainer.Controls)
c.RenderControl(writer);...
//passwordRecovery.QuestionTemplateContainer.RenderControl(writer);
foreach (Control c in passwordRecovery.QuestionTemplateContainer.Controls)
c.RenderControl(writer);...
//passwordRecovery.SuccessTemplateContainer.RenderControl(writer);
foreach (Control c in passwordRecovery.SuccessTemplateContainer.Controls)
c.RenderControl(writer);
That's some weird behavior, but it works, and it doesn't seem to break any of the functionality.Friday, September 15, 2006 4:08 PM -
User-534056067 posted
Thanks for the additional detail. It will help others who run into what you ran into.
I'll make sure we fix it in the next rev of the kit.
It sounds like you are now able to use the adapters for your project. That's great. Best of luck and regards,
Friday, September 15, 2006 4:26 PM -
User-1385398420 posted
With this, I'll throw the adapters into one of my lesser projects to see how it works. If all goes well, they'll become a permanent part of my web projec template. :)
Thanks for the quick replies and follow-up!
Friday, September 15, 2006 4:44 PM -
User1409618048 posted
Thanks for the tips guys. I added a basic adapter for the WIzard control to the CSS Friendly adapters and was haveing the same problem when the StepType = Step.
The same technique has fixed it [Yes]
Tuesday, September 19, 2006 9:50 AM -
User-1385398420 posted
A little update on this.
It works great in Firefox. In IE, when you click the Log On or Register or Recover Password button, IE does nothing.
The only difference in the source available to each browser is in the <form> tag. Note the bold area below. Firefox has this:
<form name="aspnetForm" method="post" action="Login.aspx?AspxAutoDetectCookieSupport=1" onsubmit="javascript:return WebForm_OnSubmit();" id="aspnetForm">
IE has this:
<form name="aspnetForm" method="post" action="/(X(1))/Login.aspx?AspxAutoDetectCookieSupport=1" onsubmit="javascript:return WebForm_OnSubmit();" id="aspnetForm">
Nice feature. I'll see what else I can find out.
Wednesday, September 20, 2006 1:58 PM -
User-1385398420 posted
Well, a recompile and a re-upload to the web server, and it seems to be OK now. Not sure why it happened. Odd behavior to say the least. (!)Wednesday, September 20, 2006 2:54 PM -
User-1385398420 posted
... well, not really. The generated source is identical for both pages now, but still nothing working in IE. No reported script errors in IE, either.
So you understand what it does/doesn't do in IE... It will do client-side validation when the command buttons are clicked, but it will not post back when there are no client side errors. I confirmed the problem exists with the same code on multiple servers, and from different desktops (all running XP SP2 with IE6).
I tried putting an onClientClick="return true;" on the command button: skips validation (expected), no postback.
I tried turning off ViewState: no postback.
I tried turning off JavaScript: no postback.
Obviously, there's something weird that's not working in IE. Looks like it's back to my control hack... :(
Wednesday, September 20, 2006 3:20 PM -
User-1385398420 posted
Problem found. What was it? Nothing to do with the adapters, so ignore any further reading if you don't care to know what the difference in behavior between Firefox and IE was caused by.
The things that broke IE: A PayPal donation script on the page, which uses a <FORM> tag. IE apparently breaks with the nested form tags. Moving the server-side form so it doesn't overlap these fixed the problem.
/sigh
Wednesday, September 20, 2006 3:30 PM -
User-534056067 posted
Status update...
I have fixed the code in the Login and PasswordRecovery adapters per the discussion above. I've got test pages that show the problem and demonstrate that the fix works so I'm confident about that part of the game.
However, I've not touched the CreateUserWizard adapter because, frankly, I've not been able to repro the problem. And, because the suggested code is a bit odd. I'd like to explore the CreateUserWizard case further.
Here is what I've tried as a test case:
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server"></head>
<body>
<form id="form1" runat="server">
<asp:CreateUserWizard ID="CreateUserWizard1" runat="server" ActiveStepIndex="1">
<WizardSteps>
<asp:CompleteWizardStep runat="server">
<ContentTemplate>
Complete! Your account has been successfully created.
<asp:Button ID="ContinueButton" runat="server" CausesValidation="False" CommandName="Continue" Text="Continue" ValidationGroup="CreateUserWizard1" />
</ContentTemplate>
</asp:CompleteWizardStep>
</WizardSteps>
</asp:CreateUserWizard>
</form>
</body>
</html>When I run that page in IE using the unmodified CreateUserWizard adapter I don't see the table appear. Also, if I use the suggested code (with the deeply nested de-referencing of Control[0]) I actually end up crashing when I run this test page because at some point that nest of controls hits a null.
Can anyone provide a test case (page) that I can run locally (so please don't post pages that use all sorts of databases, etc. that I won't have, ha ha) to demonstrate the problem with templating CreateUserWizard and using the kit's adapter? If we can't come up with such a test case together I'm going to fix the problem in Login and PasswordRecovery for the next rev of the kit but will not attempt any modification to the template code in the adapter for CreateUserWizard.
Sound fair, folks?
Sunday, October 8, 2006 5:51 PM -
User1094951788 posted
Try templating both steps in the CreateUserWizard control. I have observed that the first templated step is fine (no single-cell table wrapper). Second (or subsequent) templated steps get the single-cell table added in RenderContents(). A fix similar to that described up-thread works, though I included a test for control type Table as I drill down the control hierarchy past the inserted single-cell table.
Wednesday, November 8, 2006 12:12 PM -
User-651121556 posted
Hi Russ,
I'm still getting the problem of the Complete step containing tables (and this is using the most up to date source). For your simple sample of the CreateUserWizard I get the following output:
<div class="AspNet-CreateUserWizard" id="CreateUserWizard1"><table cellspacing="0" cellpadding="0" border="0" style="height:100%;width:100%;border-collapse:collapse;"> <tr> <td style="height:100%;width:100%;"> Complete! Your account has been successfully created. <input type="submit" name="CreateUserWizard1$CompleteStepContainer$ContinueButton" value="Continue" id="CreateUserWizard1_CompleteStepContainer_ContinueButton" /> </td> </tr> </table> </div>
However, this only happens when the "Complete" step occurs after first completing the initial create user step - so in the example you give you would need to remove the "ActiveStepIndex="1" " from the CreateUserWizard line - going straight to the CompleteWizardStep doesn't produce this behaviour & the code appears as it should, with no tables present.
Steve
Friday, October 12, 2007 8:57 AM