Button dynamic ng-click stuck after first click - angularjs

I have a button to change the status (STARTED/STOPPED). The button is created in a cell of ng-grid.
The cell is defined as {field:'status', displayName:'Status', cellTemplate: 'cell/statusCellTemplate.html'}] where the template is
<button class="btn btn-primary" ng-click="changeStatus(row.getProperty('id'),'{{row.getProperty(col.field) | switchStatus}}')">{{row.getProperty(col.field)}}</button>
myapp.filter('switchStatus', function() {
return function(input) {
return (input == 'STOPPED') ? 'STARTED' : 'STOPPED';
};
});
In the Plunker, the initial state is STOPPED so the rendered cell is
<button class="btn btn-primary ng-scope ng-binding" ng-click="changeStatus(row.getProperty('id'),'STARTED')">STOPPED</button>
Then clicking the button switch the status as expected and the rendered cell is
<button class="btn btn-primary ng-scope ng-binding" ng-click="changeStatus(row.getProperty('id'),'STOPPED')">STARTED</button>
But clicking the button does not switch the status which is stuck to STARTED whereas the parameter is set to STOPPED.
The Plunker that reproduces the issue.
Edit: Better example
The first answer made it work by removing the filter but I want to keep it. So I created an example where a button is rendered and clicking the button increments the content of the data. The counter is stuck after the first click.
Init: <button class="btn btn-primary ng-scope" ng-click="increment(1)">Increment</button>
Click: <button class="btn btn-primary ng-scope" ng-click="increment(2)">Increment</button>
Click: <button class="btn btn-primary ng-scope" ng-click="increment(2)">Increment</button> Should be increment(3).
The modified Plunker

There were a couple of things that I changed to get this plunker working.
First, in your cell template the changeStatus method didn't need interpolation around the current status. So this:
changeStatus(row.getProperty('id'),'{{row.getProperty(col.field) | switchStatus}}')"
changed to this:
changeStatus(row.getProperty('id'),row.getProperty(col.field))"
Second, you'll notice that I took off the filter inside the cell template. This would have the effect of calling the $filter again and reversing the toggle.
Finally, I noticed that the toggle logic was reversed. So I changed this:
$scope.changeStatus= function(id, status) {
console.log(status);
$scope.currentStatus = status;
if(status == 'STOPPED') {
$scope.myData = [{status: 'STOPPED'}];
} else {
$scope.myData = [{status: 'STARTED'}];
}
$scope.nextStatus = $filter('switchStatus')(status);
}
To this:
$scope.changeStatus= function(id, status) {
console.log(status);
$scope.currentStatus = status;
if(status == 'STOPPED') {
$scope.myData = [{status: 'STARTED'}];
} else {
$scope.myData = [{status: 'STOPPED'}];
}
$scope.nextStatus = $filter('switchStatus')(status);
}
All seems to be working now. Hope this helps.

Related

ng-disabled with index within ng-repeat angularjs

I want to disable button using ng-disabled within ng-repeat. In this case I want to make like button for every items.
I want to disable the button during http request until it return success result.
If I use $scope.btnLikeDisable = true before http request, it will block all Like button.
Here is the code.
<div ng-repeat="item in items">
<button class="button button-block icon ion-thumbsup"
ng-model="item.islike"
ng-class="item.islike== true?'button-on':'button-light'"
ng-click="changeLikeState(item.id, $index);"
ng-disabled="btnLikeDisable"> Like</button>
</div>
This is the function, when the btnLikeDisable is set to true before http then set to false when http request is done
$scope.changeLikeState = function(itemid, index) {
$scope.btnLikeDisable = true;
$http.post(Url).then(function(data) {
}).catch(function(response) {
console.log(response.data.message);
}).finally(function($) {
$scope.btnLikeDisable = false;
});
}
How to achive this so it doesnt disable all like buttons ?
So far I plan to add ng-disabled="isDisable($index)" but I am not sure how the isDisable($index) works.
You can initialise dummy variable for every item called btnLikeDisable
<div ng-repeat="item in items" ng-init="item.btnLikeDisable=false">
<button class="button button-block icon ion-thumbsup" ng-model="item.islike" ng-class="item.islike== true?'button-on':'button-light'" ng-click="changeLikeState(item.id, $index);" ng-disabled="item.btnLikeDisable"> Like</button>
</div>
And, function changes in this way :
$scope.changeLikeState = function(itemid, index) {
$scope.items[index].btnLikeDisable= true;
$http.post(Url).then(function(data) {
}).catch(function(response) {
console.log(response.data.message);
}).finally(function($) {
$scope.items[index].btnLikeDisable= false;
});
}

AngularJS disable double click

I have a problem with a button which contacts server on click. If you do a double click (or any number of clicks for that matter) you will call the server that number of times.
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'ADMIN.CONTENT.DELIVERIES.BODY.CLOSE' | translate }}</button>
<a class="btn btn-danger" ng-click="vm.markDelivered()" ng-dblclick="return" ng-disabled="flag">{{ 'MANAGER.CONTENT.DELIVERIES.BODY.DELETE_PANEL.CONFIRM' | translate }}</a>
</div>
I have tried with ng-disabled but for some reason it doesn't work, as it is saying that that element is not allowed there. I tried changing a to button, but that seems the same. ng-dblclick="return" does nothing also.
Even I had the same issue,And solved using this approach.
<div class="col-sm-4 form-group pull-right">
<input type="submit" name="Submit" class="btn btn-primary"
value="Submit" data-ng-disabled="myForm.$invalid"
ng-click="myForm.$invalid=true;vm.markDelivered()" />
</div>
So on first click myForm.$invalid=true will be set and button will be disabled. SO you will not have multiple calls to your server side code.
So with Bootstrap buttons you won't be able to use ng-disabled. You would have to do it this way:
<div class="btn btn-default" ng-class="{'disabled': idDisabled}" ng-click="doSomething()">I'm a button!</div>
where you are setting the class disabled on the button. But this does not disable the action itself. So when the button is pressed you would need to check that isDisabled variable and if it is true just return and don't do the intended action.
So for example:
doSomething() {
if (isDisabled) {
return
} else {
// do your server call
// when call is finished set isDisabled = false
}
}
I see a couple of issues here.
First, change the anchor tag to a button.
Second, you seem to be using 'controller as' syntax. So, you are probably setting your flag in the vm. But, in your html, you are looking for the flag in the $scope. Change ng-disabled="flag" to ng-disabled="vm.flag"
Your final button line would look like this:
<button class="btn btn-danger" ng-click="vm.markDelivered()" ng-dblclick="return" ng-disabled="vm.flag">{{ 'MANAGER.CONTENT.DELIVERIES.BODY.DELETE_PANEL.CONFIRM' | translate }}</button>
Adding a working plunker here demonstrating ng-disabled
What about using a simple behaviour directive?
function oneTimeCallDirective($timeout) {
var httpCallMock = (cb = () => 'ok') => $timeout(cb, 5000);
return function oneTimeCallPostLink(iScope, iElement) {
let busy = false;
return iElement
.on('click dblclick', function(event) {
if(busy) {
return event.preventDefault();
}
busy = true;
console.info('Well, Calling.');
return httpCallMock()
.then(() => {
console.log('You Can Start Calling Again');
})
.finally(() => {
busy = false;
})
;
})
;
};
}
angular
.module('test', [])
.directive('oneTimeCall', oneTimeCallDirective)
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="test">
<button one-time-call>Click Here</button>
</section>

Disable click on anchor if form is invalid

I've tried several solutions on other answers but so far none has worked as needed, basically I need to disable a button (anchor) if the form is invalid, disabling is not the problem, avoiding the call to the function is.
For that I tried something like this:
<a class="btn icon-btn btn-success" ng-disabled="myForm.$invalid" novalidate ng-submit="myForm.$valid && submit.addOrEditItem()">
<span class="glyphicon btn-glyphicon glyphicon-save img-circle text-success"></span>Save</a>
And on my controller:
$scope.isCreating = true;
$scope.submit = {
addOrEdit: function() {
if($scope.isCreating){
$scope.items.push({type: $scope.newItem.name, description: $scope.newItem.descriptions, isDone:false, editable:false});
}else{
$scope.eItem.type = $scope.newItem.name;
$scope.eItem.description = $scope.newItem.descriptions;
}
$scope.isCreating = true;
$scope.newItem = {};
}
}
Is there any alternatives for this?
Instead of ng-submit, use ng-click:
<a class="btn icon-btn btn-success" ng-disabled="myForm.$invalid" novalidate ng-click="myForm.$valid && submit.addOrEdit()">

Angular UI datepicker popup on button not showing after 1st time

Html:
<button class="btn btn-default" ng-click="openCalendar($event)" ng-model="currentDate" ng-change="dateChanged(currentDate)" datepicker-popup
show-button-bar="false" is-open="calendarOpened">
<i class="fa fa-calendar"></i>
{{currentDate | date}}
</button>
Controller:
$scope.openCalendar = function ($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.calendarOpened = true;
};
The thing is, the $scope.openCalendar is called just fine, however the popup does not shown after the first time.
It's like $scope.calendarOpened = true didn't trigger the popup.
Any ideas? How can I debug or figure out why it is not working?
Use
is-open="$parent.calendarOpened"

Angular-UI & Bootstrap: change class based on class

I am using Angular-UI and Bootstrap 3.
I have this HTML connected to a scope (assume the scope has a $scope.myBtn = "A", say).
<button type="button" class="btn btn-primary" ng-model="myBtn" btn-radio="A">A</button>
<button type="button" class="btn btn-primary" ng-model="myBtn" btn-radio="B">B</button>
<button type="button" class="btn btn-primary" ng-model="myBtn" btn-radio="C">C</button>
This produces three blue buttons, which is what I want. When one of the buttons is clicked, the $scope.myBtn value gets set to the right value (say, "B") and that button's class gets set to:
<button type="button"
class="btn btn-primary active" ng-model="myBtn" btn-radio="B">B</button>
(notice the addition of active in the class).
When one button is active I want to remove the "btn-primary" class and add the "btn-success" class. I know I could do it this way (and it is what I am actually using now):
<button
type = "button"
class = "btn"
ng-class = "{
'btn-primary': myBtn != 'B',
'btn-success': myBtn == 'B'
}"
ng-model = "myBtn"
btn-radio = "'B'">B</button>
But that seems brutally verbose for every button... Is there some better way to do this?
You can use a directive to conditionally set the class by observing the model value
app.directive('myClass', function () {
return {
link: function (scope, element, attrs) {
attrs.$observe('ngModel', function (item) {
if (scope.myBtn !== 'B') {
attrs.$set('class', "btn-primary");
} else {
attrs.$set('class', "btn-success");
}
});
}
}
});
Working Demo

Resources