Angularjs 防止/处理角度传感器中的双击
在angular中,我们可以设置一个按钮来发送ajax请求,如下所示:Angularjs 防止/处理角度传感器中的双击,angularjs,Angularjs,在angular中,我们可以设置一个按钮来发送ajax请求,如下所示: ... ng-click="button-click" 在控制器中: ... $scope.buttonClicked = function() { ... ... // make ajax request ... ... } 因此,为了防止双重提交,我可以在单击按钮时将标志设置为buttonclicked=true,并在ajax回调完成时将其取消设置。但是,即使这样,控制权也会被处理回a
... ng-click="button-click"
在控制器中:
...
$scope.buttonClicked = function() {
...
...
// make ajax request
...
...
}
因此,为了防止双重提交,我可以在单击按钮时将标志设置为buttonclicked=true,并在ajax回调完成时将其取消设置。但是,即使这样,控制权也会被处理回angular,后者将更新Dom。这意味着有一个小窗口,在原来的按钮点击完全100%完成之前,可以再次点击按钮
这是一个小窗口,但仍然可以发生。完全避免这种情况发生的任何提示-客户端,即不对服务器进行任何更新
谢谢首先,您最好添加,当它检测到双击时,只需返回false
:
<ANY ng-click="buttonClicked()" ng-dblclick="return false">
当ajax调用成功或失败时,您需要处理这两种情况,因为如果调用失败,您不希望它显示为已禁用以混淆用户。使用
ng disabled
在这方面效果很好。无论我多么疯狂地点击控制台,消息只填充了一次
var-app=angular.module('plunker',[]);
应用程序控制器('MainCtrl',函数($scope){
$scope.submitData=函数(){
$scope.buttonDisabled=true;
控制台日志(“点击按钮”);
}
函数扩充(){
变量名称,fn;
for(名称在$scope中){
fn=$scope[name];
如果(fn的类型==‘函数’){
if(name.indexOf($)!=-1){
$scope[name]=(函数(名称,fn){
var args=参数;
返回函数(){
console.log(“调用”+名称);
控制台。时间(名称);
fn.应用(此,参数);
console.timeEnd(名称);
}
})(姓名,fn);
}
}
}
}
增强();
});代码>
安古拉斯普朗克
按照建议,使用ng disabled
将解决您的问题。我制作了一个plunker来说明这一点。我刚刚扩展了zsong的代码,在处理程序中为标志添加了一个检查。如果为true,则返回,因为单击已被处理。这样可以防止双击,而不用担心角度计时之类的问题
$scope.flag = false;
$scope.buttonClicked = function() {
if ($scope.flag) {
return;
}
$scope.flag = true;
Service.doService.then(function(){
//this is the callback for success
$scope.flag = false;
}).error(function(){
//this is the callback for the error
$scope.flag = false;
})
}
要详细说明@Jonathan Palumbo的答案(使用ngDisabled)和@andre的问题(“如何在指令中而不是控制器中使用它?”):要允许单击或提交事件冒泡,需要在超时函数中以编程方式将“disabled”属性设置为可单击元素(可以是按钮、链接、span或div)(即使延迟0毫秒)允许在禁用事件之前传递事件:
$timeout(function(){ elm.attr('disabled',true); }, 0);
我参考了@arun-p-johny的答案:。我喜欢用户的解决方案:zsong
但是ng dblclick=“return false;”在js控制台上给出一个问题(我使用的是Chrome Windows7),您可以看到错误
我不能评论(我没有足够的声誉评论他的解决方案)
仅使用禁用的ng
如下图所示,如果您有两个功能:
ng单击并ng dblclick
然后双击,您将执行:
2次单击和1次dblclick
<bla ng-dblclick="count=count+1" ng-click="count=count+0.1" />
双击为您提供了1.2,因此您无法使用ng dblclick阻止两次单击,只需在第二次单击时再添加一个行为即可
Jonathan Palumbo给出了一个在这个线程中使用ng禁用工作的示例。正如其中一个答案中所建议的,我尝试使用ng dbliclick=“return false;”“
来发出JS警告
相反,我使用了运行平稳的ng dblclick=“return”
。尽管这只在
标记中起作用。再次在zsong的doe上展开:
首先,使用此解决方案,人们可以使用双击来使用你的应用程序。老年人有时会这样做(因为他们习惯于双击在windows上打开程序),其他人也会错误地这样做
其次,用户可以尽快单击,他们的浏览器将等待服务器响应,然后再重新启用按钮(这是对Mark Rajcok在zsong的帖子中的评论的修正:“如果AJAX请求花费的时间超过浏览器的双击时间/窗口,这将不起作用。即,用户可以暂停并再次单击。”)
在html中
我最近不得不这么做,我带来了一些解决方案。对我来说,这是一个指令,它是ng click的替代品,只能单击一次
这个解决方案会抛出错误,这使得测试非常容易
.directive('oneClickOnly', [
'$parse', '$compile', function($parse, $compile) {
return {
restrict: 'A',
compile: function(tElement, tAttrs) {
if (tAttrs.ngClick)
throw "Cannot have both ng-click and one-click-only on an element";
tElement.attr('ng-click', 'oneClick($event)');
tElement.attr('ng-dblclick', 'dblClickStopper($event)');
tElement.removeAttr('one-click-only');
var fn = $parse(tAttrs['oneClickOnly']);
return {
pre: function(scope, iElement, iAttrs, controller) {
console.log(scope, controller);
var run = false;
scope.oneClick = function(event) {
if (run) {
throw "Already clicked";
}
run = true;
$(event.toElement).attr('disabled', 'disabled');
fn(scope, { $event: event });
return true;
};
scope.dblClickStopper = function(event) {
event.preventDefault();
throw "Double click not allowed!";
return false;
};
$compile(iElement)(scope);
}
};
},
scope: true
};
}
])
这是我的测试(以防有人感兴趣)
“严格使用”;
描述(“一键式按钮指令”,函数(){
var$scope,testButton,$compile,clickedEvent;
var计数器=0;
beforeach(函数(){
计数器=0;
模块('shared.form.validation');
注入(函数($rootScope,$compile){
$compile=\$compile;
$scope=$rootScope.$new();
$scope.clickEvent=函数(事件){
计数器++;
};
});
});
它(“防止按钮被多次单击”,函数(){
var html=“测试按钮”;
testButton=$compile(html)($scope);
$scope.$digest();
testButton.click();
expect(函数(){testButton.click();}).toThrow(“已单击”);
期望值(计数器)。toBe(1);
});
它(“不允许ng单击同一标记”,函数(){
var html=“测试按钮”;
expect(function(){$compile(html)($scope);}).toThrow(“不能在一个元素上同时单击ng和一次单击”);
});
它(“适用于同一范围内的多个按钮”),函数(){
var=2=0;
$scope.clickEvent2=函数(事件){
计数器2++;
};
var html=“测试按钮”;
var html2=“测试按钮”;
testButton=$compile(html)($scope);
var testButton2=$compile(html2)($scope);
$scope.$digest();
testButton.click();
expect(函数(){testButton2.click();}).not.toThrow(“Alre
<bla ng-dblclick="count=count+1" ng-click="count=count+0.1" />
<ANY
ng-click="buttonClicked();
submitButtonDisabled = 1 + submitButtonDisabled;"
ng-disabled="submitButtonDisabled > 0;"
ng-init="submitButtonDisabled = 0;"
>
$scope.buttonClicked = function() {
Service.doService.then(function(){
//this is the callback for success
// you probably do not want to renable the button here : the user has already sent the form once, that's it - but just if you want to :
$scope.submitButtonDisabled --;
//display a thank you message to the user instead
//...
}).error(function(){
//this is the callback for the error
$scope.submitButtonDisabled --;
})
}
.directive('oneClickOnly', [
'$parse', '$compile', function($parse, $compile) {
return {
restrict: 'A',
compile: function(tElement, tAttrs) {
if (tAttrs.ngClick)
throw "Cannot have both ng-click and one-click-only on an element";
tElement.attr('ng-click', 'oneClick($event)');
tElement.attr('ng-dblclick', 'dblClickStopper($event)');
tElement.removeAttr('one-click-only');
var fn = $parse(tAttrs['oneClickOnly']);
return {
pre: function(scope, iElement, iAttrs, controller) {
console.log(scope, controller);
var run = false;
scope.oneClick = function(event) {
if (run) {
throw "Already clicked";
}
run = true;
$(event.toElement).attr('disabled', 'disabled');
fn(scope, { $event: event });
return true;
};
scope.dblClickStopper = function(event) {
event.preventDefault();
throw "Double click not allowed!";
return false;
};
$compile(iElement)(scope);
}
};
},
scope: true
};
}
])
'use strict';
describe("The One click button directive", function() {
var $scope, testButton, $compile, clickedEvent;
var counter = 0;
beforeEach(function () {
counter = 0;
module('shared.form.validation');
inject(function ($rootScope, _$compile_) {
$compile = _$compile_;
$scope = $rootScope.$new();
$scope.clickEvent = function (event) {
counter++;
};
});
});
it("prevents a button from being clicked multiple times", function () {
var html = "<a one-click-only='clickEvent()'>test button</a>";
testButton = $compile(html)($scope);
$scope.$digest();
testButton.click();
expect(function () { testButton.click(); }).toThrow("Already clicked");
expect(counter).toBe(1);
});
it("doesn't allow ng-click on the same tag", function() {
var html = "<a ng-click='clickEvent()' one-click-only='clickEvent()'>test button</a>";
expect(function () { $compile(html)($scope); }).toThrow("Cannot have both ng-click and one-click-only on an element");
});
it("works for multiple buttons on the same scope", function () {
var counter2 = 0;
$scope.clickEvent2 = function (event) {
counter2++;
};
var html = "<a one-click-only='clickEvent()'>test button</a>";
var html2 = "<a one-click-only='clickEvent2()'>test button</a>";
testButton = $compile(html)($scope);
var testButton2 = $compile(html2)($scope);
$scope.$digest();
testButton.click();
expect(function () { testButton2.click(); }).not.toThrow("Already clicked");
expect(counter).toBe(1);
expect(counter2).toBe(1);
});
});
npm install angular-click-and-wait
bower install angular-click-and-wait
angular.module('demo').directive('disableDoubleClick', function ($timeout) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('click', function(){
$timeout(function(){
elem.attr('disabled','disabled');
}, 20);
$timeout(function(){
elem.removeAttr('disabled');
}, 500);
});
}
};
});
<button ng-click="clickMe()" disable-double-click >Click Me</button>
ng-mousedown="$event.preventDefault();"
You can handle the form validation
$('form.your-form').validate({
rules: {
name: 'required',
email: {
required: true,
email: true
}
},
submitHandler: function (form) {
// Prevent double submission
if (!this.beenSubmitted) {
this.beenSubmitted = true;
form.submit();
}
}
});