2013-03-08 40 views
15

在我的輸入框列表中應用orderBy後,如果我編輯任何字段,它會立即開始排序,我鬆散的焦點。我試圖在角碼中挖掘,發現他們已經在orderBy的屬性上應用了類似$ watch的東西,因此只要值改變就對列表進行排序。是否有任何方法可以在編輯時禁用orderBy?我不想讓orderBy在編輯文本時對數據進行排序。任何幫助將不勝感激在編輯列表時禁用AngularJS中的訂單

Here is my plunker

注意:我想用排序依據&不需要像任何控制器本身的排序列表中的任何選擇。我只想讓orderBy在頁面加載時對列表進行排序,然後保持不變。

+1

當服務器發送我的數據時,我已經包含了一個額外的'sortBy'列,它具有我想排序的字段,然後ng-repeat使用orderBy。這個字段不在編輯中,所以直到我再次從服務器返回行時纔會更改。即當我「保存」一條記錄時,將從數據庫中提取返回的數據,包括sortBy,它將替換$ scope中的同一行,從而僅在編輯完成後更新頁面上的排序。 – 2016-10-21 16:24:23

回答

8

您可以覆蓋該指令,將更新時刻更改爲您希望重新排序的時刻。您也可以不使用ng-model並依靠custom directive

This thread討論覆蓋輸入指令以更改由tge blur事件觸發的模型更新。看看fiddle

雖然您可能會覆蓋指令,你不應該這樣做,最好的解決辦法,如comments below說明例由@Liviu T.將創建一個自定義指令,刪除該事件KEYUP結合,並增加了一個模糊。這裏是指令代碼,這裏是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/> 

不幸的是,角事件不是命名空間,你將不得不刪除任何以前添加的事件。

+2

我建議你不要重寫,但添加一個新的指令,只有在你需要它的時候才啓用該行爲http://plnkr.co/edit/yoUmEUMMzecNlbKmtgDq?p=preview – 2013-03-08 12:07:13

+0

好的解決方案,但正如評論中所建議的,我們不應該覆蓋已經存在的一個。以及我不想打破任何綁定視圖,即使對於一個keydown事件 – 2013-03-08 12:36:56

+0

我同意,並更新了問題以容納@LiviuT。解。不幸的是,避免'keydown'更新的唯一方法是刪除已經綁定到元素的事件。利維的解決方案的好處在於,您不會失去使用默認指令的其他時刻。 – 2013-03-08 13:14:57

0

有沒有簡單或直接的方式來完成你想要的,但有一些選擇。你會不NG-模型的工作,而是使用模糊事件:

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

但請注意,這會打破模型和視圖之間的雙向綁定。

+0

我確實與我的頁面中的其他元素綁定,我想這些更改不會被反映,直到我模糊輸入框。對?如果我們可以取消/編輯orderBy,它將不會看到任何更改,直到我重新加載頁面或通過任何按鈕進行排序,這會不會更好。你的解決方案毫無疑問是好的,但我不想用ng模型進行破解。希望你明白 – 2013-03-08 12:35:39

+0

'orderBy'過濾器實際上並沒有注意到變化。這是ng-repeat指令,它監視你的'items'數組,並在你的ng模型改變後立即重複它。所以你可以按照我的建議去做,或者你可以創建你自定義的ng-repeat指令,它不會監視變化,而是由其他(明確的)方式觸發。 – Stewie 2013-03-08 12:51:59

2

以下@CaioToOn工作,但它在Angular 1.2.4(可能是整個1.2.X分支)中斷。爲了使它起作用,還需要聲明自定義指令的優先級爲1(輸入指令爲0)。 該指令然後變爲:

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()); 
      });   
     }); 
    } 
}; 

});

請參閱http://plnkr.co/edit/rOIH7W5oRrijv46f4d9R?p=previewhttps://stackoverflow.com/a/19961284/1196057以獲取相關的優先級修復。

+0

這很好,但我在網格中有一個複選框,並且當用戶檢查該項目時,該行將拍攝到它的新排序位置。不知道我能做些什麼,除了關閉這個命令。 – 2017-10-18 14:13:03

10

我在使用angular-sortable可以重新排序的列表上使用orderBy,並且遇到類似問題。

我的解決方案是通過在頁面初始化時調用控制器內部的orderBy過濾器來手動執行排序,然後在需要時隨後調用它,例如在重新排序列表之後的回調函數中。

+2

您能否提供一個示例... – 2014-06-20 15:08:11

+3

官方文檔中有一個示例:https://docs.angularjs.org/api/ng/filter/orderBy。搜索'var orderBy = $ filter('orderBy');'。不要忘記注入'$ filter'。 – Maxence 2014-10-10 13:07:31

0

可以創建自定義過濾器和調用只在必要時。當你在「網格報頭」點擊用於排序或之後動態地添加/數組移除值實施例,或簡單地點擊按鈕(刷新網格)

您需要依賴注入角濾波器排序濾波器

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); 
    } 
} 

和HTML調用類似:

<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> 
2

一種不同的方法可能是不鬆動的焦點開始。如果你的主要問題是,你失去然後,而不是禁用排序依據的焦點,這個指令添加到您的輸入:

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; 
      }); 

     } 
    }; 
}]) 

然後,只需:

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

我知道這並不直接回答你的問題,但它可能有助於解決潛在的問題。

+0

這有助於改善我的情況,謝謝。但是,如果在排序欄中有一個複選框,並且您檢查它,那麼該項目就會按照正確的順序發送。任何想法如何改善? – 2017-10-18 13:33:59

0

您可以在編輯時凍結當前排序。假設你的HTML看起來像這樣:

<tbody ng-repeat="item in items | orderBy:orderBy:reverse"> 
    <tr ng-click="startEdit()"> 
     <td>{{item.name}}</td> 
    </tr> 
</tbody> 

在你的控制器,你寫的:用戶開始編輯

var savedOrderBy, savedReverse; 
$scope.startEdit() = function() { 
    $scope.items = $filter('orderBy')($scope.items, $scope.orderby, $scope.reverse); 

    for (var i = 0; i < $scope.items.length; ++i) { 
     if (i < 9999) { 
      $scope.items[i]['pos'] = ("000" + i).slice(-4); 
     } 
    } 

    savedOrderBy = $scope.orderBy; 
    savedReverse = $scope.reverse; 
    $scope.orderBy = 'pos'; 
    $scope.reverse = false; 
}; 

之前,首先在完全相同的順序當前項目,他們目前出現在排序頁。您可以通過使用當前的排序參數調用orderBy $ filter()來完成此操作。

然後,您將檢查您的 - 現在已排序的項目,並添加一個任意屬性(此處爲「pos」)並將其設置爲當前位置。我零填充它,使位置技術整理之前,0011也許這是沒有必要的,不知道。

通常要記住當前排序,在這裏變量的作用域「savedOrder」和「savedReverse」。

最後你告訴角由新的屬性「pos」進行排序,並且表的順序被凍結,因爲該屬性在編輯時不會改變。

當編輯完成後,您需要做的是相反的。您可以從變量的作用域「savedOrder」和「savedReverse」恢復舊排序:

$scope.endEdit = function() { 
    $scope.orderBy = savedOrderBy; 
    $scope.reverse = reverse; 
}; 

如果您在$ scope.items陣列事項的順序,你也必須重新排序它原來的排序。

0

嘗試使用範圍變量改變順序。在這種情況下,當你要訂貨,你叫你的控制器的功能改變變量順序值要訂購的領域,當你編輯,你重新設置。

例子:

<li ng-repeat="item in filtered = (items | filter:search) | orderBy:order:rever" > 

所以在這裏我們有變量「訂單」,告訴NG-重複由字段列表必須是有序的。一個按鈕調用控制器中的一個函數來更改「訂單」值。

<button type="button" id="orderName" click="changeOrder('item.name')" >Name order </button> 

<button type="button" id="orderDate" click="changeOrder('item.date')" >Date order </button>` 

,然後在changeOrder功能

$scope.order = param; 

在哪裏 'PARAM' 是你想訂購的領域。如果你沒有做任何事情,你將有你有同樣的問題,這樣的話,你已經分配了正確值的順序變量之後你去

$scope.order = ""; 

可復位的順序。 結果是,按下按鈕後排序纔會有效,除非再次按下按鈕,否則不會再次排序。 這可以改變,以便在您完成編輯項目時再次重新命令,如您所願。

相關問題