Disabling orderBy in AngularJS while editing the list

前端 未结 8 651
情歌与酒
情歌与酒 2021-01-07 23:06

After applying orderBy in my list of input boxes if i edit any field it starts sorting immediately and i loose focus. I tried to dug in the angular code and fou

相关标签:
8条回答
  • 2021-01-07 23:44

    You could override the directive to change the moment of the update to the moment you wish the reordering. You could also just not use ng-model and rely on a custom directive.

    This thread discuss overriding the input directive to change the model update to be triggered by tge blur event. Take a look at the fiddle.

    Although you might override the directive, you shouldn't do this, and the best solution, as explained and exemplified by @Liviu T. in the comments below would be to create a custom directive that removes the event keyup binding and adds a blur one. Here is directive code, and here is Liviu's plunker:

    app.directive('modelChangeBlur', function() {
        return {
            restrict: 'A',
            require: 'ngModel',
                link: function(scope, elm, attr, ngModelCtrl) {
                if (attr.type === 'radio' || attr.type === 'checkbox') return;
    
                elm.unbind('input').unbind('keydown').unbind('change');
                elm.bind('blur', function() {
                    scope.$apply(function() {
                        ngModelCtrl.$setViewValue(elm.val());
                    });         
                });
            }
        };
    });
    
    <input type="text" ng-model="variable" model-change-blur/>
    

    Unfortunately, as Angular events are not namespaces, you will have to remove any previously added event.

    0 讨论(0)
  • 2021-01-07 23:44

    There's no easy or straightforward way to accomplish what you want, but there are some options. You would have to work without ng-model, and instead use the blur event:

    JS:

    var app = angular.module('myapp', []);
    
    app.controller('MainCtrl', function($scope) {
      $scope.items = [
        { name: 'foo', id: 1, eligible: true },
        { name: 'bar', id: 2, eligible: false },
        { name: 'test', id: 3, eligible: true }
      ];
    
      $scope.onBlur = function($event, item){
        // Here you find the target node in your 'items' array and update it with new value
        _($scope.items).findWhere({id: item.id}).name = $event.currentTarget.value;
      };
    });
    
    app.directive('ngBlur', function($parse) {
      return function ( scope, element, attr ) {
        var fn = $parse(attr.ngBlur);
        element.bind( 'blur', function ( event, arg ) {
          scope.$apply( function(){
            fn(scope, {
              $event : event,
              arg: arg
            });
          });
        });
      };
    });
    

    HTML:

    <div ng-controller="MainCtrl">
      <div ng-repeat="item in items | orderBy:'name'" >
        <input value="{{item.name}}" ng-blur="onBlur($event, item)"/>
      </div>
    </div>
    

    Plunker.

    But be aware that this would break the two-way binding between the model and the view.

    0 讨论(0)
  • 2021-01-07 23:45

    A different approach may be to not loose focus to begin with. If your main problem is that your loosing focus, then instead of disabling orderBy, add this directive to your input:

    app.directive("keepFocus", ['$timeout', function ($timeout) {
        /*
        Intended use:
            <input keep-focus ng-model='someModel.value'></input>
        */
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function ($scope, $element, attrs, ngModel) {
    
                ngModel.$parsers.unshift(function (value) {
                    $timeout(function () {
                        $element[0].focus();
                    });
                    return value;
                });
    
            }
        };
    }])
    

    Then just:

    <input keep-focus ng-model="item.name"/>
    

    I know this does not directly answer you question, but it might help solve the underlying problem.

    0 讨论(0)
  • 2021-01-07 23:49

    I was using orderBy on a list that could be re-ordered using angular-sortable, and ran into a similar issue.

    My solution was to perform the ordering manually, by calling the orderBy filter inside the controller when the page was initialised, and then calling it subsequently when necessary, for example in a callback function after re-ordering the list.

    0 讨论(0)
  • 2021-01-07 23:50

    Following @CaioToOn works but it breaks in Angular 1.2.4 (possibly the whole 1.2.X branch). To get it to work you also need to declare the priority of the custom directive to be 1 (the input directive is 0). The directive then becomes:

    app.directive('modelChangeBlur', function() {
    return {
        restrict: 'A',
        priority: 1,
        require: 'ngModel',
            link: function(scope, elm, attr, ngModelCtrl) {
            if (attr.type === 'radio' || attr.type === 'checkbox') return;
    
            elm.unbind('input').unbind('keydown').unbind('change');
            elm.bind('blur', function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(elm.val());
                });         
            });
        }
    };
    

    });

    See http://plnkr.co/edit/rOIH7W5oRrijv46f4d9R?p=preview and https://stackoverflow.com/a/19961284/1196057 for related priority fix.

    0 讨论(0)
  • 2021-01-07 23:58

    You can create custom filter and call that only when necessary. Example when you click on 'Grid header' for sorting or after dynamically adding/removing values to array, or simply click of a button(Refresh Grid)

    You need to dependency Inject Angular filter and sort filter

    angular
       .module('MyModule')
       .controller('MyController', ['filterFilter', '$filter', MyContFunc])
    
         function ExpenseSubmitter(funcAngularFilter, funcAngularFilterOrderBy) {
           oCont = this;
           oCont.ArrayOfData = [{
             name: 'RackBar',
             age: 24
           }, {
             name: 'BamaO',
             age: 48
           }];
           oCont.sortOnColumn = 'age';
           oCont.orderBy = false;
           var SearchObj = {
             name: 'Bama'
           };
    
           oCont.RefreshGrid = function() {
             oCont.ArrayOfData = funcAngularFilter(oCont.ArrayOfData, SearchObj);
             oCont.ArrayOfData = funcAngularFilterOrderBy('orderBy')(oCont.ArrayOfData, oCont.sortOnColumn, oCont.orderBy);
       }
     }
    

    and call in HTML something like:

    <table>
      <thead>
        <tr>
          <th ng-click="oCont.sortOnColumn = 'age'; oCont.RefreshGrid()">Age</th>
          <th ng-click="oCont.sortOnColumn = 'name'; oCont.RefreshGrid()">Name</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="val in oCont.ArrayOfData">
          <td>{{val.age}}</td>
          <td>{{val.name}}</td>
        </tr>
      </tbody>
    </table>
    
    0 讨论(0)
提交回复
热议问题