AngularJS: scope change in ngClick gets lost - angularjs

I have ngClick and ngClass on an element duplicated by ngRepeat:
<li
ng-class="{'active': $parent.mem.A == $key, 'not-active': $parent.mem.A && $parent.mem.A != $key}"
ng-repeat="($key, A) in As"
ng-click="$parent.mem.A = $key">
Inside the li I have a button that changes the value of $parent.mem.A onClick:
<button ng-click="$parent.mem.A = $parent.findInHash('prev','A')">Activate previous</button>
findInHash() returns the expected value, and when I step through angular, the value in $scope.$apply() from ngEventDirective is correct; but somewhere it's getting lost.
fiddle

in your code all ng-click are executed when you click on the button
you just need to stop the event propagation like the following sample
$scope.findInHash = function ($event, dir, attr) {
$event.stopPropagation();
$event.preventDefault();
...
<button ng-click="$parent.mem.A = $parent.findInHash($event,'prev','A')">...

When you click on the button, the click event is propagated to the li element and its ng-click is executed as well.
In ng-click the $event variable is available so you can easily use it to stop event propagation:
<button ng-click="$parent.mem.A = $parent.findInHash('prev','A');$event.stopPropagation();">Activate previous</button>

Related

Angular: ng-show and functions

Say you have a template like
<a ng-show=function()>a link</a>
My question is: when is function run? How can I tell angular that it is time to re-run the function?
Well, ng-show takes a Boolean value, so your best option for using it is to call your function somewhere in the logic that sets ng-show.
$scope.show = false;
$scope.showSomething = function(myCondition){
if(myCondition){
myFunction();
$scope.show = true;
}
};
<div ng-show='show'></div>
Any expression in ng-show is evaluated at every digest cycle, so the function is run on every digest cycle as well. Thus any change to the value returned by the function, will reflect in the view. If your function makes any changes to the application state that triggers a new digest cycle, you may run into an infinite digest loop (which isn't great).
So be careful about using functions in directives like ng-show. If the function is pure though (it doesn't have any side-effects), you should be safe using it.
Here's a plunker that shows the function being called on every digest.
(Note: in the plunker example, clicking the button actually triggers two digest cycles, since the click event triggers one, and toggling the $scope variable triggers another.)
ng-show="booleanVar" takes a condition or a Boolean value . You can change the value of condition expression to hide and show values at run time .
But if you want some function to be called when ng-show is triggered then you can use $watch in your model .
<div ng-app="myApp" ng-controller="myCtrl" ng-init="isDisplayed = true">
<div ng-show="isDisplayed">something</div>
<button ng-click="isDisplayed = !isDisplayed">Toggle</button>
</div>
var myApp = angular.module('myApp', [])
.controller('myCtrl', function($scope, $log) {
$scope.$watch('isDisplayed', function(newValue, oldValue) {
if (newValue !== oldValue) {
$log.log('Changed!');
}
});
});
See details here

ng-click directive not working on button

html
<button class="btn btn-primary" ng-click="tasks.passivate()">
Passivate <i class="fa fa-spinner fa-spin" ng-if="tasks.passivating"></i>
</button>
task.controller
function passivate() {
console.log('passivate');
vm.passivating = true;
return taskService
.passivate(vm.task.id)
.then(function (task) {
vm.passivating = false;
})
.catch(alertError);
}
The button does not work, passivate does not appear in the console.
When referencing something from the controller in the view, you have to use the $scope. Your function definition should be:
$scope.tasks.passivate = function() {
//...
}
your button, I believe is part of the view which is now bound to a controller. The controller creates a scope object which actually glues your view and the controller. So if you want to invoke a function from the view it should have the scope reference. Hence $scope should be used:-
$scope.tasks.passivate = function(){
//----your logic goes here.
}
Its good to see that you are using tasks.passivate as it will save your from prototypal inheritance. To know more:- Click here

ui.bootstrap popover-is-open doesn't work properly

I want not to show ui.bootstrap popover by using popover-is-open directive. For example, in template:
<button class="fa fa-link add-link"
uib-popover="popover"
popover-is-open="isOpen"> Show popover </i>
And in controller:
angular.module('demoModule').controller('PopoverDemoCtrl', function ($scope) {
$scope.isOpen = false;
});
See plunkr
I am expecting that popover should never be opened, but it opens on click on it. It seems that popover-is-open affects only first angular compiling. Any ideas?
upd: Actually, i want not to show popover only in some cases, in other cases it should be shown. For example, i have download-dialog popover and i want to show it only if size of file is greater than some limit.
The popover-is-open is only for the initial behavior, i.e. if it evaulates to true, then the popover opens instantly even without a click. If you change the value of isOpen to true in your plunkr, you see that (my example plunkr).
What you want is the popover-enable attribute:
<button class="fa fa-link add-link"
uib-popover="popover"
popover-enable="isOpen">Show popover</button>
Update for the question update:
You are free to evaluate any boolean expression in the popover-enable attribute instead of the static isOpen which always evaulates to false in your example.
I have created an advanced plunkr to show that:
<input type="text" ng-model="downloadSize">
<button class="fa fa-link add-link"
uib-popover="popover"
popover-enable="isOpen()">Show popover</button>
with the controller code
$scope.isOpen = function() { return $scope.downloadSize > 100; }
You have a new text box where you can enter a number to simulate the download size. When it gets > 100, the popup will be enabled.
In order to handle the open state whit the popover-is-open value you must set popover-trigger="none" or maybe popover-trigger="'none'". As it says in the docs
Using the 'none' trigger will disable the internal trigger(s), one can
then use the popover-is-open attribute exclusively to show and hide
the popover.
Use
$scope.$apply(function () {
$scope.isOpen = false;
});
method for applying this property

two-way data binding not working for data-ng-disabled

How can I can get btnDisabled to change the data-ng-disabled in the immediate function scope but inside my ajax success scope nothing is playing nicely. How to I get my button to disable?
JS
.controller('CouponCtrl', function($http, $scope) {
$scope.btnDisabled = false;
// $scope.btnDisabled = true; // this works fine too
$http.jsonp("someurl?_jsonp=JSON_CALLBACK").success(function(){
$scope.btnDisabled = true; // does not work
console.log("I see this so why doesn't my button disable?");
// $scope.$digest(); // tried this too but I'm told digest is already running
}
}
HTML
<button data-ng-disabled="{{ btnDisabled }}" class="button button-block green">redeem coupon</button>
NOTE
I've noticed that none of my two-way data binding works when I update a variable via the ajax success scope. Is there a way to overcome that?
ngDisabled expects an expression, not a string (interpolation always outputs string values):
<button data-ng-disabled="btnDisabled"
class="button button-block green">redeem coupon</button>
Working Plunker
Change
data-ng-disabled
to
ng-disabled

Click event gets executed even after window.confirm returns false in angular confirmation dialog

Based on the example given here I have written a directive to display a confirmation dialog in Angular when a button is clicked. The problem is even after the user clicks on the cancel button on the confirmation dialog, the ng-click action gets triggered.
This is the directive:
app.directive('ngConfirmClick',function(){
return {
link: function(scope, element, attr) {
var msg = attr.ngConfirmClick;
var clickAction = attr.ngClick;
attr.ngClick = "";
element.bind('click', function(event) {
if(window.confirm(msg)){
scope.$eval(clickAction);
}
});
}
}
});
This is the section of my index.html that has the ng-confirm-click directives:
<input class="delete" type="button" value="" ng-click="delete(item._id)"
ng-confirm-click="Are you sure you want to delete?">
I tried setting a priority of -1 for the ng-confirm-click directive and that did not help either.
When I was debugging the code on firebug, I found that window.confirm DOES return false when the user clicks on Cancel, so I am not sure why the ng-click (clickAction in the directive code above) is getting executed.
Is there a way to stop propagating the click action if window.confirm returns false?
Any help would be appreciated.

Resources