PDA

View Full Version : سوال: جلوگیری از کلیک های مجدد کاربر



2farsoft
دوشنبه 23 فروردین 1389, 16:02 عصر
سلام
دوستان من برای اضافه کردن یک رکورد جدید درgridview یکinsert button در footer gridview تعریف کردم مانند برنامه (Common_GridView_Functions_by_ Behrouz_Rad)
مشکلم اینه که وقتی کاربری چندین بار پشت سر هم روی insert btuuon کلیک میکنه چندین سطر بدون کنترل اضافه میشه.ولی اگه منتظر پیغام update progress بمونه کنترل انجام میشه و از ثبت رکوردهای اشتباه جلوگیری میشه.
حالا من چطوری میتونم جلوی این کلیک ها رو بگیر و تا ثبت کامل یک رکورد فقط یکبار کاربر بتونه کلیک کنه.
در یکی از post ها دیدم که پیشنهاد شده بود از این کد استفاده کنم


BtnAddNew.OnClientClick = "this.disabled=true;";

ولی این کار باعث میشه حتی یکبار هم insert نشه یعنی بعد کلیک هیچ post back ای صورت نمی گیره و بعد هم که دیگه disable می شه

2farsoft
سه شنبه 24 فروردین 1389, 17:50 عصر
:متفکر:
به هر حال من این کار رو کردم
اول کلیک های سمتclient رو شمردم.



var count=0;
function clickcounter(state) {
if (state == 1)
count += 1;
if (state == 0)
count=0;
if (count > 1)
alert("لطفاً منتظر بمانید");

}

و در روال row_created گریدم این کد رو اضافه کردم


BtnAddNew.OnClientClick = "clickcounter('1');";

و وقتی یک insert با موفقیت انجام بشه این کد رو اضافه کردم


ScriptManager.RegisterStartupScript(this, typeof(Page), "clickcounter", "clickcounter('0')", true);

فعلاً درست کار میکنه ولی اگه می شد به جای alert در تابع clickcounter یه کار دیگه کرد به نظرم بهتر بود دوستان اگر لطف بفرمایند و راهنمایی های ارزشمندشون رو از من دریغ نکنند واقعاً ممنون میشم:لبخند:

••••••••••••••• ويرايش شده توسط مدير •••••••••••••••
لطفاً از كنايه زدن خودداري كنيد! و احترام خود و ديگر كاربران رو حفظ كنيد!

Alireza_Salehi
سه شنبه 24 فروردین 1389, 20:00 عصر
می توانید در هنگام اولین کلیک دکمه مورد نظر را غیر فعال کنید تا مجددا کلیک نشود:
دکمه ها در واقع از طریق جاوااسکریپت عملیات Validation و PostBack را انجام می دهند، شم امی توانید این کار را خودتان انجام دهید.

ابتدا یک تابع جاوا اسکریپت می نویسید به صورت زیر:
function disableButton(ButtonNameOrg, ButtonName, ValidationGroup) {
if (Page_ClientValidate(ValidationGroup)) {
var button = document.getElementById(ButtonName);
button.disabled = true;
button.style.backgroundColor = "#8B8989";
button.style.backgroundImage = "url('../_images/ajax-loader.gif')";
button.style.backgroundRepeat= "no-repeat"
__doPostBack(ButtonNameOrg, null);
//this__doPostBack('ctl00$cph$ButtonNewFileSubmit', '');
// WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(ButtonNameOrg, "", true, ValidationGroup, "", false, false))
}
else {
return false;
}
};

بعد متد Page_Load را به صورت زیر تغییر می دهید:
protected void Page_Load(object sender, EventArgs e)
{
BtnAddNew.Attributes.Add("onclick", String.Format("javascript:disableButton('{0}','{1}','{2}');",
BtnAddNew.ClientID.Replace("_", "$"), BtnAddNew.ClientID, BtnAddNew.ValidationGroup));
}
به همین سادگی!

اون کدهای مربوط به استایل هم در قسمت جاوااسکریپت صرفا جهت زیبائی است ، مثلا وقتی disableشد یک تصویر loading روی دکمه ظاهر می شود.

2farsoft
شنبه 28 فروردین 1389, 10:28 صبح
سلام
دوست عزیز خیلی ممنون از وقتی که گذاشتید و پاسخ دادید ولی من تو اجرای این کد مشکل دارم این قسمت مثل اینکه هیچ وقت true نمی شه

if (Page_ClientValidate(ValidationGroup))

چون وقتی شرط رو بر می دارم عمل disable رو درست انجام میده و البته این کار باعث میشه که کد یه بار هم اجرا نشه
در ضمن من از update panel دارم استفاده می کنم و دستور


__doPostBack(ButtonNameOrg, null);

باعث می شه کل صفحه رفرش بشه
لطفاً بهم بگید کجا دارم اشتباه می کنم.

Milad Mohseny
شنبه 28 فروردین 1389, 15:17 عصر
من از این روش استفاده میکنم و با postback و validation ها و ValidationSummary هم مشکلی نداره.
این تابع js:
function disButton(btn) {
if (typeof (Page_ClientValidate) == 'function' && Page_ClientValidate() == false) {
return false;
}
btn.disabled = true;
btn.value = "صبر كنيد.";
return true;
}

این هم روش استفاده:
<asp:Button ID="btnSave" runat="server" Text="ارسال" OnClick="btnSave_Click"
OnClientClick="disButton(this);" UseSubmitBehavior="false" CausesValidation="false" />

به UseSubmitBehavior="false" CausesValidation="false دقت کنید.

Alireza_Salehi
شنبه 28 فروردین 1389, 19:29 عصر
من از این روش استفاده میکنم و با postback و validation ها و ValidationSummary هم مشکلی نداره.
این تابع js:
function disButton(btn) {
if (typeof (Page_ClientValidate) == 'function' && Page_ClientValidate() == false) {
return false;
}
btn.disabled = true;
btn.value = "صبر كنيد.";
return true;
}

این هم روش استفاده:
<asp:Button ID="btnSave" runat="server" Text="ارسال" OnClick="btnSave_Click"
OnClientClick="disButton(this);" UseSubmitBehavior="false" CausesValidation="false" />

به UseSubmitBehavior="false" CausesValidation="false دقت کنید.
بله این روش هم جواب میده ولی نه برای یک ValidationGroup خاص بلکه کل صفحه رو ولید میکنه.

Alireza_Salehi
شنبه 28 فروردین 1389, 19:31 عصر
سلام
دوست عزیز خیلی ممنون از وقتی که گذاشتید و پاسخ دادید ولی من تو اجرای این کد مشکل دارم این قسمت مثل اینکه هیچ وقت true نمی شه

if (Page_ClientValidate(ValidationGroup)) چون وقتی شرط رو بر می دارم عمل disable رو درست انجام میده و البته این کار باعث میشه که کد یه بار هم اجرا نشه
در ضمن من از update panel دارم استفاده می کنم و دستور


__doPostBack(ButtonNameOrg, null);
باعث می شه کل صفحه رفرش بشه
لطفاً بهم بگید کجا دارم اشتباه می کنم.

در حالتی که دکمه مورد نظر validationGroup نداره باید قسمت مربوط به Validation از تابع جاوااسکریپت حذف بشه با یک شرط ساده می توانید آن را هم حل کنید.

2farsoft
دوشنبه 30 فروردین 1389, 10:42 صبح
من از این روش استفاده میکنم و با postback و validation ها و ValidationSummary هم مشکلی نداره.
این تابع js:
function disButton(btn) {
if (typeof (Page_ClientValidate) == 'function' && Page_ClientValidate() == false) {
return false;
}
btn.disabled = true;
btn.value = "صبر كنيد.";
return true;
}

این هم روش استفاده:
<asp:Button ID="btnSave" runat="server" Text="ارسال" OnClick="btnSave_Click"
OnClientClick="disButton(this);" UseSubmitBehavior="false" CausesValidation="false" />

به UseSubmitBehavior="false" CausesValidation="false دقت کنید.

دوستان من واقعاً معذرت می خوام که اینقدر سوالم رو تکرار می کنم ولی در این روش ها Button مورد نظر بلافاصله disable می شه و کد سمت سرور دیگه اجرا نمیشه به همین دلیل من تو کد خودم مجبور شدم کلیک های کاربر رو بشمارم تا بعد از دومین کلیک اون دکمه disable بشه یا پیغام بده. خیلی ممنون از راهنمایی هاتون

Alireza_Salehi
دوشنبه 30 فروردین 1389, 11:08 صبح
آن روشی که بنده در پست شماره 3 برای شما مثال زدم دقیقا مطابق با روند کاری خود ASP.NET است و با در نظر گرفتن موارد زیر کلیک شدن دکمه را شبیه سازی می کند:
1. از توابعی که خود asp.net برای ایجاد postback استفاده می کند.
2. بعد از postback شدن دکمه به حالت فعال بر می گردد.
3. در صورتی که دکمه در یک گروه validation قرار گرفته باشد فقط پس از معتبر بودن validation عمل postback انجام می گیرد.


اگر بدون valdation می خواهید کار انجام شود کافیست در کدی که ذکر شد دستور if را حذف کنید.
در چندین پروژه این روش استفاده شده و به خوبی جواب می دهد.
هم دکمه غیرفعال می شود و هم کد سرور اجرا می شود.

کدی که نوشتید را ضمیمه کنید تا ببینیم مشکلش چیه...

2farsoft
دوشنبه 30 فروردین 1389, 17:17 عصر
آن روشی که بنده در پست شماره 3 برای شما مثال زدم دقیقا مطابق با روند کاری خود ASP.NET است و با در نظر گرفتن موارد زیر کلیک شدن دکمه را شبیه سازی می کند:
1. از توابعی که خود ASP.NET برای ایجاد postback استفاده می کند.
2. بعد از postback شدن دکمه به حالت فعال بر می گردد.
3. در صورتی که دکمه در یک گروه validation قرار گرفته باشد فقط پس از معتبر بودن validation عمل postback انجام می گیرد.


اگر بدون valdation می خواهید کار انجام شود کافیست در کدی که ذکر شد دستور if را حذف کنید.
در چندین پروژه این روش استفاده شده و به خوبی جواب می دهد.
هم دکمه غیرفعال می شود و هم کد سرور اجرا می شود.

کدی که نوشتید را ضمیمه کنید تا ببینیم مشکلش چیه...




به خاطر ارور هایی که داشتم( object excepted)کد های شما رو به این شکل تغییر دادم
الان کد من در روال GridView1_RowCreated این شکلیه


protectedvoid GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{

if (e.Row.RowType == DataControlRowType.Footer )
{
Button BtnAddNew = newButton ();
BtnAddNew .ID ="BtnAddNew";
BtnAddNew .Text = "ثبت";
BtnAddNew .CommandName = "Insert";
BtnAddNew .BorderStyle = BorderStyle.Solid;
BtnAddNew .BorderWidth = Unit.Pixel(1);
BtnAddNew .BackColor =Color.FromKnownColor(KnownColor.White);
BtnAddNew.Attributes.Add("Style", "WIDTH: 70px; Font-Family:Tahoma; Font-Size:10px; FONT-WEIGHT: bold; color:#5D7B9D;BACKGROUND-IMAGE: url(../Images/add.gif); BACKGROUND-REPEAT: no-repeat");


BtnAddNew.Attributes.Add("onclick", String.Format("disableButton('{0}',this,'{2}');", BtnAddNew.ClientID.Replace("_", "$"),BtnAddNew.ClientID, BtnAddNew.ValidationGroup));
e .Row .Cells [9].Controls .Add (BtnAddNew );

}
}

و تابع js رو به خاطر اروری که می داد این جوری تغییر دادم




function disableButton(ButtonNameOrg, ButtonName, ValidationGroup) {
//if (Page_ClientValidate(ValidationGroup)) {
//var button = document.getElementById(ButtonName);
ButtonName.disabled = true;
__doPostBack(ButtonNameOrg, null);
// }
// else {
// return false;
// }


}




با این کد ها بعد از کلیک روی button اصلاً روال row_command اجرا نمیشه یعنی هیچ رکوردی ثبت نمی شه و در ضمن اینجوری کل صفحه رفرش می شه که من نمی خوام این اتفاق بیفته.



فکر می کنید تغییراتی که من روی کد شما دادم باعث می شه جواب درست نگیرم؟:ناراحت:

Alireza_Salehi
دوشنبه 30 فروردین 1389, 19:44 عصر
به خاطر ارور هایی که داشتم( object excepted)کد های شما رو به این شکل تغییر دادم
الان کد من در روال GridView1_RowCreated این شکلیه


protectedvoid GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{

if (e.Row.RowType == DataControlRowType.Footer )
{
Button BtnAddNew = newButton ();
BtnAddNew .ID ="BtnAddNew";
BtnAddNew .Text = "ثبت";
BtnAddNew .CommandName = "Insert";
BtnAddNew .BorderStyle = BorderStyle.Solid;
BtnAddNew .BorderWidth = Unit.Pixel(1);
BtnAddNew .BackColor =Color.FromKnownColor(KnownColor.White);
BtnAddNew.Attributes.Add("Style", "WIDTH: 70px; Font-Family:Tahoma; Font-Size:10px; FONT-WEIGHT: bold; color:#5D7B9D;BACKGROUND-IMAGE: url(../Images/add.gif); BACKGROUND-REPEAT: no-repeat");


BtnAddNew.Attributes.Add("onclick", String.Format("disableButton('{0}',this,'{2}');", BtnAddNew.ClientID.Replace("_", "$"),BtnAddNew.ClientID, BtnAddNew.ValidationGroup));
e .Row .Cells [9].Controls .Add (BtnAddNew );

}
}
و تابع js رو به خاطر اروری که می داد این جوری تغییر دادم




function disableButton(ButtonNameOrg, ButtonName, ValidationGroup) {
//if (Page_ClientValidate(ValidationGroup)) {
//var button = document.getElementById(ButtonName);
ButtonName.disabled = true;
__doPostBack(ButtonNameOrg, null);
// }
// else {
// return false;
// }


}


با این کد ها بعد از کلیک روی button اصلاً روال row_command اجرا نمیشه یعنی هیچ رکوردی ثبت نمی شه و در ضمن اینجوری کل صفحه رفرش می شه که من نمی خوام این اتفاق بیفته.



فکر می کنید تغییراتی که من روی کد شما دادم باعث می شه جواب درست نگیرم؟:ناراحت:

به به.......!؟!؟!؟!؟!؟؟!..................
یک بار از اول اون کدهای من رو بخون،
چه جوری شما توی تابع جاوااسکریپت واسه ButtonName خاصیت disabled ست کردید؟

این خط رو چرا حذف کردید؟

var button = document.getElementById(ButtonName);

این خط کارش پیدا کردن دکمه شماست نباید پاک بشه

2farsoft
سه شنبه 31 فروردین 1389, 10:08 صبح
چه جوری شما توی تابع جاوااسکریپت واسه ButtonName خاصیت disabled ست کردید؟

این خط رو چرا حذف کردید؟

var button = document.getElementById(ButtonName);

این خط کارش پیدا کردن دکمه شماست نباید پاک بشه



خوب به جای button name از توی کد this رو فرستادم


BtnAddNew.Attributes.Add("onclick", String.Format("disableButton('{0}',this,'{2}');", BtnAddNew.ClientID.Replace("_", "$"), BtnAddNew.ClientID, BtnAddNew.ValidationGroup));

با کد شما وقتی یه button رو از toolbox میکشم می ندازم توی فرم کار می کنه ولی چون من button رو توی کد تعریف کردم با کد شما نمیشناسه و ارور 'null' is null or not an object رو می ده به خاطر همین خود this رو فرستادم و اینجوری هم میشناسه همdisable میکنه .

Vahid_moghaddam
سه شنبه 31 فروردین 1389, 10:22 صبح
این مقاله رو بخونید

http://encosia.com/2008/03/04/why-my-aspnet-ajax-forms-are-never-submitted-twice/

2farsoft
سه شنبه 31 فروردین 1389, 12:23 عصر
دوستان کدهایی که شما گذاشتید درسته مشکله من اینه که دارم از ajax استفاده می کنم

Vahid_moghaddam
سه شنبه 31 فروردین 1389, 13:43 عصر
با چه روشی ajax رو پیاده سازی کردید؟

2farsoft
سه شنبه 31 فروردین 1389, 15:23 عصر
از UpdatePanel و ScriptManager استفاده کردم.

Vahid_moghaddam
سه شنبه 31 فروردین 1389, 15:52 عصر
از UpdatePanel و ScriptManager استفاده کردم.

توی مقاله ای که براتون لینکش رو گذاشتم هم از update panel استفاده شده. اگه مقاله رو بخونید مطمئن باشید جلوی چند بار کلیک کردن رو می گیرید. البته اون مقاله دقیقا راه حل چیزی که شما می خواید نیست اما به شما ایده میده چه کاری باید انجام بدید

Alireza_Salehi
سه شنبه 31 فروردین 1389, 20:14 عصر
عزیر من اون کدی که گذاشتم داخل یک گریدویو که داخل آپدیت پنل بوده تست شده است شما کدها را اشتباه به پروژه خودتون منتقل کرده اید....
کد ذکر شده در چند پروژه در حالت های مختلف تست شده و به خوبی کار می کند.

در ضمن اون کد با ادغام و ترکیب کدهای چند منبع مختلف تولید شده است.

از طریق کد سی شارپ نمی شود به یک تابع جاوا اسکریپت متغییر this را پاس داد، جاوا اسکریپت نمی فهمد.........!!!!؟؟؟؟؟!!!!

2farsoft
چهارشنبه 01 اردیبهشت 1389, 10:17 صبح
از طریق کد سی شارپ نمی شود به یک تابع جاوا اسکریپت متغییر this را پاس داد، جاوا اسکریپت نمی فهمد.........!!!!؟؟؟؟؟!!!!
:متفکر: من کدم رو موقع اجرا watch کردم این شکلیه


disableButton('BtnAddNew',this,'');

چرا نباید جاوا اسکریپت این this رو نشناسه؟

2farsoft
چهارشنبه 01 اردیبهشت 1389, 10:27 صبح
توی مقاله ای که براتون لینکش رو گذاشتم هم از update panel استفاده شده. اگه مقاله رو بخونید مطمئن باشید جلوی چند بار کلیک کردن رو می گیرید. البته اون مقاله دقیقا راه حل چیزی که شما می خواید نیست اما به شما ایده میده چه کاری باید انجام بدید

خیلی ممنون از مقاله مفیدتون کد مثال این مقاله رو dl کردم و دارم روش کار میکنم ولی همون کد رو توی masterpage که می ذارم button ها رو نمی تونه پیدا کنه. ویا با کد خودم ادغام میکنم پیغام Sys is undefined رو میده.هنوز زیاد روش وقت نذاشتم.دارم روش کار می کنم.

Alireza_Salehi
پنج شنبه 02 اردیبهشت 1389, 19:47 عصر
نکته اول: جاوا اسکریپت روی کدهای HTML کار می کند و هیچ اطلاعی از جریانات و آبجکت های سی شارپی شما ندارد. شما بایستی نام یک آبجکت سی شارپی (به صورت یک رشته) را به یک متد جاوا اسکریپت پاس بدهید و سپس در آن متد جاوا اسکریپت با روشهائی که هست آن را پیدا کنید و سپس با آن کار کنید.

نکته دوم: اگر یک کنترلی مثلا ID اش برابر با BtnAddNew باشد وقتی داخل یک Container دیگر مثل View یا Panel یا ... قرار بگیرد در سمت HTML و وقتی با جاوا اسکریپت کار می کنید دیگر ID اش BtnAddNew نخواهد بود. بلکه ID تمام Container ها با جدا کننده $ به اول آن اضافه می شود.

بنابراین کدی که نوشتم را با دقت بیشتری مطالعه کنید، موارد فوق همگی در آن رعایت شده اند.