I have a function that checks if a value is true or false and a function that changes value.
checkValue(item){
if item.exists{
return 1;
}
else {
return 0;
}
}
and in my html I have a ng-repeat that orders by this function:
<span ng-repeat="item in items | orderBy: checkValue"></span>
<a ng-click="changeItemExists(selectedItem)">
now when item.exists change the orderBy does not work again and order the spans again.
How can I make the orderBy to watch for any changes in the item.exsist?
You don't need the checkValue function.
Just do:
<span ng-repeat="item in items | orderBy: 'exists'"></span>
Then the orderBy will refresh the order automatic on any changes of the 'exists' property.
Related
<li ng-repeat="item in quantityList track by $index" ng-model="isPageValid='true'">
<input value="item.quantity" ng-blur="validateQuantity(item)" ng-model="item.quantity">
</li>
I'm trying to set a default value for a status variable each time an ng-repeat loop occurs. I've tried ng-model, but that doesn't work. For instance,
I'd like to set isPageValid="true" before each time the ng-repeat loop runs. 'True' is will be the default value, and the validation function will test whether isPageValid should be set to 'false'.
I'd like the ng-repeat loop to run each time the ng-blur is exercised.
NOTE: I understand the way I'm using ng-model is incorrect, but this is just to illustrate the issue.
HTML:
<li ng-repeat="item in quantityList track by $index" ng-model="isPageValid='true'">
<input value="item.quantity" ng-blur="validateQuantity(item)" ng-model="item.quantity">
</li>
JS:
scope.validateQuantity = function(item){
var qty = item.quantity;
if(parseInt(qty) >=1 && parseInt(qty) <= 200){
item.isQuantityValid = true;
}else{
item.isQuantityValid = false;
scope.isPageValid = false;
}
}
The loop creates a list of input boxes. The objective is to create a global validation value called isPageValid which is 'false' if the validation by the JS fails for any input box. Note, when ng-blur is exercised, the JS validation runs and loop should re-run.
I believe ng-init could help...
<ul ng-init="isPageValid='true'">
<li ng-repeat="item in quantityList track by $index" >
<input ng-blur="validateQuantity(item)" ng-model="item.quantity">
</li>
</ul>
Note that it would be better practice to initialise isPageValid in the controller that is in the same scope as your validateQuantity function.
Here is an example of how you could initialise isPageValid in your controller and update the value after each call to validateQuantity...
In your controller:
scope.isPageValid = true;
function updatePageValid() {
scope.isPageValid = scope.quantityList.every(item => item.isQuantityValid);
}
scope.validateQuantity = function(item) {
var qty = parseInt(item.quantity);
item.isQuantityValid = (qty >= 1 && qty <= 200);
updatePageValid();
});
The elements in the ng-repeat is filtered by toggling bools on the individual elements.
<div class="message-list" infinite-scroll="loadMore()" infinite-scroll-distance="1" infinite-scroll-parent="true">
<div ng-repeat="powerplant in powerPlantFilter = (selectablePowerPlants | filter:searchString | limitTo: numberToDisplay) track by powerplant.ID">
<div class="message" ng-show="powerplant.IsSelected === false && powerplant.IsInSegment === false">
...
</div>
</div>
</div>
My problem is that, if I apply a certain filter, the first element that should be shown, is number 659 in the list.
If I haven't scrolled down so the numberToDisplay is higher than 659, no elements is shown in the list.
The numberToDisplay has a initial value of 35 and is incremented like this.
$scope.loadMore = function () {
if ($scope.numberToDisplay + 20 < $scope.selectablePowerPlants.length) {
$scope.numberToDisplay += 20;
} else {
$scope.numberToDisplay = $scope.selectablePowerPlants.length;
}
};
How do I work around this problem?
JsFiddle demonstrates the problem
I found your problem.
Here is a working jsfiddle : https://jsfiddle.net/3Lsu2ojz/
Your problem what that you were using ng-show instead of a filter..
ng-show can be understood as 'put display: none !important; on this element if condition'
Consequently, it will still be taken in account in the infinite-scroll directive because elements are really here and limitTo actually does its job.
You can use a custom filter, in your case :
$scope.searchString = {'ShowMe': true }
Does the trick.
Also consider using this syntax instead of yours :
powerplant in powerPlantsFilter = ( selectablePowerPlants |
filter:searchString |
limitTo: numberToDisplay) track by powerplant.ID"
Where powerPlantsFilter is here not a collection from the scope but a collection dynamically created by the spec of limitTo and filter.
I am successfully using ng-repeat and its filter and orderBy functions
<div ng-repeat="center in centers | filter: subjectName | orderBy:[\'name\',\'parent']">'
However when user decides to print/download the "centers" filtered and ordered by angular, the printing method fails because it knows only the original unsorted unfilterd array. Is there a way to capture the object resulted by the filtered/orderBy angular methods so I could use it directly in my printing method?
<div ng-repeat="center in centers | filter: subjectName | orderBy:[\'name\',\'parent']">'
'<span>{{center.name}</span>'+
</div>
....
// what I have so far
<li><a ng-click="print(centers)"><span class="glyphicon glyphicon-print"></span> Print All </a></li>
...
// what I would like to have
...
<li><a ng-click="print(filteredOrderedObject)"><span class="glyphicon glyphicon-print"></span> Print All </a></li>
...
// what I have
scope.print = function(ocw) {
//printing
}
// what I would like to have
scope.print = function(filteredOrderedObject) {
//printing
}
You can use the $filter service directly in your code. Something like this.
var filtered = $filter('filter')(centers, subjectName);
filtered = $filter('orderBy')(filtered, ['name', 'parent']);
https://docs.angularjs.org/api/ng/filter/filter
You can use $eval to evaluate expression in controller.
Following is the syntax
$scope.centers = $scope.$eval("center in centers | filter: subjectName | orderBy:[\'name\',\'parent']");
I have the following ng-repeat:
<td data-ng-repeat="scheduleAbsenceDayContainer in scheduleAbsenceMonthContainer.scheduleAbsenceDayContainers track by $index
and scheduleAbsenceDayContainer can contain an array of scheduleIntervalContainers:
My question now would be if there is any possibility to filter all scheduleIntervalContainers with a special containerType value.
My filter- name is is calles vm.absenceType:
<select name="typeSelection" id="typeSelection" data-ng-model="vm.absenceType"
I have tried this one withour success, because I don't know how to gete any or when not possible only the first one:
<td data-ng-repeat="scheduleAbsenceDayContainer in scheduleAbsenceMonthContainer.scheduleAbsenceDayContainers track by $index | filter: {scheduleIntervalContainers(any or - when not possible than only first): {containerType.value: vm.absenceType}}"
You will need to use nested ng-repeat. Then you can use a custom filter to filter the scheduleIntervalContainers using your vm.absenceType model variable.
<div data-ng-repeat="scheduleAbsenceDayContainer in scheduleAbsenceMonthContainer.scheduleAbsenceDayContainers track by $index">
<div data-ng-repeat="scheduleIntervalContainer in scheduleAbsenceDayContainer.scheduleIntervalContainers | filter: check" >
</div>
</div>
Custom filter function
$scope.check = function(a){
if (angular.equals(a.containerType,$scope.vm.absenceType))
return true;
else
return false;
}
You could also implement this without a custom filter function by renaming your filter model (if it's possible) to vm.containerType and giving filter : vm in the nested ng-repeat.
I have the following ng-repeat:
<div ng-repeat="location in truckDetail.locations track by $index | orderBy:location.startDate" class="locationLoopRow">
<span class="rowEdit"><i ng-click="location.editMode=!location.editMode" class="fa {{location.editMode?'fa-ban':'fa-pencil'}}"></i></span>
<span class="rowDate">{{location.startDate|date:'dd.MM.yyyy'}}</span>
<span class="rowDate">{{location.endDate|date:'dd.MM.yyyy'}}</span>
<span class="rowLocation">{{location.name}}</span>
</div>
The orderBy seems to be ignored completely as seen in the screenshot.
I also tried to solve this by using a sort-function:
| orderBy:dateOrderBy(location.startDate)
$scope.dateOrderBy=function(date) {
return date.getFullYear()+'/'+date.getMonth()+'/'+date.getDate();
},
In debug mode I can see that this message returns values like '2015/4/29'. Still: The list isn't sorted at all
You don't need to call dateOrderBy function in ng-repeat, you only need to specify it's name:
| orderBy:dateOrderBy
Then in your controller your sort function will receive the location object:
$scope.dateOrderBy = function(location) {
return location.startDate;
};
Example in plunkr.
UPD: this one should work as well:
| orderBy:'startDate'
UPD 2: track by $index should always go in the end of expression:
location in truckDetail.locations | orderBy:'startDate' track by $index