Nested usercontrol Linkbutton Onclick event not firing after postback - asp.net/C# - c#

I'm using nested controls for a series of forms and having problem with the onclick event.
I'm just using textboxes and a manual code-behind insert rather than Gridview/Details view structure.
The scenario is that I have a car insurance form where users can add additional named drivers. At the top is a section where you add your own details (which is a seperate user control) and there is a section underneath where you can add up to 4 named drivers (which is also a seperate usercontrol). What I wanted to do was use my 'Add Driver' linkbutton onclick event to add the details into the database, then clear the form fields so the user could then add another driver. This all works fine until you go to click the Add Driver button again and discover it doesn't work.
This is the Parent control that houses the Add Driver user control:
<h2>Add Permanent Driver</h2>
<asp:ValidationSummary ID="uxValidationSummary" runat="server" ShowSummary="true" ValidationGroup="ChangeDetails" />
<div class="clear"></div>
<h3>
Please enter your details below as they are on your insurance documents</h3>
<uc1:UserDetails ID="uxUserDetails" runat="server" />
<uc2:AddDriver ID="uxAddDriver" EntryType="Permanent" runat="server" />
This is a cutdown version of the onclick event for the Add Driver submit button on the AddDriver control
protected void uxSubmit_Click(object sender, EventArgs e)
{
Page.Validate("AddDriver");
if (Page.IsValid)
{
DriverDAL.DriverTableAdapters.DriverTableAdapter taDriver = new DriverDAL.DriverTableAdapters.DriverTableAdapter();
taDriver.DriverInsert(StartDate, EndDate, Title,
FirstName, Surname, DateOfBirth, Gender);
uxDriverList.DataBind();
uxDate.Text = string.Empty;
uxEndDate.Text = string.Empty;
uxTitle.SelectedIndex = 0;
uxFirstName.Text = string.Empty;
uxSurname.Text = string.Empty;
uxDateOfBirth.Text = string.Empty;
uxGender.SelectedIndex = 0;
}
}
Is there anything I can do to reactivate this linkbutton after the first OnClick (or remove it and recreate it) so I can add multiple drivers? I tried to databind the button after the submit, but as expected, that had no effect, but that is the kind of thing I'm looking for. I can't redirect the page, because as mentioned earlier in the post, it is using nested controls and I arrive at this form by using the SelectedIndexChanged event of a DropDownList.
Any ideas appreciated - thanks. Let me know if more info is required.

It sounds like you might have some validation that's preventing the button from doing a postback. Try setting CausesValidation="false" and see if that makes a difference.
If validation is causing the problem, I would either separate the validation into groups and assign the button to a specific group, or toggle the enabled state of the validators based on some condition, for example:
RequiredFieldValidator1.Enabled = Panel1.Visible;

Related

Gridview Custom controls and javascript functions c#

I have a custom control which is basically a Gridview and its first column is a TemplateField with a checkbox in the header and a checkbox for each of the rows. Clicking on the header checkbox should call some javascript to toggle each of the checkboxes in every row on display... it's a common requirement as we know.
My problem is (I'll go into more detail later) that when I have 2 of these controls on the same page, and I click the checkbox that selects all the chkboxes, the page calls the wrong bit of javascript (which only appears once on the rendered html page) and checks all the checkboxes on the wrong grid !
Here's my code:
<asp:TemplateField>
<HeaderTemplate>
<input type="checkbox" ID="chkSelectAll" onclick="SelectAllCheckboxes(this)"/>
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox runat="server" ID="chkSelected"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
Javascript:
<script>
function SelectAllCheckboxes(chk) {
$('#<%=gridPublishers.ClientID%>').find("input:checkbox").each(function ()
{
if (this != chk) { this.checked = chk.checked; }
});
}
</script>
So, the parent page has 2 of these controls on it. The first grid shows All the publishers and the other shows the publishers that have been selected from the first...
<h2>Selected Publishers</h2>
<cac:GridPublishers id="GridSelectedPublishers" runat="server" CssClass="GridSelectedPublishers" BindSource="DynamicFromSession" ShowMultiSelectCol="true" ShowFilterControls="false" NoRecordsMessage="No Publishers have been selected yet." />
<br /><br />
<h2>All Publishers</h2>
<cac:GridPublishers id="GridPublishers" runat="server" ShowMultiSelectCol="true" CssClass="GridPublishers" />
As I said earlier, the javascript only appears once on the rendered html page (and I understand why) but how can I get each instance of the custom control calling it's own javascript (or an alternative method) so that it only toggles its own checkboxes ??
...
I've also tried adding 2 javascript events and on grid bind trying to find the master checkbox and assign it the correct JS function, but I've searched each cell of the header row, and col 0 (where the control should be) holds 0 controls.
...
I've also tried adding a hidden button that on page load, I can assign it the correct javascript function (that will affect the correct gridview) and then the master checkbox fires the hidden button onClientClick event, but as the page reloads, it gets confused and fires the click event twice and from both grids apparently !
Please help !!
So I guess you realise that this line of code is causing the root problem of selecting the checkboxes in the wrong datagrid:
#<%=gridPublishers.ClientID%>').find
It's always going to pickup gridPublishers, and not GridSelectedPublishers.
So this is the area to fix. What you need to do is make this function a bit more abstract:
<input type="checkbox" ID="chkSelectAll" onclick="SelectAllCheckboxes(this)"/>
The onclick event passes 'this', but that's only a reference to the checkbox which isn't much help.
I'd suggest you try and make it something like this:
<input type="checkbox" ID="chkSelectAll" onclick="SelectAllCheckboxes(this,'GridSelectedPublishers')"/>
And then use the 2nd argument in the javascript function to grab the right datagrid.
Your problem now, is how to get that 2nd argument in there....you may be able to think of your own solution for this, but I would be tempted to make that checkbox an ASP checkbox, and find it during datagrid render and assign it the onClick with Attribute.Add
Making sense?
I've already marked "ben_the_builder's" answer as correct because it got me along the right line.
When I bind my grids I call this function:
private void Register_CheckAllControl_JScript()
{
// THIS IS A WORKAROUND FOR WHEN TWO OF THE SAME CUSTOM CONTROL LIVE ON THE SAME PAGE, EACH CONTROL'S JAVASCRIPT MUST SPECIFY THE ID OF THE CONTROL TO AFFECT
if (gridPublishers.HeaderRow != null)
{
CheckBox chkAll = gridPublishers.HeaderRow.FindControl("chkSelectAll") as CheckBox;
if (chkAll != null)
{
if (this.BindSource == Enumerators.BindSource.DynamicFromSession)
{
chkAll.Attributes.Add("onclick", "SelectAllCheckboxes(this,'GridSelectedPublishers');");
}
else
{
chkAll.Attributes.Add("onclick", "SelectAllCheckboxes(this,'GridPublishers');");
}
}
}
}
To access the "master" checkbox from code behind - it had to be an ASP control. an input control just wasn't recognised when iterating through the header cell collection.
My Javascript needed a little tweaking for the IDs to be correct. The control name I'm passing had to be name it was given on the parent page which belongs in the middle of the three tier final html output name (see the example, it'll make sense...)
My Javascript looks like this now:
<script>
function SelectAllCheckboxes(chk, ctrlName) {
//if ctrlName = "
$("#MainContent_" + ctrlName + "_gridPublishers").find("input:checkbox").each(function () {
if (this != chk) { this.checked = chk.checked; }
});
}
</script>
You want to use parameters. Instead of hard coding #<%=gridPublishers.ClientID%> into your javascript function, use the this parameter you pass to the function to determine the name of the grid view that contains the checkbox, then check everything inside that grid view.

Knowing when a ModalPopupExtender user control has closed

I have created a usercontrol (.ascx) for use in my asp.net website (not mvc). The control has a few text boxes and allows the user to enter a new customer. It has two buttons, one to add the customer and one to cancel the control. I call display the control by using a “ModalPopupExtender “ with the code shown below:
This is in an updatePanel:
<asp:ModalPopupExtender ID="ModalPopupExtender2" runat="server" TargetControlID="hiddenButton"
PopupControlID="Panel3" BackgroundCssClass="modalBackground" DropShadow="true"/>
Here is the Panel3 markup:
<asp:Panel ID="Panel3" runat="server" Style="display: none" CssClass="modalPopup" Width="100%" Height="100%">
<uc3:CustomerForm runat="server" ID="CustomerForm1" ParentUpdatePanel="UpdatePanel1" ErrorDisplayControl="lblErrorMessage"/>
</asp:Panel>
When I click a button on the main page the code behind calls:
ModalPopupExtender2.Show();
This shows my control and when I add a new customer the database is updated so this side of things works fine. What I need to do is enhance the code so that when a customer is added and the usercontrol closes, the customer dropdownlist on the main page is loaded with the updated customer list and the customer that the user enter is selected. The dropdownlist is databound so my question is, how do I know when my usercontrol has been closed so I can work out if a new customer has been added and then re databind my list and select the correct item? Working with asp.net and javascript is not an area I have a lot of skill in so please forgive if I have used the wrong terminology.
I have found a solution to my problem. In my usercontrol, after a new customer has been added I call:
RaiseBubbleEvent(this, new CustomerArgs {OrganisationId = organisationId});
In the calling page’s code behind I listen for the bubble event:
protected override bool OnBubbleEvent(object sender, EventArgs e)
{
if (sender is CustomerForm && e is CustomerArgs)
{
_organisationID = (e as CustomerArgs).OrganisationId.ToString();
DoOrganisationListDataBind();
return true;
}
return false;
}
This works fine for what I’m after. Not sure if this is a good way to do it but it works.

asp.net Button OnClick event not firing

I have problem in asp.net button control.
I define a button in form, onclick event of button is not firing when I click on the button.
<asp:Button ID="btn_QuaSave" runat="server" Text="SAVE" OnClick="btn_QuaSave_Click" />
protected void btn_QuaSave_Click(object sender, EventArgs e)
{
}
Because your button is in control it could be that there is a validation from another control that don't allow the button to submit.
The result in my case was to add CausesValidation property to the button:
<asp:Button ID="btn_QuaSave" runat="server" Text="SAVE" OnClick="btn_QuaSave_Click" CausesValidation="False"/>
Have you copied this method from other page/application ? if yes then it will not work, So you need to delete the event and event name assigned to the button then go to design and go to button even properties go to onClick event double click next to it, it will generate event and it automatically assigns event name to the button.
this should work
I had the same problem, my aspnet button's click was not firing. It turns out that some where on other part of the page has an input with html "required" attribute on.
This might be sound strange, but once I remove the required attribute, the button just works normally.
If you are using updatepanel on onclick event, this may happen.
Use 'EnableEventValidation="false"' in your page markup like this :
<%# Page Language="C#" MasterPageFile="~/ars_home.master" AutoEventWireup="true" CodeFile="Transaction_Window.aspx.cs" Inherits="Transaction_Window" EnableEventValidation="false" %>
Hope this helps
I had a similar issue and none of the answers worked for me. Maybe someone finds my solution helpful. In case you do not mind submitting on button click, only attaching to click event setting UseSubmitBehavior="false" may be worth trying.
In my case I put required="required" inside CKEditor control.
Removing this attribute fixed the issue.
Before
<CKEditor:CKEditorControl ID="txtDescription" BasePath="/ckeditor/" runat="server" required="required"></CKEditor:CKEditorControl>
After
<CKEditor:CKEditorControl ID="txtDescription" BasePath="/ckeditor/" runat="server"></CKEditor:CKEditorControl>
i had the same problem did all changed the button and all above mentioned methods then I did a simple thing I was using two forms on a single page and form with in the form so I removed one and it worked :)
Try to Clean your solution and then try once again.
It will definitely work. Because every thing in code seems to be ok.
Go through this link for cleaning solution>
http://social.msdn.microsoft.com/Forums/en-US/vsdebug/thread/e53aab69-75b9-434a-bde3-74ca0865c165/
Try to go into Design mode in Visual Studio, locate the button and double click the button that should setup the event. Otherwise once the button is selected in Design more, go to the properties and try setting it from there.
Add validation groups for your validator elements. This allows you distinguish between different groups which to include in validation. Add validation group also to your submit button
in my case:
make sure not exist any form element in your page other than top main form,
this cause events not fired
If the asp button is inside tag then also the Click event will not raise.
Hope it's useful to some one.
In the case of nesting the LinkButton within a Repeater you must using something similar to the following:
<asp:LinkButton ID="LinkButton1" runat="server" CommandName="MyUpdate">LinkButton</asp:LinkButton>
protected void Repeater1_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName.Equals("MyUpdate"))
{
// some code
}
}
If it's throwing no error but still not firing the click event when you click the submit button, try to add action="YourPage.aspx" to your form.
Even i had two forms one for desktop view and other for mobile view , Removed one formed worked for me . I dint knew asp.page should have only one form.
Try this onserverclick
<button id ="DemoButton" runat="server" onserverclick="button_Click">Login</button>

FindControl can't locate my dynamically added control

I have a repeater that lists customer items, one of which is a button for more information. When the user clicks that button, a user control appears immediately below it. I'd like for the user control to then close when the button is clicked again. I initially toggled visibility server-side, but I now can't use this because the user control needs to be loaded on the button click due to parameters that need to bepassed through. I also can't used show and hide by jquery because that would involve downloading all the data first for the whole page which could make the page too cumbersome.
So currently in each repeater I have a linkbutton with command arguments and an OnCommand event which fires this event:
protected void uxPolicyDocsButton_Command(object sender, CommandEventArgs e)
{
//Find Policy Summary control within repeater item in order to toggle visibility
LinkButton button = sender as LinkButton;
if (button != null)
{
RepeaterItem ri = button.Parent as RepeaterItem;
if (ri != null)
{
PlaceHolder policySummaryPlaceHolder = (PlaceHolder)ri.FindControl("uxPolicySummaryPlaceHolder");
Control policyDocuments = (Control)PolicySummaryPlaceHolder.FindControl("uxPolicyDocumentsControl");
foreach (Control c in policySummaryPlaceHolder.Controls)
{
//FindControl action goes in here. Have stepped through though and it doesn't appear
}
if (policyDocuments != null)
{
policySummaryPlaceHolder.Controls.Remove(policyDocuments);
}
else
{
policyDocuments uxPolicyDocumentsControl = (PolicyDocuments)LoadControl("~/Controls/Home/PolicyDocuments.ascx");
uxPolicyDocumentsControl.PolicyNumber = button.CommandArgument;
policySummaryPlaceHolder.Controls.Add(uxPolicyDocumentsControl);
}
}
}
}
My plan for the toggle was that if the PolicyDocuments control was null, then load the control, and if not then remove the control, but it always came back null. It did load the control correctly though.
Here is the section of the repeater:
<ItemTemplate>
<tr>
<td>
<%#Eval("StartDate","{0:d}")%>
</td>
<td class="center-cell-ctrl">
Postcode:<br />
<%#Eval("Postcode")%>
</td>
<td id='<%#Eval("PolicyNumber")%>' class="button-cell">
<asp:LinkButton ID="uxPolicyDocsButton" CommandName="PolicyNumber" CommandArgument='<%#Eval("PolicyNumber")%>' OnCommand="uxPolicyDocsButton_Command" runat="server" Visible="false">Policy<br />Documents</asp:LinkButton>
</td>
</tr>
<asp:PlaceHolder ID="uxPolicySummaryPlaceHolder" runat="server"></asp:PlaceHolder>
<asp:PlaceHolder ID="uxPolicyDocumentsPlaceHolder" runat="server"></asp:PlaceHolder>
</ItemTemplate>
I've had a look around for people who have had similar problems, and a common answer is that you need to load controls in the Page_Init event. Does that mean that this way won't work? Any ideas for an alternative if this is the case?
Many thanks
Every time your page is loaded (either initially, or via PostBack) the Control Tree needs to be re-created.
The controls declared in the ASPX part of your page are added by the framework (kind of), but any controls that you add "dynamically" need to be placed back in the control tree too. If they aren't then, as you've disovered, they simply can't be found again.
Complex controls, like the datagridview, rebuild their control tree by storing (a huge amount of) data in the ViewState.
It might be simpler, rather than have your page add/remove items from a PlaceHolder, to create a user control that you can and hide, and load it's data the first time its shown. This also helps your controls and pages adhere to the Single Repsonsibility Principal
I dont' understand, why you can't add the PolicyDocuments with visible = false and no datasource instead of Placeholder, like that:
<uc:PolicyDocuments ID="uxPolicyDocuments" runat="server" Visible="false"></asp:PolicyDocuments>
and during the command use such code:
if (ri != null)
{
var policyDocuments = ri.Controls.OfType<PolicyDocuments>().FirstOrDefault();
if (policyDocuments == null)
return;
if (policyDocuments.Visible)
{
policyDocuments.Visible = false;
}
else
{
policyDocuments.PolicyNumber = button.CommandArgument;
policyDocuments.Visible = true;
}
}
In this case you don't need to use some hacks in Init event of the page.
Anyway, you always can use the .Controls.OfType<PolicyDocuments>() extension method to get all the user controls you need.

Resolving viewstate/namespace conflicts

I have a listbox control. When the user clicks it, it tells a custom control to use a certain ID to use.
The custom control draws the same thing everytime(dynamically), just loads different content depending on this ID(it's loaded from a database into a dynamic form like control).
Ok, Now I'm having trouble with viewstate spillage. When you click the listbox to load say ID #1, it'll all look good. Then, you click on ID #2 and all the textbox controls created inside the custom control has the same thing that was put in ID #1. So when the listbox index changes I need to clear the view state, but I can't get this to work.
All of the controls are created at Page_Load also.
I tried ViewState.Clear() at Page_Load but that didn't do anything.
I had the custom control derive from INamingInterface, but I guess the IDs still match for viewstate.
I've tried changing the custom controls ID to something unique(like "CONROL_"+id.ToString()) I've also tried doing the same thing with the panel containing the custom control.
I can not seem to get rid of this view state!
EDIT
Ok here is code that demonstrates the problem
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (ddl.SelectedValue == "1")
{
Create("ID #1");
}
else if (ddl.SelectedValue == "2")
{
Create("ID #2");
}
}
void Create(string text)
{
TextBox t = new TextBox();
t.Text = text;
pnl.Controls.Add(t);
}
}
the markup:
<div>
<asp:Panel ID="pnl" runat="server">
<asp:DropDownList ID="ddl" runat="server" AutoPostBack="True">
<asp:ListItem Text="id 1" Value="1">
</asp:ListItem>
<asp:ListItem Text="id 2" Value="2"></asp:ListItem>
</asp:DropDownList>
</asp:Panel>
</div>
If you run this code you'll notice that if you change what is in the textbox and then you change the dropdown list, then what you typed earlier will be kept in there instead of it being overwritten..
My basic goal with this is to get it so that when you change to ID #2, it puts "ID #2" in the textbox no matter what(preferably without disabling viewstate altogether)
If I set the ID of the Text control then it doesn't retain the old value. Are you giving all controls a unique id?
void Create(string text)
{
TextBox t = new TextBox();
t.ID = text;
t.Text = text;
pnl.Controls.Add(t);
}
You can't do it that way.
For viewstate to work properly all controls must be created before it is loaded and with the same id's. So you must store the control definitions in session and recreate then with the same ids to ASP.NET load their properties from the view state. Page_load is too late, do it at PreLoad.
But it is easier to have all controls created at design time with visible set to false, and alternate their visibility so viewstate will work properly.
Actually this is no longer relevant. We fixed it by just disabling viewstate for our dynamically created controls. This would not work in all instances, but in our case there are two buttons the user can push(that are to do with the dynamic controls) or a list box to switch forms. The two buttons both save the state of the controls to database, so viewstate is not actually needed.(I always get confused when thinking about viewstate and how it interacts with controls.. )
So basic advice: If your having trouble controlling the viewstate, be sure you actually need it.

Categories