Reputation: 341
I was wondering if there was a way I could have a ng-click function which takes in a scope variable execute after the value of the ng-model of that same scope variable changes. I have a list of analysis
objects in a list called analyses
that have (among others) an include
boolean attribute. They are displayed in html as button checkboxes to press to include/exclude.
I have this html:
Number of bisulfite sequences: {{included}} used / {{excluded}} excluded
<div ng-repeat="analysis in analyses"><br><label class="btn btn-success"
ng-model="analysis.include" ng-click="set(analysis.include)" btn-checkbox>
This is the code in the controller:
$scope.analyses = some_list_of_analyses
$scope.included = 0
$scope.excluded = $scope.analyses.length
$scope.set = function(include){
//more code to execute involving $scope.analyses
if(include){
$scope.included += 1
$scope.excluded -= 1
}
else{
$scope.excluded += 1
$scope.included -= 1
}
}
right now, assuming I start with a list of analyses that are all excluded as you can see in the initialization, when I click on a button, it should increase the included
scope variable by one and decrease the excluded
by one. instead, it passes in analysis.include
before the variable actually changes so the first button I click shows -1 used / n+1 excluded.
The solutions I can think of are either to find some way of having ng-click execute after the scope variable is bound after ng-model, or some way to change $scope.analyses objects within the ng-click method, so then the ng-model statement isn't needed?
Thanks!
EDIT: the ng-model statement is actually needed for the btn-checkbox directive. I need this directive to show a toggle on/off for including/excluding certain analyses. Alternative directives or code to implement css for indicating inclusion/exclusion would be helpful!
Upvotes: 2
Views: 2001
Reputation: 411
What if instead of passing in the analysis.included you get it from the scope in your function
I created a plunkr to demonstrate
basically HTML:
Number of bisulfite sequences: {{included}} used / {{excluded}} excluded
<div ng-repeat="analysis in analyses">
<br />
<label class="btn btn-success" ng-model="analysis.include" btn-checkbox>
<button ng-click="set($index)">Click Me!</button>
</label>
</div>
So here, you pass in the $index so you know which one to look at on $scope in the controller. so then in your controller:
$scope.set = function(i){
var include = $scope.analyses[i].include;
//more code to execute involving $scope.analyses
if(include){
$scope.included += 1
$scope.excluded -= 1
}
else{
$scope.excluded += 1
$scope.included -= 1
}
};
It seemed to work in the plunkr. the included went up and the excluded went down
Update: New Plunkr that toggles included/excluded instead of only incrementing.
As well as updated set function:
$scope.set = function(i){
$scope.analyses[i].include = !$scope.analyses[i].include;
include = $scope.analyses[i].include
//more code to execute involving $scope.analyses
if(include){
$scope.included += 1
$scope.excluded -= 1
} else {
$scope.excluded += 1
$scope.included -= 1
}
};
Upvotes: 0
Reputation: 31761
I'm not quite sure I follow, but I think we can simplify things.
First, let's say that each analysis
has a property called included
.
This allows you to write a couple methods like this:
$scope.included = function() {
var count = 0;
for(var i = 0; i < $scope.analyses.length; i++) {
if($scope.analyses[i].included) {
count++;
}
}
return count;
};
$scope.excluded = function() {
var count = 0;
for(var i = 0; i < $scope.analyses.length; i++) {
if(!$scope.analyses[i].included) {
count++;
}
}
return count;
};
I'll let you do the refactoring to keep it DRY. Then your UI can do something like this:
Number of bisulfite sequences: {{included()}} used / {{excluded()}} excluded
<div ng-repeat="analysis in analyses"><br>
<label class="btn btn-success" ng-model="analysis" ng-click="set(analysis)" btn-checkbox>
And your click can be very simple (note that we are now passing in the analysis object, you can remove the ng-model
attribute):
$scope.set = function(analysis) {
$scope.analysis.included = !$scope.analysis.included;
};
Upvotes: 1
Reputation: 14620
I'm not sure I follow but your conditional logic in $scope.set
is looking for a true value before the include property is increased. This is clearly not happening as demonstrated in this plunker example of your code in action.
The only difference is that I have made sure that include
is a property of the first three analysis && set to true
. Your code is working as expected, your analysis objects are not.
Upvotes: 0
Reputation: 343
My suggestion is to alter the way you are tracking the included / excluded values.
If, instead of adding/subtracting from values you simply track the length of the array then everything should fall into place.
Here is what I'm talking about. Your HTML could look like this:
<div ng-controller="solutionController">
Number of bisulfite sequences: {{included.length}} used / {{analyses.length - included.length}} excluded
<div ng-repeat="analysis in analyses">
<br />
<label class="btn btn-success" ng-click="include(analysis)" btn-checkbox=""></label>
</div>
And your controller could look something like this:
angular.module("routerApp").controller("solutionController", ["$scope", function($scope){
$scope.included = [];
$scope.analyses = ["sodium", "sulfur", "calcium"];
$scope.include = function(includeMe){
$scope.included.push(includeMe);
};
}]);
I mean I don't know exactly what your analyses objects look like etc, but this should get you up and running on binding those counts to the actual array lengths.
Upvotes: 0