Sorting ng-repeat with alternate ordering - angularjs

I am trying to sort a client list using ng-repeat in Angular so that the column with ratings "Hot", "Warm", and "Cold" presented in that order. Currently when it sorts the Rating column it puts them in alphabetical order of "Cold", "Hot", and "Warm". How would I sort it non-alphabetically like that? Is it something with using a custom directive to create a custom attribute related to the rating value and then using "track by"?
Here is a CodePen with a working example of how it sorts alphabetically:
http://codepen.io/MattSchultz/pen/VeBpaQ
<li id="listCont" ng-repeat="client in clients | orderBy:col:reverse as results" ng-class-even="'even'">
<ul class="clients">
<li>{{client.Name}}</li>
<li>{{client.AnnualRevenue | currency}}</li>
<li ng-class="classy('{{client.Rating}}')">{{client.Rating}}</li>
</ul>
</li>

If you pass a string (i.e. an object property name) as the first argument to the orderBy filter, as you are doing in your example, it will attempt to sort alphabetically. To change this behavior, you need to pass a custom sort function instead.
For example:
function ratingSort(val) {
return ['Cold', 'Warm', 'Hot'].indexOf(val.Rating);
};
This function returns a number between -1 (i.e. val.Rating value is not in the array) and 2 (i.e. 'Hot', which is at index 2 in the array). The number returned is used to determine the sort order.
Here is a working example: CodePen

Related

Simplest way to return get the word value for a key in an ng repeat? e.g. 1 = One?

I am outputting a list in angular from an object.
The object can contain anywhere from 0 - 100 items and the design I have to work to use the word for the numbers as the list item name.
E.g. currently:
<li ng-repeat="result in results">
{{ $index }}
</li>
Will return 0,1,2,3 etc. But I need to instead show one, two, three...
Is there a simple way of doing this?
You could simply do {{$index +1}}.
Then apply a custom filter to the this number.
See Angular directive/service to convert number into words (need in Angularjs)? for creating a custom filter that converts a number to a word.

Referring to outer scope variables in orderBy inside ng-repeat

I'd like to have an ng-repeat that's sorted by a value in some external lookup table.
For example, suppose I have a list of items with an itemType for each item. I have a separate itemTypePriorities lookup table in the scope, such that itemTypePriorities[someItemType] gives the priority for a given item type. Now, I'd like to display items in order of their priorities. I am trying the following:
<div ng-repeat="item in items | orderBy:'itemTypePriorities[item.itemType]'>
But it doesn't seem to work - my guess is that it's interpreting the orderBy expression in the context of item, i.e. it's trying to order by the nonsensical expression item.itemTypePriorities[item.itemType].
Is there a way to rewrite the ng-repeat to make it wok correctly, without having to modify the items or itemTypePriorities arrays in any way?
You can use of course the orderBy filter but I think you will need to create a custom function to orderit.
For example:
<div ng-repeat="item in items | orderBy:myFunction>
Where myFunction is declared somewhere in your controller as:
$scope.myFunction = function(el){
//el is the current element under evaluation
}
And should return a value that will be compared with <, === and > with the other. In your case the function can be:
$scope.myFunction = function(el){
return itemTypePriorities.indexOf(el);
}
And that should work

How to split angular ui-sortable list into two even columns?

I am using angularJS ui-sortable directive to sort my array. The code looks like in example:
<ul ui-sortable ng-model="items">
<li ng-repeat="item in items">{{ item }}</li>
</ul>
Is there a way to split the list in a view into two even columns?
For example now I have my list looking like:
1
2
3
4
The thing i want to achieve is to split the list in two columns to look like:
1|3
2|4
In this case I want to start filling the second column only when the first column is full (contains more than two elements).
Update: Thanks for those who answered my question and gave me useful ideas. I have made the solution for this case and if someone gets to the same situation this might be useful:
1) In your controller split the main array into two arrays of equal lenght
2) in your view make two ui-sortable lists (each list for a separate column). Each of the ui-sortable list must have set the ui-sortable options allowing to drag and drop items from first list to the second list and vice versa.
3) define the ui-sortable options in your controller. Options must contain the connectWith property (allowing to drag and drop items between separate lists) and the logic to keep lists the same length. Mine looks like that:
$scope.sortableOptions = {
stop: function () {
// if the first column contains more than 30 elements, move last element to the top of the next column
if ($scope.tpPart1.length > $scope.halfListLength) {
$scope.tpPart2.unshift($scope.tpPart1[$scope.halfListLength]);
$scope.tpPart1.splice($scope.halfListLength, 1);
}
// if the second column contains more than 30 elements, move the first element to the end of the first column
if($scope.tpPart2.length > $scope.halfListLength) {
$scope.tpPart1.push($scope.tpPart2[0]);
$scope.tpPart2.splice(0, 1);
}
},
connectWith: ".list-group"
};
So that's pretty much it. Hope somebody finds this helpful.
I've made a service to split an array by cols or rows.
You can use a double ng-repeat to iterate the subset
<ul ng-repeat="col in main.itemsCols">
<li ng-repeat="item in col">{{ item.text }}</li>
</ul>
Working example here
You could just use two ng-repeats and limit the first one to the first half of the list and the second one the the second half
<ul ui-sortable class="left-column">
<li ng-repeat="item in items | limitTo:items.length/2">{{ item }}</li>
</ul>
<ul ui-sortable class="right-column">
<li ng-repeat="item in items | limitTo:items.length/2:items.length/2">{{ item }}</li>
</ul>
Note: you'd have to take the ceiling of items.length/2 in your controller to get this working for arrays of odd length but that's the basic idea

ng-repeat with a filter and dual order by

I have an array of People I need to filter and order by against two criteria. My filter is simple in that if the name contains what they're typing let it through. For grouping, I want to group all of the people with clockedIn=1 first, and then within those two groups I want to order by last name.
My filter is working perfectly but I cannot seem to get orderBy to work at all no matter what I do...
Full jsfiddle: http://jsfiddle.net/joshuaohana/82k76uj0/1/, shows all helper functions and whatnot
The repeat I'm trying to setup:
<div ng-repeat="person in people | filter:nameFilterFn | orderBy: '+person.clockedIn' | orderBy:'-person.userLastName' ">
<p>{{person.userName}}</p>
<p>{{person.clockedIn}}</p>
</div>
For an ng-repeat, how do I...
Filter against a function
First sort by a boolean in the ng-repeat
Secondly sort against the user's last name
To sort by multiple field use this syntax:
<div ng-repeat="person in people | filter:nameFilterFn | orderBy: ['clockedIn', 'userLastName'] ">
To use reversed lastName use ['clockedIn', '-userLastName']
Updated fiddle here

AngularJS filter with multiple perms

i have a users like this
[{id:1,name:'name',parent_id:0,type:1},
{id:2,name:'name2',parent_id:0,type:2},
{id:3,name:"name1 child",parent_id:1,type:1}]
and i am trying to display parents and child users based on parent_id and type id so for example id 3 is child of id 1 and i am trying to display them like this
http://jsfiddle.net/U3pVM/689/
thanks for help
I fixed up your fiddle:
http://jsfiddle.net/eQP8S/
<div ng-controller="MyCtrl">
<ol>
<li ng-repeat="user in users | filter:{parent_id:0}">
{{user.name}}
<ol>
<li ng-repeat="child in users | filter:{parent_id:user.id, type:user.type}">
{{child.name}}
</li>
</ol>
</li>
</ol>
</div>
Your main problem was that you were trying to use the "filter" filter with a function, which is okay, but that function isn't allowed to take any parameters. If you actually need to create a filter that takes parameters you have to write a custom filter: http://docs.angularjs.org/guide/dev_guide.templates.filters.creating_filters.
But in your case, you can use the standard "filter" filter and pass it objects that will do what you want.
Also, curse you Angular developers for creating an abstraction called filter and then creating a "filter" filter. I mean, how confusing is that?
That is not the correct way to use filters. If you check the documentation, you have three options:
use a string. It will be searched deeply in the object. Any object with some deep value containing the string will match
use a function. It will be called for elements of the array. You should provide any parameter in the function's scope, not as a parameter to the filter.
use an object. It will work like the string match, but for specific properties.
If you use the third case
<li ng-repeat="child in users | filter:{parent_id: user.id, type: user.type}">
and moreover print the child's name
{{ child.name }}
then you'll see the correct results.
http://jsfiddle.net/waAc7/

Resources