I have an AJAX ToolKit TabContainer control with several TabPanels. I want to validate the contents of the current active TabPanel to prevent user from working on other ones in case data was invalid.
If you need to do a TabPanelChangingEvent SERVER side, You will need to do this by Altering the ajaxcontroltoolkit Source code.
Good news : you could easily get it
Here a new solution that does almost what your need :
The OnClientActiveTabChanged event is raised
The tabcontainer New Tab index is saved in a Hiddenfield
The tabindex is reset to it's old value (so it wont change right now)
The form trigger a asyncpostback using a hidden button.
Within the hidden button's Click event, the OldTabIndex and NewTabIndex are retrieved.
At the end of the Click event, the tabcontainer's tabindex is switched to the new value.
So, the hidden button's Click event is executed before the TabContainer tab is changed.
aspx:
<asp:Button runat="server" ID="hiddenTargetControlForTabContainer" style="display:none" />
<asp:UpdatePanel ID="TabContainerUpdatePanel" runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="hiddenTargetControlForTabContainer" />
</Triggers>
<ContentTemplate>
<asp:HiddenField ID="TabContainerActiveTab" runat="server" Value="0" />
<AjaxControlToolkit:TabContainer ID="TabContainer1" runat="server" ActiveTabIndex="0"
OnClientActiveTabChanged="OrderTabContainerClientActiveTabChanged" >
<AjaxControlToolkit:TabPanel runat="server" ID="TabPanel1"
HeaderText="TabPanel1"
>
<ContentTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</ContentTemplate>
</AjaxControlToolkit:TabPanel>
<AjaxControlToolkit:TabPanel runat="server" ID="TabPanel2"
HeaderText="TabPanel2" >
<ContentTemplate>
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
</ContentTemplate>
</AjaxControlToolkit:TabPanel>
</AjaxControlToolkit:TabContainer>
</ContentTemplate>
</asp:UpdatePanel>
<script type="text/javascript">
var TabContainerActiveTabControlID = '<%= TabContainerActiveTab.ClientID %>';
var hiddenTargetControlForTabContainerControlID = '<%= hiddenTargetControlForTabContainer.uniqueID %>';
function OrderTabContainerClientActiveTabChanged(sender, args) {
var TabContainerActiveTabControl = $get(TabContainerActiveTabControlID);
var OldtabIndex = parseInt(TabContainerActiveTabControl.value);
var NewtabIndex = sender.get_activeTabIndex();
if (!(OldtabIndex == NewtabIndex)) {
sender.set_activeTabIndex(OldtabIndex);
TabContainerActiveTabControl.value = NewtabIndex;
__doPostBack(hiddenTargetControlForTabContainerControlID, '');
}
}
Code behind:
Protected Sub hiddenTargetControlForTabContainer_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles hiddenTargetControlForTabContainer.Click
Dim oldActiveTabIndex = TabContainer1.ActiveTabIndex
Dim newActiveTabIndex As Integer = Convert.ToInt32(TabContainerActiveTab.Value)
'your stuff here
TabContainer1.ActiveTabIndex = newActiveTabIndex
End Sub
Problem: Ajax TabContainer the ActiveTabChanged event shows incorrect ActiveTabIndex.
For eg. TabContainer contain 3 tabs, if second tab is hide(visible = false on server side) then on click of third tab, we get ActiveTabChanged = 1 not 2 (expected active index is 2 on server side code).
Solution:
Register the clientside event of the tab container:
OnClientActiveTabChanged="Tab_SelectionChanged"
Then define the javascript function to handle the above event which will internally store the tab index in a hidden variable.
function Tab_SelectionChanged(sender,e)
{
document.getElementById('<%=hdntabIndex.ClientID %>').value = sender.get_activeTabIndex();
}
Use the hidden variable(hdntabIndex) in the code behind where ever you need the active tab index.
You should do it using JavaScript.
Here an example I made, the trick is to use ValidationGroup and save the Old tab Index at the end of the function called by the OnClientActiveTabChanged
<AjaxControlToolkit:TabContainer ID="TabContainer1" runat="server" Height="138px"
Width="402px" ActiveTabIndex="0"
OnClientActiveTabChanged="ValidateTab" >
<AjaxControlToolkit:TabPanel runat="server" ID="TabPanel1"
HeaderText="TabPanel1"
>
<ContentTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
ErrorMessage="RequiredFieldValidator"
ControlToValidate="TextBox1"
ValidationGroup="TabPanel1"
/>
</ContentTemplate>
</AjaxControlToolkit:TabPanel>
<AjaxControlToolkit:TabPanel runat="server" ID="TabPanel2"
HeaderText="TabPanel2" >
<ContentTemplate>
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server"
ErrorMessage="RequiredFieldValidator"
ControlToValidate="TextBox2"
ValidationGroup="TabPanel2"
/>
</ContentTemplate>
</AjaxControlToolkit:TabPanel>
</AjaxControlToolkit:TabContainer>
<script type="text/javascript">
var OldtabIndex = 0;
function ValidateTab(sender, args) {
if (OldtabIndex == 0) {
if (!Page_ClientValidate('TabPanel1')) {
sender.set_activeTabIndex(OldtabIndex);
}
}
else if (OldtabIndex == 1) {
if (!Page_ClientValidate('TabPanel2')) {
sender.set_activeTabIndex(OldtabIndex);
}
}
OldtabIndex = sender.get_activeTabIndex();
}
</Script>
I know I'm probably late to answering this question, but hopefully, I can offer some assistance to someone who's pot-committed like I was to the TabPanels.
Add the OnClientActiveTabChanged="showMap" to the ajaxToolkit:TabContainer. My function is obviously called showMap (had to hide and show the Google Street Map, because TabContainer screws it all up. So I had to move the Google Street Map outside of the container and then 'fake' put it back in the container).
<ajaxToolkit:TabContainer runat="server" ID="tabs" OnClientActiveTabChanged="showMap">
<ajaxToolkit:TabPanel runat="server" ID="pnlZones" HeaderText="Delivery Zones">
<ContentTemplate>
...
</ContentTemplate>
</ajaxToolkit:TabPanel>
</ajaxToolkit:TabContainer>
Then create the javascript:
<script type="text/javascript">
function showMap() {
var tabID = $('.ajax__tab_active').attr('id');
if (tabID.indexOf('pnlZone') > 0) {
$('#mapHider').css('height', '600px');
}
else {
$('#mapHider').css('height', '0');
}
}
</script>
We can then find the active tab by the class .ajax__tab active, which is what TabContainer will set the active class to. Snag the ID (.attr('id')) with jQuery... And voila, we now which tab we're currently on.
For this I change the height of the class from 0 to 600px. With the overflow set to hidden, it makes it seem like the map is on the page and only in that container, but it isn't.
Hopefully, this helps!! Good luck.
Related
I have a listview that populates with data. This listview is inside a user control which sits inside a page called Preferences.aspx. Today I am handling click event on each row meaning that involves posting back to server.
Now, I have to put another user control on Preferences.aspx because there are group of more settings which need to be presented separately to users. I have added the new user control inside a separate tab on the page. This new tab has to be the first one to show when user lands on Preferences.aspx.
Now the problem is that when user goes to second tab (user control with listview) and click on a row, a postback occurs. This puts the user on the first tab (newly added user control).
So I wonder how can I get click event on a row without having to postback?
Any ideas or suggestions are welcome.I am working in Asp.Net with C#.
The code is:
Markup inside the user control:
<asp:TableRow runat="server" id="trVisitor" CssClass='<%# GetRowClass() %>' >
<asp:TableCell ID="tdPicture" runat="server" Width="10" onclick='<%# GetClickPostBack(Container.ItemIndex) %>'>
<div style="margin-top:1px;">
<asp:Image ImageUrl=' <%# Page.ResolveUrl("~/" + Eval("Visitor.StatusImageUrl")) %>' visible='<%# historyFlag ? false : true %>' runat="server"/>
</div>
</asp:TableCell>
... and so on
Markup inside Preferences.aspx:
<ABC:ListControl runat="server" ID="visitorListControl" CanSelect="true" IsMine="true" Recurring="false" OnVisitorSelected="ListControl_VisitorSelected" />
And code behind is:
protected string GetClickPostBack(int itemIndex)
{
if (CanSelect)
//return 0.ToString();
return "javascript: " + Page.ClientScript.GetPostBackEventReference(this, VisitorRowPrefix + itemIndex) + "; return false;";
else
return string.Empty;
}
public void RaisePostBackEvent(string eventArgument)
{
if (eventArgument.StartsWith(VisitorRowPrefix))
{
HandleRowClick(Convert.ToInt32(eventArgument.Substring(VisitorRowPrefix.Length)));
}
}
private void HandleRowClick(int index)
{
int CmgVisitorId = Constants.NotConfigured;
// bool IsHistoricVisitor = false;
// Visitor HistoricVisitor = new Visitor();
// Mark only the clicked row
... and so on.
Hook up to the grid button's click event using JavaScript/jQuery, and prevent theirs default behaviour (post-back) by 2 possible means:
return false;
e.preventDefault (jQuery only)
Example (using jQuery):
$('.button').click(function(event){
event.preventDefault();
//Write your client-side logic here
});
Description: If this method is called, the default action of the event
will not be triggered.
If I am understanding the issue properly, try an update panel.
Check out the documentation here.
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:TableRow runat="server" id="trVisitor" CssClass='<%# GetRowClass() %>' >
<asp:TableCell ID="tdPicture" runat="server" Width="10" onclick='<%# GetClickPostBack(Container.ItemIndex) %>'>
<div style="margin-top:1px;">
<asp:Image ImageUrl=' <%# Page.ResolveUrl("~/" + Eval("Visitor.StatusImageUrl")) %>' visible='<%# historyFlag ? false : true %>' runat="server"/>
</div>
</asp:TableCell>
</ContentTemplate>
</asp:UpdatePanel>
I have a modal popup extender and a panel inside of an update panel. I do have a Close button which I bind with the CancelControlId. I however, would like to be able to click outside of my modal/panel to close the panel. (instead of using the close button).
I tried a couple things and a plugin clickoutside. Nothing seems to help. Any help or advice is much appreciated. Thanks.
<asp:Content ID="Content3" ContentPlaceHolderID="rightNavigation" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<div id="mls_title" class="MLS_Title">
<asp:Label ID="lblTitle1" Text="Tasks" runat="server" class="MLS_titleLbl" /><br />
</div>
<asp:UpdatePanel ID="pnlMap" runat="server">
<ContentTemplate>
<div>
<asp:Button ID="btnMap" runat="server" Text="MAP" CausesValidation="false" CssClass="btnMap" />
<ajax:ModalPopupExtender
ID="ModalPopupExtender1"
runat="server"
TargetControlID="btnMap"
PopupControlID="panel1"
PopupDragHandleControlID="PopupHeader"
Drag="true"
BackgroundCssClass="ModalPopupBG">
</ajax:ModalPopupExtender>
<asp:Panel ID="panel1" runat="server">
<div class="popup_large">
<asp:Label ID="Label7" Text="Floor Plan" runat="server" stle="float:left"></asp:Label>
<asp:ImageButton ID="ImageButton1" runat="server" ToolTip="No" ImageUrl="~/Images/no.png" Style="float: right; margin-right: 20px" />
<br />
<asp:ImageButton ID="img" runat="server" Height="30em" Width="45em" />
</div>
</asp:Panel>
</div>
</ContentTemplate>
</asp:UpdatePanel>
Here is a link to an example that adds to the background onclick to close the modal:
http://forums.asp.net/t/1528820.aspx
Copied the key bits here for reference:
function pageLoad() {
var mpe = $find("MPE");
mpe.add_shown(onShown);
}
function onShown() {
var background = $find("MPE")._backgroundElement;
background.onclick = function() { $find("MPE").hide(); }
}
<AjaxToolKit:ModalPopupExtender ID="mdlPopup" BehaviorID="MPE" runat="server"
TargetControlID="btnShowPopup" PopupControlID="pnlPopup"
CancelControlID="btnClose" BackgroundCssClass="modalBackground" />
C#
<AjaxToolKit:ModalPopupExtender .... BackgroundCssClass="jsMpeBackground" />
JavaScript (using jQuery)
jQuery('.jsMpeBackground').click(function () {
var id = jQuery(this).attr('id').replace('_backgroundElement', '');
$find(id).hide();
});
I had to do it this way so that I was able to click the actual popup without it closing, as I have functional user controls such as tab sections and textboxes on the popup.
<script type="text/javascript">
//Hide's Doc Center when clicking outside
function pageLoad(sender, args) {
if (!args.get_isPartialLoad()) {
$addHandler($find("MPE")._backgroundElement, "click", closePopup);
}
}
function closePopup(e) {
$find("MPE").hide();
}
//End
</script>
Now just make sure your BehaviorID in your actual ModelPopupExtender matches up with the tag above. Like so:
<ajaxToolkit:ModalPopupExtender ID="Popup" runat="server" PopupControlID="Container" BehaviorID="MPE" TargetControlID="fakeTargetControl" BackgroundCssClass="modalBackground" CancelControlID="btnCancel" />
Basically I think this just handles the 'click' event of the _backgroundElement attr of the modal popup, and on that event runs the closePopup() function.
write a dynamically created script that is added, in my example, when the modal popup extender is loaded. Note: In order to bind this event handler to the ModalPopupExtender.OnLoad event, you need to add a reference (in client-side code, you can add 'OnLoad="mpeExample_Load"' to your ModalPopupExtender tag).
protected void mpeExample_Load(object sender, EventArgs e) {
ScriptManager.RegisterClientScriptBlock(this, this.GetType(),
"hideModalPopupViaClient", String.Format(#"function hideModalPopupViaClient() {
{
var modalPopupBehavior = $find('{0}');
if (modalPopupBehavior) modalPopupBehavior.hide();}}",
mpeExample.ClientID), true);
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "pageLoad", String.Format(#"function pageLoad() {
{
var backgroundElement = $get('{0}_backgroundElement');
if (backgroundElement) $addHandler(backgroundElement, 'click', hideModalPopupViaClient);
}}",
mpeExample.ClientID), true);}
I am trying to create a simple form that uses radio buttons. I set the radio button to AutoPostBack = True, this way if the radio button is true/false, a subpanel is Shown or Hidden. The radio buttons are required fields. I also have a hidden textbox that the value of the selected radio button is inserted and this textbox is what I validate against (empty or not).
Problem 1:
This works until you go to submit and the validation fails. The validation messages show, then when you click on one of the radio buttons with AutoPostBack = True, all the validation disappear. I can resolve this by adding Page.Validate() to the method that runs when the radio button is clicked. But, I do not want the Page.Validate() to run unless the page was already showing validation errors (so it will not re-validate unless the form was already submitted and failed the validation).
As it stands, before the form is submitted and fails validation: when you click on any radio button question, all the other questions requiring validation show the validation error. I am only looking to overcome the AutoPostBack which is clearing all the validation messages that are shown when you had click submit.
Problem 2:
I would like to be able to change the color of the question if it does not pass validation. I added the javascript to override the default .net settings. I got this to work, but only when you click the submit button and not after a RadioButton AutoPostBack.
Currently, When you click submit all the required questions turn red and also display the required validation message. But if you click a radio button to start fixing the validation errors, on the AutoPostBack, the all the questions that were now red in color changes back to the orignal black and the required validation message is still shown. How can I call the Javascript to run again along with the Page.Validation() in the code behind method?
Any help would be greatly appricated! Thanks
Below is an example of the code so far.
ASPX Code:
<asp:Table ID="Table1" runat="server" CellSpacing="0" CellPadding="0">
<asp:TableRow>
<asp:TableCell CssClass="question">
<label>4. Have you had an abnormal result from a prenatal test (e.g. amniocentesis, blood test, ultrasound)?</label>
</asp:TableCell>
<asp:TableCell CssClass="answer">
<ul class="selectGroup">
<li>
<asp:RadioButton ID="Q4_true" runat="server" Checked='<%# Bind("Q4_yes") %>' Text="Yes"
GroupName="4" OnCheckedChanged='RB_QuestionSubPane_YN' AutoPostBack="true" /></li>
<li>
<asp:RadioButton ID="Q4_false" runat="server" Checked='<%# Bind("Q4_no") %>' Text="No"
GroupName="4" OnCheckedChanged='RB_QuestionSubPane_YN' AutoPostBack="true" />
</li>
<asp:TextBox ID="Q4_validationBox" runat="server" CssClass="hiddenField" Enabled="false"
Text=''></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" EnableViewState="true" ControlToValidate="Q4_validationBox"
Display="Dynamic" runat="server" ErrorMessage="RequiredFieldValidator"></asp:RequiredFieldValidator>
</ul>
</asp:TableCell>
</asp:TableRow>
</asp:Table>
Code Behind
protected void RB_QuestionSubPane_YN(object sender, EventArgs e)
{
RadioButton radio_Selected = (RadioButton)sender;
string radio_QuestionID = Convert.ToString(radio_Selected.ID);
(((TextBox)FormView1.FindControl(strQuestionID + "_validationBox")).Text) = radio_Selected.ID.ToString();
Page.Validate();
}
JavaScript
ValidatorUpdateDisplay = function (val) {
var ctl = $('#' + val.controltovalidate);
var eCount = 0;
for (var i = 0; i < Page_Validators.length; i++) {
var v = Page_Validators[i];
if (v.controltovalidate == val.controltovalidate) {
if (!v.isvalid) {
eCount++;
ctl.addClass('validationError');
$('td.question:eq(' + i + ')').addClass('red');
}
};
}
if (eCount > 0) {
ctl.addClass('validationError');
} else {
ctl.removeClass('validationError');
$('td.question:eq(' + i + ')').removeClass('red');
}
if (typeof (val.display) == "string") {
if (val.display == "None") {
return;
}
if (val.display == "Dynamic") {
val.style.display = val.isvalid ? "none" : "inline";
return;
}
}
if ((navigator.userAgent.indexOf("Mac") > -1) &&
(navigator.userAgent.indexOf("MSIE") > -1)) {
val.style.display = "inline";
}
val.style.visibility = val.isvalid ? "hidden" : "visible";
}
It sounds like what you really need is custom validation. That way you can fully customize your validation to meet your needs.
Here is a simple example:
<script language="javascript" type="text/javascript" >
function CustomValidator1_ClientValidate(source,args)
{
//put your javascript logic here
}
//-->
</script>
<body>
<form id="form1" runat="server">
<div>
<asp:RadioButton ID="RadioButton1" runat="server" GroupName="direction" Text="left" />
<asp:RadioButton ID="RadioButton2" runat="server" GroupName="direction" Text="right" />
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
<asp:CustomValidator id="CustomValidator1" runat="server" Display="Dynamic" ErrorMessage="please choose" ClientValidationFunction="CustomValidator1_ClientValidate" OnServerValidate="CustomValidator1_ServerValidate"></asp:CustomValidator>
</div>
</form>
</body>
Server Side
protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
args.IsValid = RadioButton1.Checked || RadioButton2.Checked;
}
protected void Button1_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
//validate is successful.
}
}
I'm trying to turn on/off various RequiredFieldValidator controls when checkboxes are checked/unchecked, based on this question. But rather than having a separate js function for each checkbox I want to pass in the ClientID of the input to validate, something like this (only one INPUT here but you can see once it's working I can add more INPUTs without more js):
<asp:TextBox ID="txtSubject" runat="server" />
<asp:CheckBox ID="chkSubjectRequired" runat="server"
OnClick="updateValidator('<%= rfvSubject.ClientID %>');" />
<asp:RequiredFieldValidator ID="rfvSubject" ControlToValidate="txtSubject"
ErrorMessage="You must enter a subject." runat="server" />
<script>
function updateValidator(inputId) {
var enableValidator = !event.srcElement.checked;
var theInput = document.getElementById(inputId);
ValidatorEnable(theInput, enableValidator);
}
</script>
Currently that scriptlet txtSubject.ClientID isn't evaluated, just output directly. I'm sure this is simple but I just don't know the appropriate syntax.
How about adding it via the codebehind (or a script section):
checkSubjectRequired.Attributes.Add("onclick", "updateValidator(" +
txtSubject.ClientID + ")");
This explaination of ClientID may be helpful.
This is because; ASP.NET parser can not parse server tag "<% = %>" for a server side control (i.e. control made as runat='server').
Use the following:
<asp:TextBox ID="txtSubject" runat="server" />
<asp:CheckBox ID="chkSubjectRequired" runat="server"
OnClick="updateValidator('<%#txtSubject.ClientID %>');" />
<asp:RequiredFieldValidator ID="rfvSubject" ControlToValidate="txtSubject"
ErrorMessage="You must enter a subject." runat="server" />
<script>
function updateValidator(inputId) {
var enableValidator = !event.srcElement.checked;
var theInput = document.getElementById(inputId);
ValidatorEnable(theInput, enableValidator);
}
</script>
You could just do this:
<asp:TextBox ID="txtSubject" runat="server" />
<asp:CheckBox ID="chkSubjectRequired" runat="server"
OnClientClick="updateValidator(this.id);" />
<asp:RequiredFieldValidator ID="rfvSubject" ControlToValidate="txtSubject"
ErrorMessage="You must enter a subject." runat="server" />
<script>
function updateValidator(inputId) {
var enableValidator = !event.srcElement.checked;
var theInput = document.getElementById(inputId);
ValidatorEnable(theInput, enableValidator);
}
</script>
I have a datalist inside that I am using a checkbox, I have 1 asp button and 2 image buttton which is outside of datalist something like this
<asp:DataList ID="dlst1" runat="server" RepeatDirection="Horizontal" OnItemDataBound="dlst1_ItemDataBound" CaptionAlign="Left">
<ItemTemplate>
<asp:ImageButton ID="btnImage" runat="server" />
<asp:CheckBox ID="Chkbox" runat="server" TextAlign="Right" />
</ItemTemplate>
</asp:DataList>
<asp:Button ID="Button1" runat="server" Enabled="false" Text="Delete" />
<asp:ImageButton ID="ibtnok" runat="server" Enabled="false" />
I want to enable the Button1 and ibtok when any one checkbox is checked and disable the Button1 and ibtnok when no checkbox is checked.
someone plz help me how to do that with javascript?
If you are using jquery, you can do it this way:
$("#Chkbox").change(function(){
if($(this).is(':checked'))
{
$('#Button1, #ibtnok').attr('disabled','disabled');
}
else
$('#Button1, #ibtnok').removeAttr('disabled');
})
If there are multiple checkboxes appearing, then you can give those checkboxes a common class, and on every change event, you need to loop through all those elements , or take a count of unchecked/checked checkboxes, and do enable/disable your button.
Looping through each of those checkboxes can be done with $('.your_common_chkbox_class').each(function_to_be_performed);
UPDATE
eg:
$('.your_common_chkbox_class').click(function(){
if($('.your_common_chkbox_class:checked').length > 0)
$('#Button1, #ibtnok').attr('disabled','disabled');
else
$('#Button1, #ibtnok').removeAttr('disabled');
})
Thank you # linuxeasy I have taken you code and modified (checkbox id) and now its working
<script type="text/javascript" language="javascript">
$(function () {
$('.CSSCheck').click(function () {
if ($("[id$='Chkbox']:checked").length > 0) {
$("#<%=Button1.ClientID %>").removeAttr('disabled');
}
else {
$("#<%=Button1.ClientID %>").attr('disabled', 'disabled');
}
});
});
</script>