Bug: Checkbox re-checks itself, inconsistently

Hi

I am having the same bug as here, which led to this bug. But it’s a very old post so I thought I’d create a new one.

I have a very weird issue on iOS with checkboxes… I uncheck them, and then they re-check themselves, inconsistently.
(tested on iOS simulator and iPhone 5s, iOS 8)

    <div id="wavetypes" class="row">
	  <div class="col">
	     <label class="checkbox">
	       <input type="checkbox" ng-model="search.fun" ng-true-value="1" ng-false-value="" ng-click="scrollCollectionTop()"></input>
	     	Small Waves
	     </label>
	  </div>
	  <div class="col">
	     <label class="checkbox">
	       <input type="checkbox" ng-model="search.fun" ng-true-value="0" ng-false-value="" ng-click="scrollCollectionTop()"></input>
	    	Normal Waves
	    </label>
	  </div>
	  <div class="col">
	     <label class="checkbox">
	      	<input type="checkbox" ng-model="search.fun" ng-true-value="2" ng-false-value="" ng-click="scrollCollectionTop()"></input>
	    	Step-Ups
	     </label>
	  </div>
	</div>
....
<ion-item collection-repeat="item in prodataSelect | orderBy:sort | filter:search | filter: selectBrand.brand | filter: selectName.name | unique:model"  item-width="96%" item-height="'18%'"> .... </ion-item>

My system info:

$ ionic info

Your system information:

Cordova CLI: 5.3.3
Ionic Version: 1.1.0
Ionic CLI Version: 1.7.10
Ionic App Lib Version: 0.6.5
ios-deploy version: 1.8.2 
ios-sim version: 5.0.3 
OS: Mac OS X El Capitan
Node Version: v4.2.1
Xcode version: Xcode 7.1 Build version 7B91b

please can someone help on this ?

Hi I really need help on this, this seems to be a bug in the framework…

maybe you should use radio-buttons instead of checkboxes --> radiobutton --> only one element is selectable… checkboxes --> multiple values can be selected

Hi Thanks for answering, I really need to be able to select multiple values, hence the checboxes choice.
Is it a know bug ?

yeah but you are using the same model the checkboxes :wink:

mmmh, i am not sure I see why this would be a problem. I edited my question with more code so you can see that I am using | filter:search in the collection-repeat below.

the problem is… that you are using the same ngModel… if you set one checkbox --> the model is used for the other checkboxes… so use three different models.

ok, can you help me rewite the ng-model(s) and the filter in the collection-repeat so I can display the item(s) that have item.fun=2 item.fun=1 or item.fun=0 or a combination of those ?

I just tried this, but no success…

<input type="checkbox" ng-model="type1" ng-true-value="1" ng-false-value="" ...
<input type="checkbox" ng-model="type0" ng-true-value="0" ng-false-value="" ...
<input type="checkbox" ng-model="type2" ng-true-value="2" ng-false-value="" ...

... | filter:({fun: type1} || {fun: type0} || {fun: type2})

I found this solution, but I find it very very slow…can someone help me find a faster code ?

<input type="checkbox" ng-model="type1" ng-true-value="1" ng-false-value="''" ...
<input type="checkbox" ng-model="type0" ng-true-value="0" ng-false-value="''" ...
<input type="checkbox" ng-model="type2" ng-true-value="2" ng-false-value="''" ...

checkboxesFilterFunc:type1:type0:type2 

with a custom filter:

.filter('checkboxesFilterFunc', function() {
	return function(array, type1, type0, type2) {
		var newarray = [];
		angular.forEach(array, function(line) {       
			if (        (type1 !== '' && line.fun == type1) || (type0 !== '' && line.fun == type0) || (type2 !== '' && line.fun == type2) ) {
				newarray.push(line);
			} else if ( (type1 !== '' && line.fun != type1) || (type0 !== '' && line.fun != type0) || (type2 !== '' && line.fun != type2) ) {
			} else {
				newarray.push(line);
			}
		});
		return newarray; 
	};
});

why are you not working with ng-if in the template --> only show entries where the flags are correctly set?

or --> do not use the filter --> add ngChange-function to each checkbox and there you filter your items

:wink:

1 Like

mmmh @bengtler thanks for your answer, but I don’t really see what you mean, can you pop some code please ?

if you loop over you items --> you do not need to add a custom filter for that check simple but ngIf at the parent dom node like that:

<div ng-repeat="item in items">
  <div ng-if="!type1 || item-type === "1">only shown if not filtered for type1 or if filtered and type is 1</div>
</div>

or with ngChange function:

<input type="checkbox" ng-change="filterItems()" ng-model="type1" ng-true-value="1" ng-false-value="''"...>

$scope.filterItems = function () {
   // loop over items and filter
};

Ok I see, I am gonna try something like this. Do you think the ngChange way will be faster than the custom filter route I made above ?

sometimes yeah, because it is only called if the model changes through a user interaction --> keep in mind the two-way-databinding and watchers of angularjs are fireing everytime the scope changes --> so you ngrepeat with the filter could be called manytimes during a userinteraction.

try it :wink:

I am trying now with ng-if, but the thing is that if I use the ng-if on the elements inside de ion-item, its show empty items in the list.
And it seems I can’t use it directly on the ion-item…

nope then you need to change your dom-structure a little bit or use the altenative syntax with ng-repeat-start ng-repeat-end
https://docs.angularjs.org/api/ng/directive/ngRepeat

you use ngChange :wink:

There is no collection-repeat-start it seems, and my list is big (444 items with images) so I need the collection-repeat.

The ngIf trick works, but the list contains empty :

<ion-item collection-repeat="item in prodataSelect | orderBy:sort | filter: selectBrand.brand | filter: selectName.name | unique:model" item-width="96%" item-height="'18%'">
    <a class="optionfuninit" ui-sref="app.result" data-proid="{{item.id}}" ng-click="launchCompute(item.id)" ng-if="( type1 === '' && type0 === '' && type2 === '' ) || (type1 !== '' && item.fun == type1) || (type0 !== '' && item.fun == type0) || (type2 !== '' && item.fun == type2)"  ng-class="item.fun == '1' ? 'aSmallWave' : (item.fun == '2' ? 'aStepUp' : '')">					
	<img class="imageoptionsbrand" ng-src="{{ imagesUrls[(item.brand | lowercase | nospace)+'.png'] }}"] />
	<div class="listviewTrophy" ng-if="item.winning != 'win0'">
		<i class="icon ion-trophy"></i>
		<div class="winningboardtext" translate="computepage.30">Winning Board</div>
	</div>
	<i class="icon ion-female" ng-show="item.gender == 'female'"></i>
	<div class="listviewtexts">
		<span class="listviewtextsmodel">{{item.model}}</span> - <span class="listviewtextspro" translate="computepage.15">as surfed by</span> 
		<span class="listviewtextspro" ng-class="item.gender == 'female' ? 'nameFemale' : 'nameMale'">{{item.name}}</span>
	</div>
	<div class="imagebox rotate90rightCenter">
		<img class="imageoptionsmodel " ng-src={{imagesUrls[item.imageName]}} />
	</div>
    </a>
</ion-item>

I tried and hide them using:

<ion-item collection-repeat="item ... ng-class="{'heightzero' : !(( type1 === '' && type0 === '' && type2 === '' ) || (type1 !== '' && item.fun == type1) || (type0 !== '' && item.fun == type0) || (type2 !== '' && item.fun == type2))}" ....

css:

#boardselection .item.heightzero {
    height: 0;
}

which hides them, but the ‘space’ is kept in the collection-repeat list, so it’s not viable…

maybe you can wrap the ion-item within something to not get your styling broken.

or like i said --> use the ngChange approach to prefilter your list.