WebForms keeps re-rendering a TextBox control with a data- attribute in spite of my code removing it on PostBack-- which I shouldn't have to do in the first place, since the PostBack process clears attributes. I've tried clearing the attributes in OnInit and OnUnload, but they somehow reappear after leaving code-behind. They only ever reset through the TextChanged event.
I'm going crazy trying to figure out if I have a cache setting somewhere in my web.config that would prevent ASP.NET from properly removing this attribute.
For reference, the (as far as I can determine) relevant sections of my code:
.aspx JavaScript:
$("[data-confirm]").each(function () {
var alertText = $(this).attr("<%= _data_confirm %>");
$(alertText).dialog({
modal: true,
draggable: false,
resizable: false,
closeOnEscape: false,
title: "Note",
width: 330,
buttons: {
"Continue with Application": function () {
$(this).dialog("close");
}
}
});
});
.aspx.cs C#:
protected override void OnInit(EventArgs e)
{
if (Page.IsPostBack)
{
ClearIraDistributionConfirmation();
}
iraDistribution.TextChanged += iraDistribution_TextChanged;
}
void iraDistribution_TextChanged(object sender, EventArgs e)
{
if (SessionFormData.ConfirmedIraDistribution == false
&& SessionFormData.IraDistribution.HasValue
&& SessionFormData.IraDistribution.Value > 0)
{
iraDistribution.Attributes[_data_confirm] =
"<div>You must submit a copy of the first page of your 2014 federal tax return to verify the rollover amount.</div>";
iraDistribution.Attributes[_aria_live] = "assertive";
SessionFormData.ConfirmedIraDistribution = true;
}
else if (SessionFormData.ConfirmedIraDistribution)
{
ClearIraDistributionConfirmation();
}
}
private void ClearIraDistributionConfirmation()
{
if (SessionFormData.ConfirmedIraDistribution)
{
iraDistribution.Attributes.Clear();
}
}
I've verified that at the end of the PostBack cycle, iraDistribution has no attributes set. As soon as my .aspx JS hits the very first line of JavaScript -- which is way before the JS I pasted here -- iraDistribution has its data-confirm attribute set.
What am I missing?
The answer to this question is: The Page Life Cycle.
I made the mistake of trying to check for TextBox values in OnInit when they weren't yet available. OnUnload didn't work either because the values had already been rendered to output at that point.
I've fixed this bug by reordering the code above and moving it into the OnLoadComplete event. My code now looks like (well -- not quite like this, but it's abbreviated to remove code that interacts with the Session, functions I defined to improve readability, etc.):
protected override void OnLoadComplete(EventArgs e)
{
base.OnLoadComplete(e);
if (SessionFormData.ConfirmedIraDistribution)
{
iraDistribution.Attributes.Clear();
}
else if (SessionFormData.ConfirmedIraDistribution == false
&& SessionFormData.IraDistribution.HasValue
&& SessionFormData.IraDistribution.Value > 0)
{
iraDistribution.Attributes[_data_confirm] =
"<div>You must submit a copy of the first page of your 2014 federal tax return to verify the rollover amount.</div>";
iraDistribution.Attributes[_aria_live] = "assertive";
SessionFormData.ConfirmedIraDistribution = true;
}
}
The moral of this story: The Page Life Cycle will eat your lunch.
Related
<div>
<asp:Repeater ID="ProductView" runat="server" OnItemDataBound="Repeater1_ItemDataBound" >
<ItemTemplate>
<asp:Label ID="lblAddressID" runat="server" Text='<%# Eval("OrderNumer") %>' Visible = "false" />
<asp:LinkButton ID="Delete" CssClass="MordersButton" OnCommand="btnDelete_Click" OnClientClick="return ShowMessage();" runat="server" Text='<%#Eval("Delete") %>'></asp:LinkButton></h5>
</ItemTemplate>
</asp:Repeater>
</div>
<script type="text/javascript">
function ConfirmBox(msgtitle, message, controlToFocus) {
$("#msgDialogAlert").dialog({
autoOpen: false,
modal: true,
title: msgtitle,
closeOnEscape: true,
buttons: [{
text: "Yes",
click: function () {
$(this).dialog("close");
if (controlToFocus != null)
controlToFocus.focus();
}
},
{
text: "No",
click: function () {
$(this).dialog("close");
if (controlToFocus != null)
controlToFocus.focus();
}
}],
close: function () {
$("#operationMsgAlert").html("");
if (controlToFocus != null)
controlToFocus.focus();
},
show: { effect: "clip", duration: 200 }
});
$("#operationMsgAlert").html(message);
$("#msgDialogAlert").dialog("open");
};
function ShowMessage() {
ConfirmBox("This is Title - Please Confirm", "Are you sure you wanted to delete? This cannot be undone!", null);
return false;
}
</script>
protected void btnDelete_Click(object sender, EventArgs e)
{
RepeaterItem item = (sender as LinkButton).Parent as RepeaterItem;
string name = (item.FindControl("Delete") as LinkButton).Text.Trim();
string OrderNumber = (item.FindControl("lblAddressID") as Label).Text.Trim();
{
using (SqlCommand cmd = new SqlCommand("DC_ManageOrders_Update"))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#CategoryType", name);
cmd.Parameters.AddWithValue("#OrderNumber", OrderNumber);
cmd.Connection = cn;
cn.Open();
cmd.ExecuteNonQuery();
cn.Close();
}
}
this.FlavorImage1Bind();
}
If I Click the button Yes after the modal box opened the delete is not happening. Please help how can i achieve this
i want to run the btnDelete_Click code to delete the record, without modal box through normal javascript i can able to delete the record.
If someone able to help me it will be very usefull to me ...
Ok, the problem here?
When you use onClientClick, you "goal" is to return true (server side code runs), or false - server side button event does not run.
So, you can say use a js confirm box. That's because confirm() HALTS the code.
However, jquery.UI, and in FACT MOST web based software does NOT halt code. Most web based controls (bootstrap dialogs, and jQuery.UI) are NOT modal. They are asynchronous in operation. Blocking, or halting code in js is simple RARE allowed these days.
So, most suggested solutions center around say disabling the event code for the button, and then you execute a _doPostBack(). This is not bad, but then you can't have that button conditional run based on return of true/false. So you wind up with a extra button, extra _doPoast back. So most solutions are really quite poor.
So, when this code runs:
OnClientClick="return ShowMessage();
The above code runs async - does NOT wait. So the dialog pops, but the code continues running and the server side button click will fire!! - (and the dialog that was displayed will of course colipase since we have a page post back.
So, we want:
avoid document ready solutions - they are horrid to debug
document ready means we have a VERY difficult time following code flow.
we want a simple function - has to return true/false.
but, jQuery.UI dialogs do not wait, and they don't halt code.
So, to avoid world poverty, 2-3 extra routines, messy _doPostback, and code to disable the button?
Do it this way:
Adopt a code standard that you create a true/false var of the SAME name of the function (with "OK" on the end), and scope the variable to that function.
Also, I assume that the delete button when clicked (without the onclientclick) works as you wish.
<script>
var mypopok = false; // runs on browser load
function mypop() {
if (mypopok) {
return true;
}
mydiv = $('#dlg1');
mydiv.dialog({
autoOpen: false, modal: true, title: 'Yes/no test', width: '250px',
position: { my: 'top', at: 'top+150' },
buttons: {
'ok': function () {
mypopok = true;
mydiv.dialog('close');
$('#Button1').click();
},
'cancel': function () {
mydiv.dialog('close')
}
}
});
// Open the dialog
// if dialog has MORE then just ok, cancel, and say has text
// box, check box in content, then you MUST move back to form
mydiv.parent().appendTo($("form:first"))
mydiv.dialog('open')
return false;
}
</script>
Now, the button click code looks like this:
<asp:Button ID="Button1" runat="server" Height="48px" Text="Button" Width="171px"
ClientIDMode="Static" OnClientClick="return mypop();"/>
So what will occur?
You will click on the button - the code will run and return false!!! - (remember, it does NOT wait or halt). Now the dialog does pops, but button event code will not trigger.
Based on yes or no, we set that bol flag to true or false. If cancel, then we just close the dialog. If "ok", then we set the flag = true and RE-CLICK the SAME button. Now the button click runs again, but we in our routine return true before the pop dialog code runs, and thus now the server side event click runs.
We:
did not have to consider using await (promise)
did not have to add a extra button
did not have document ready and code ALL OVER in the page
did not have to add extra buttons and events.
code is liner - easy to read - all in one spot.
Now I would consider adding the parameters to the Actual OnClientClick,
Say like this:
OnClientClick="return mypop('This is Title - Please Confirm',
'Are you sure you wanted to delete? This cannot be undone!', null);"
And add the parms to the mypop.
You can't really use two routines like you have, since as noted this:
function ShowMessage() {
ConfirmBox("This is Title - Please Confirm", "Are you sure you wanted to delete? This cannot be undone!", null);
return false;
}
Confirmbox does NOT halt or wait - the code will "run right though" and immediate return false.
So use the flag trick I outline, and re-click the SAME button again when user hits ok. That way, you don't wire up 3-4 routines, and you don't need to add extra buttons or use _DoPostBack() in the js code.
I have a Kendo UI Toolbar:
$("#toolbar").kendoToolBar({
items : [ {
type : "button",
text : "List"
} ]
})
and I have a script in my app that will translate strings according to the chosen language; i.e. it will find the word 'List' and change it to 'Liste'.
The problem is with timing. There is a finite time that the Toolbar takes to render, so calling my translation function inside
$(document).ready(function() { })
Is too early.
The Kendo Toolbar component doesn't have an onRendered event handler. Otherwise I could use that.
Is there any way to define an event that occurs after all Kendo components, including Toolbar have been rendered?
First of all: Ain't there a better way to localize your page?
Besides that: I've created a small JavaScript function which waits until a given list of elements exist. Just call it as shown in the comment in $(document).ready(function() { }).
// E.g. waitUntilKendoWidgetsLoaded({ "toolbar": "kendoToolBar" }, doTranslation);
function waitUntilKendoWidgetsLoaded(widgets, action) {
var allLoaded = true;
for (var key in widgets) {
if (widgets.hasOwnProperty(key)) {
allLoaded = allLoaded && $("#" + key).data(widgets[key]) !== undefined;
}
}
if (allLoaded) {
action();
}
else {
setTimeout(waitUntilKendoWidgetsLoaded, 500, widgets, action);
}
}
But be aware: The only thing you know for sure is that the element exists. It does not ensure that the element has finished loading. Especially with Kendo widgets which use a datasource you should use the existing events to trigger your function at the right moment.
I'm currently developing a Ckeditor 4 widget, but I run into the following issue. I'd like my widget button initially disabled untill an AJAX call is done and has a particular result.
The widget code:
editor.widgets.add('smartobject', {
dialog: 'smartobject',
pathName: lang.pathName,
upcast: function(element) {
return element.hasClass('smartObject');
},
init: function() {
this.setData('editorHtml', this.element.getOuterHtml());
},
data: function() {
var editorHtml = this.data.editorHtml;
var newElement = new CKEDITOR.dom.element.createFromHtml(editorHtml);
newElement.replace(this.element);
this.element = newElement;
}
});
The button is added as follows:
editor.ui.addButton && editor.ui.addButton('CreateSmartobject', {
label: lang.toolbar,
command: 'smartobject',
toolbar: 'insert,5',
icon: 'smartobject'
});
With this code it seems I can't configure the default disabled state.
So I searched in the docs, and thought I had the fix.
The following code addition seemed to work:
editor.$smartobjectPluginPreloadAvailableSmartobjectsPromise.done(function(availableSmartobjects) {
if (availableSmartobjects && availableSmartobjects.length > 0) {
editor.getCommand('smartobject').enable();
}
});
editor.addCommand('smartobject', new CKEDITOR.dialogCommand('smartobject', {
startDisabled: 1
}));
After adding this code the button is initially disabled, and enabled after the AJAX call is completed. So far so good. After a while I tried to add a new 'smartobject', but after completing the dialog config, the widgets 'data' function is not called. When editing an already existing smartobject by doubleclicking the element in the editor, still works..
I've probably mixed up different 'code styles' for adding a button, but I can't find the fix I need for my use case..
Any ideas how to fix this?
It seemed my idea was not possible through the ckeditor widget API and I combined some API logic which was not meant to be combined..
For now I simply fixed it by initially hiding the widgets button through CSS and adding a class to the button after the AJAX call succeeded:
.cke_button__createsmartobject {
display: none !important;
}
.cke_button__createsmartobject.showButton {
display: block !important;
}
And the JS logic:
editor.ui.addButton && editor.ui.addButton('CreateSmartobject', {
label: lang.toolbar,
command: 'smartobject',
toolbar: 'insert,5',
icon: 'smartobject'
});
// Enable the button if smartobjects are allowed for the itemtype of this editor.
editor.$smartobjectPluginPreloadAvailableSmartobjectsPromise.done(function(availableSmartobjects) {
if (availableSmartobjects && availableSmartobjects.length > 0) {
jQuery('.cke_button__createsmartobject').addClass('showButton');
}
});
It's not the solution I'm most proud of, but it works for now.
This link explains how to handle it on the server side via the ASPxGridView.AfterPerformCallback event:
http://www.devexpress.com/Support/Center/p/Q274366.aspx
How can I handle it on the client side?
I am working on a custom server control and I have this client side function on my control:
applyFilterToGridView: function () {
this.theGridView.ApplyFilter(this.filterCondition);
this.filterAppliedEvent();
}
Because ApplyFilter does a callback, this.filterAppliedEvent() is not called at the right time which should be after the filtering is complete. this.filterAppliedEvent() is a client side function.
This event is fired after the filter is applied:
protected void theGridView_AfterPerformCallback(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewAfterPerformCallbackEventArgs e)
{
if (e.CallbackName == "APPLYFILTER")
{
}
}
Is there some way to to tell the client to call filterAppliedEvent from the AfterPerformCallback event?
I would prefer to be able to run this.filterAppliedEvent() after AfterPerformCallback on the client side if possible.
Thanks in advance.
EDIT ( Solution thanks to Filip ):
C#:
protected void theGridView_AfterPerformCallback(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewAfterPerformCallbackEventArgs e)
{
if (e.CallbackName == "APPLYFILTER")
{
ASPxGridView gv = sender as ASPxGridView;
gv.JSProperties["cp_FilterApplied"] = "true";
gv.JSProperties["cp_VisibleRowCount"] = gv.VisibleRowCount;
}
}
theGridView.ClientSideEvents.EndCallback = "function(s,e){"theGridView.theGridView_OnEndCallback(s, e);}";
JS:
theGridView_OnEndCallback: function (s, e) {
if (s.cp_FilterApplied) {
if (s.cp_FilterApplied.indexOf('true') != -1) {
this.adjustGridViewSize();/*Uses visible row count.*/
delete s.cp_FilterApplied;
}
}
}
In theGridView_AfterPerformCallback add entry to JSProperties collection, e.g. cp_FilterApplied.
Add EndCallback client side event handler.
In EndCallback handler execute this.filterAppliedEvent() if cp_FilterApplied exists.
Delete that property so that subsequent callback doesn't execute filterAppliedEvent method.
Look at my answer to this question for code example.
It's really the same problem, just set js property in theGridView_AfterPerformCallback instead of ASPxGridView1_RowUpdated and adjust names/js code to your needs.
I have two script controls (code is very simplified):
class Form : IScriptControl
{
Panel pnl;
Button trigger;
public Form()
{
pnl = new Panel();
trigger = new Button();
IPresenter p = new Popup();
p.SetContent(this.pnl);
this.Controls.Add(trigger);
}
}
class Popup : IScriptControl, IPresenter
{
public void SetContent(Control content)
{
this.Controls.Add(content);
}
}
Now in the HTML output, i see the following (again very simplified):
<div id="ctrlForm">
<div id="ctrlPopup">
<div id="ctrlFormPnl"></div>
</div>
<div id="ctrlFormTrigger"></div>
</div>
And script:
Sys.Application.add_init(function() {
$create(Form, {"_presenter":"FormPresenter"}, null, null, $get("ctrlForm"));
});
Sys.Application.add_init(function() {
$create(Popup, {"_isOpen":false}, null, null, $get("ctrlPopup"));
});
Question: How I can do, that the script that creates the popup appears on page before script of form...in other words, when initializer of the ctrlForm control executes, I want to get reference to forms presenter.
I hope I clearly explained what I want to do. Thanks.
In order to archive you goal you should let the child controls to register with ScriptManager before your control.
This can be done if you register your control with ScriptManager inside overridden Render method, after calling base.Render(...)
like that:
protected override void Render(HtmlTextWriter writer)
{
// Let child controls to register with ScriptManager
base.Render(writer);
// Now, when all the nested controls have been registered with ScriptManager
// We register our control.
// This way $create statement for this control will be rendered
// AFTER the child controls' $create
if (this.DesignMode == false)
{
ScriptManager sm = ScriptManager.GetCurrent(this.Page);
if (sm != null)
sm.RegisterScriptDescriptors(this);
}
}