user_dev user_dev - 7 months ago 11
Javascript Question

Why ng-click is getting called the number of times button is clicked?

I am developing an angular-node.js application where I have a button which when clicked triggers a post request. I am facing a strange issue where this post request is getting called the number of times the button is clicked. For example if I click button for first time - post request is called once, if I click again that is the second time post request executes twice and so on. I am clueless what is wrong with the code , here is the code I have :

angular.js:

$scope.addActivity = function(actor){

AJS.dialog2("#impact-dialog").show();

$(".dialog-close-button-impact").click(function(e) {
//e.preventDefault();
AJS.dialog2("#impact-dialog").hide();
});

var countClicks = 0;
$(".SubmitImpact").click(function(e) {

e.preventDefault();


alert("I am being called again and again");
countClicks++;
alert(countClicks);
AJS.dialog2("#impact-dialog").hide();

var data = {
productName: $scope.productName,
actor: actor,
activity : $('#activity').val(),
checked: false
};

console.log("Input data for add impact" + actor)

$http.post('/addActivity', data)
.success(function(data){
$scope.data = data;
$scope.activities = [];

for (var activity in data) {

$scope.activities.push({
text: data[activity].activity,
id: data[activity].actor,
checked: data[activity].checked
});
}
actor = "";


}).error(function(data){
console.log('Error in adding activity' + data)
});

});

};


node.js code:

app.post('/addActivity',function(req, res) {

console.log("I am going to add activity");

console.log("Checked value:" +req.body.checked)

impactMapActivity.create(
{productName: req.body.productName,
checked: req.body.checked,
actor: req.body.actor,
activity: req.body.activity

}, function(err,data){
if (err)
//{
res.send(err);
console.log(err);

impactMapActivity.find({
productName : req.body.productName
}, function(err, data) {
if (err)
res.send(err);

console.log("Printing Data" + data)
res.json(data);
});
}
);

});


template code:

<span><button class=" aui-button dialog-show-button-impact div.actor-\{{$index}}" style="float: left" title="$i18n.getText('add.activity')"
ng-click="addActivity(actor.id)"><span class="aui-icon aui-icon-small aui-iconfont-add">Add</span>
</button>\{{actor.id}}</span>


updated code after removing jquery as suggested :

$scope.addActivity = function(actor){

AP.require('dialog', function(dialog){
dialog.create({
key: 'activity-content',
width: '40%',
height: '30%',
chrome: true,

});
});

AP.require('events', function(events){
events.on('customEvent', function(){
console.log(arguments[0]);
var data = {
productName: $scope.productName,
actor: actor,
activity : arguments[0],
checked: false
};

$http.post('/addActivity', data)
.success(function(data){
$scope.data = data;
$scope.activities = [];

for (var activity in data) {

$scope.activities.push({
text: data[activity].activity,
id: data[activity].actor,
checked: data[activity].checked
});
}

actor = "";

AP.require("messages", function(messages){
//create a message
var message = messages.success('','Activity added');
setTimeout(function(){
messages.clear(message);
}, 2000);
});


}).error(function(data){

AP.require("messages", function(messages){
//create a message
var message = messages.error('','Error in Adding Activity');
setTimeout(function(){
messages.clear(message);
}, 2000);
});
});
});
});

};


But I still face the same problem.

Answer

The problem is that the addActivity function is calling a .click handler every time it is called. Hence, on the second click, there are two .click handlers attached to the element.

There are several ways of fixing this:

  • Refactoring the code in Angular and using ng-click (not possible)
  • Adding the click handler only once. This would involve moving the click handler outside the addActivity function. (best way)
  • Using jQuery.one (as suggested by Sampath).
  • Using name-spaced jQuery events.
Comments