ng-disabled with index within ng-repeat angularjs - 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;
});
}

Related

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>

How to check If ng-show is true then do something in angularjs

<div class ="container" ng-show="mbrscemployee=='yes'">
<span class="btn">click<span>
</div>
<button class="submit">submit</button>
When someone press button tag, it will check if ng-show is true, then the span will be clicked automatically.
If you want the click event to be triggered on the span element, after you click the button, when ng-show is true:
DOM:
<div class="container" ng-show="mbrscemployee=='yes'">
<span id="myspan" class="btn">click<span>
</div>
<button ng-click="btnClick()" class="submit">submit</button>
Controller:
$scope.btnClick = function() {
if ($scope.mbrscemployee == 'yes') {
angular.element('#myspan').triggerHandler('click');
}
}
Edit: Although, the following approach makes more sense:
DOM
<div class="container" ng-show="mbrscemployee=='yes'">
<span ng-click="spanClick()" id="myspan" class="btn">click<span>
</div>
<button ng-click="btnClick()" class="submit">submit</button>
Controller:
$scope.spanClick = function() {
// do something
}
$scope.btnClick = function() {
if ($scope.mbrscemployee == 'yes') {
$scope.spanClick();
}
}
Just check the condition that the ngShow uses:
<div class ="container" ng-show="mbrscemployee=='yes'">
<span class="btn">click<span>
</div>
<button ng-click="foo()" class="submit">submit</button>
And the controller:
$scope.foo = function() {
if ($scope.mbrscemployee == 'yes') {
}
}
you can write ng-click="someFunction" on submit button which will check your variable $scope.mbrscemployee is true and then you can call subsequent function from there.!

Update facebook page list in to a drop down list

I am working on an angular app which integrates with facebook. I have given the code below,
$scope.getCompanyPages = function () {
fb.login(function (response) {
fb.api('/me/accounts', function (apiresponse) {
if (typeof apiresponse !== 'undefined' && typeof apiresponse.data !== 'undefined') {
$scope.facebookPages = apiresponse.data;
$scope.facebookPages.push({ id: "", name: 'Please select a page' });
$scope.selectedItem = $scope.facebookPages[2];
console.log($scope.facebookPages);
}
});
}, { scope: 'manage_pages' });
};
HTML
<div class="row">
<div class="col-xs-12 col-sm-6 center">
<a href="#" ng-click="shareToMyWall()">
<div class="primary-task">
<i class="fa fa-user fa-3x">
</i>
<h2 class="heading-text fa-bold">Personal Wall</h2>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-6 center">
<a href="#" ng-click="getCompanyPages()">
<div class="primary-task">
<i class="fa fa-building fa-3x">
</i>
<h2 class="heading-text fa-bold">Company Wall</h2>
</div>
</a>
<select ng-if="facebookPages.length > 0" ng-change="shareToFacebookPage(selectedItem.id)" ng-model="selectedItem" ng-options="item.name for item in facebookPages track by item.id"></select>
</div>
</div>
The above method is called in hyperlink click (ng-click) event and the when the response comes back the drop down should update with data. The data does come back but it doesn't update straight away, rather I have to do another click anywhere in the page to update drop down list.
The data in the model is updated when you do the first ng-click. However, AngualrJS probably does not do check so the view still shows the old data. You can force a $digest() check and tell AngualrJS to compare old data and new data and update it if there is any difference. You can use $timeout, $evalAsync, or $apply to trigger $digest() which will update the data immediately.
For example:
$timeout(function () {
$scope.getCompanyPages = function () {...}
//or
$scope.facebookPages = apiresponse.data;
})
Edit: according to Angular JS best coding practice
Always wrap 3rd party API call-backs in to $apply to notify AngularJS
regarding out of environment changes.

How to create multiple elements drag and drop in angularjs

Anyone knows or can point me to an example in which multiple draggable elements are being dragged into a container ?
I need to achieve this behavior using Angular JS.
So far I've tried this : http://codef0rmer.github.io/angular-dragdrop/#/ but it only seems to work for 1 element at a time.
Thansk
That plugin you mentioned doesn't support multi drag&drop out of box.
Here is a working method to support multi drag&drop using the same plugin:
http://embed.plnkr.co/lyCnU3gNeGRrTk1D9hh0/
After you open the link, click on any area to get it to focus and detect your keyboard presses, then hit ctrl and click on the items you want to drag them to make them selected. Finally, drag them.
How it works:
<div class="container form-inline" style="text-align: center;">
<div class="btn btn-droppable" ng-repeat="item in list5" data-drop="true" ng-model='list5' data-jqyoui-options="{accept:'.btn-draggable:not([ng-model=list5])'}" jqyoui-droppable="{index: {{$index}}}">
<div class="btn btn-info btn-draggable"
ng-class="{'selected':(multiSelectedDataColumnsIndecies.indexOf($index) > -1)}"
data-html="true"
data-drag="true"
data-jqyoui-options="draggableOptionsList"
ng-model="list5"
jqyoui-draggable="{index: {{$index}},animate:false,placeholder: 'keep'}"
ng-click="dataItemClick($index,$event,item)">
{{item.title}}
</div>
</div>
</div>
.
$scope.draggableOptionsList = {
appendTo: 'body',
snap: true,
cursor: 'move',
revert: 'invalid',
helper: function() {
console.log('Im in helper');
var selected = $('.selected');
if (selected.length === 0) {
selected = $(this);
}
var container = $('<div/>').attr('id', 'draggingContainer');
container.append(selected.clone());
return container;
}
};
Using jquery UI's helper method, I select all selected items and return them to show dragging effect. And then on click, if ctrl is pressed I save the selected items in a gloabl list array.
<div class="row-fluid">
<ul class="thumbnails">
<li class="span3" style='margin:10px;width: 100%; '>
<div class="thumbnail"
data-drop="true"
ng-model='list1'
data-jqyoui-options
jqyoui-droppable="{onDrop:'dropCallback(list1,$index)',beforeDrop: 'beforeDrop(list1)', multiple:true}">
<div class="caption">
<div class="btn btn-info btn-draggable" ng-repeat="item in list1" ng-show="item.title" data-drag="{{item.drag}}" data-jqyoui-options="{revert: 'invalid'}" ng-model="list1" jqyoui-draggable="{index: {{$index}},animate:true}">{{item.title}}</div>
</div>
</div>
</li>
</ul>
</div>
.
$scope.beforeDrop = function(event, ui, dataModel) {
//In case of multi drop
for (var i = 0; i < $scope.multiSelectedDataColumnsForDrop.length; i++) {
var isExisting = false;
for (var j = 0; j < dataModel.length; j++) {
if (dataModel[j].title == $scope.multiSelectedDataColumnsForDrop[i].title) {
isExisting = true;
break;
}
}
if (!isExisting) {
dataModel.push(angular.copy($scope.multiSelectedDataColumnsForDrop[i]));
}
}
var deferred = $q.defer();
deferred.resolve();
return deferred.promise;
};
In beforeDrop method I select set the model value using the global list of selected items.
If you are talking about nested dropzones check out one of these:
http://marceljuenemann.github.io/angular-drag-and-drop-lists/ (HTML5)
https://github.com/JimLiu/angular-ui-tree (pure JavaScript)
If you just want to drop two elements into the container, then the library you mentioned also supports that, see this example:
http://codef0rmer.github.io/angular-dragdrop/#/list

Button dynamic ng-click stuck after first click

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.

Resources