AngularJS orderby doesn't work when orderby-property is edited
Asked Answered
V

2

7

I have a list of objects in my scope and want to iterate over them, show some of their properties in ordered-by-some-property way and change them.

ng-repeat is used to display textboxes binded to each object of my list and orderby filter which takes "position" as a parameter is applied.

Once again, position is also editable!

Now we change position of certain object once(angular reorders the list as expected) and then change twice. Angular does not reorder the list.

Could anyone explain how it is possible to fix this reorder-only-once situation and what are the reasons for such a behaviour?

Here is fiddle: JSFiddle

HTML

<div ng-controller="MyCtrl">
    <p>List of activities:</p>
    <div ng-repeat="activity in model.activities | orderBy: 'position'">
        <textarea type="text" ng-model="activity.name">

        </textarea>
        {{activity.name}}
        <input type="text" ng-model="activity.position">
    </div>
</div>

JS

var myApp = angular.module('myApp',[]);

function MyCtrl($scope) {
    $scope.model = { 
        activities: [
            {name: "activity 1", position: 1}, 
            {name: "activity 2", position: 2}, 
            {name: "activity 3", position: 3}, 
            {name: "activity 4", position: 4}, 
            {name: "activity 5", position: 5}
        ] 
    };
}
Vachil answered 5/5, 2015 at 21:11 Comment(0)
M
6

Here it goes.

Why does the code behave like that?

position is bound to a text input. That makes the text integers at first and then translated into Strings as soon as you start to type. Then the ordering becomes odd and that's why it fails.

How do I fix this?

You have two options. First option is to change type="text" by type="number" then it'll work. If that's not an option you can create a simple directive (Angular 1.2 onwards)

myApp.directive('integer', function() {
    return {
        require: 'ngModel',
        link: function(scope, el, attr, ctrl){
            ctrl.$parsers.unshift(function(viewValue){
                return parseInt(viewValue, 10);
            });
        }
    };
});

What that code does is to parse every value into an integer making it work.

Melanochroi answered 5/5, 2015 at 21:34 Comment(1)
Thanks, my issue was also an int being converted to string in the view.Hausner
P
2

It occured because your position property is binded to the text value. It means that your position's value becomes the string after the editing through the input.

You need to create custom sorting.

For example:

<div ng-repeat="activity in getOrderedData()">
    {{activity.name}}
    <input type="text" ng-model="activity.position">
</div>

$scope.getOrderedData = function(){
    return $scope.model.activities.sort(compare);
};

var compare = function(a,b){
    if (parseInt(a.position) < parseInt(b.position))
         return -1;
    if (parseInt(a.position) > parseInt(b.position))
        return 1;
    return 0;
};

This will work with every AngularJS version.

Please see this JSFiddle for the whole working example.

Hope it helps!

Pinkeye answered 5/5, 2015 at 21:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.