limitto - Deshabilitando orderBy en AngularJS mientras edita la lista
ng-attr-title (8)
Estaba usando orderBy
en una lista que se podía reordenar usando angular-sortable , y angular-sortable un problema similar.
Mi solución fue realizar el pedido manualmente, llamando al filtro orderBy
dentro del controlador cuando se inicializó la página, y luego llamándolo posteriormente cuando sea necesario, por ejemplo, en una función de devolución de llamada después de reordenar la lista.
Después de aplicar orderBy
en mi lista de cuadros de entrada, si edito cualquier campo, comienza a ordenar inmediatamente y pierdo el enfoque. Intenté buscar en el código angular y descubrí que han aplicado algo como $ watch en los atributos de orderBy, por lo tanto, cada vez que el valor cambia, ordena la lista. ¿Hay alguna forma de desactivar orderBy al editar? No quiero permitir que la orden ordene los datos mientras edito el texto. Cualquier ayuda será apreciada.
Nota : quiero usar orderBy y no necesito ninguna alternativa como ordenar la lista desde cualquier controlador. Solo quiero que orderBy ordene la lista una vez en la carga de la página y luego permanezca tranquila.
No hay una manera fácil ni directa de lograr lo que quiere, pero hay algunas opciones. Tendrías que trabajar sin ng-model, y en su lugar usar el evento de desenfoque:
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 .
Pero tenga en cuenta que esto rompería la unión bidireccional entre el modelo y la vista.
Puede anular la directiva para cambiar el momento de la actualización al momento en que desee la reordenación. También podría simplemente no usar ng-model
y confiar en una directiva personalizada .
Este hilo discute sobre reemplazar la directiva de entrada para cambiar la actualización del modelo que se activará por el evento de blur
tge. Echa un vistazo al fiddle .
Aunque puede anular la directiva, no debería hacer esto, y la mejor solución, como se explica y ejemplifica en @Liviu T. en los comentarios a continuación, sería crear una directiva personalizada que elimine el enlace de activación de teclas de evento y agregue una borrosa. . Aquí está el código de la directiva, y aquí está el desplumador de Liviu :
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/>
Desafortunadamente, como los eventos angulares no son espacios de nombres, tendrá que eliminar cualquier evento agregado previamente.
Puede congelar el pedido actual mientras está editando. Digamos que su html se ve así:
<tbody ng-repeat="item in items | orderBy:orderBy:reverse">
<tr ng-click="startEdit()">
<td>{{item.name}}</td>
</tr>
</tbody>
En tu controlador escribes:
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;
};
Antes de que el usuario comience a editar, primero ordena los elementos actuales exactamente en el mismo orden en que aparecen actualmente en la página. Para hacerlo, llame a orderBy $ filter () con los parámetros de clasificación actuales.
Luego revisa sus elementos, ahora ordenados, y agrega una propiedad arbitraria (aquí "pos") y la establece en la posición actual. Lo coloco a cero para que la posición 0002 se compagine antes de 0011. Tal vez eso no sea necesario, ni idea.
Normalmente desea recordar el orden actual, aquí en las variables de alcance "savedOrder" y "savedReverse".
Y finalmente le dices a angular que ordene por esa nueva propiedad "pos" y voilà el orden de la tabla está congelado, porque esa propiedad simplemente no cambia durante la edición.
Cuando hayas terminado de editar, tienes que hacer lo contrario. Restaura el orden anterior de las variables de alcance "savedOrder" y "savedReverse":
$scope.endEdit = function() {
$scope.orderBy = savedOrderBy;
$scope.reverse = reverse;
};
Si el orden de la matriz $ scope.items es importante para usted, también tendrá que ordenarlo nuevamente a su orden original.
Puede crear un filtro personalizado y llamar a eso solo cuando sea necesario. Ejemplo al hacer clic en ''Encabezado de cuadrícula'' para ordenar o después de agregar / eliminar valores dinámicamente a la matriz, o simplemente hacer clic en un botón (Actualizar cuadrícula)
Necesitas depender. Inyectar filtro angular y ordenar filtro.
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);
}
}
y llamar en HTML algo como:
<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>
Seguir a @CaioToOn funciona pero se rompe en Angular 1.2.4 (posiblemente toda la rama 1.2.X). Para que funcione, también debe declarar que la prioridad de la directiva personalizada es 1 (la directiva de entrada es 0). La directiva se convierte entonces en:
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());
});
});
}
};
});
Consulte http://plnkr.co/edit/rOIH7W5oRrijv46f4d9R?p=preview y https://.com/a/19961284/1196057 para la corrección de prioridad relacionada.
Trate de usar una variable de alcance para cambiar el orden. En este caso, cuando va a realizar un pedido, llama a una función en su controlador que cambia el valor del orden variable al campo que desea ordenar y cuando lo está editando, lo restablece.
Ejemplo:
<li ng-repeat="item in filtered = (items | filter:search) | orderBy:order:rever" >
Así que aquí tenemos la variable "orden" para indicar la repetición ng por qué campo debe ordenarse la lista. Un botón llama a una función en el controlador que cambia el valor de "orden".
<button type="button" id="orderName" click="changeOrder(''item.name'')" >Name order </button>
<button type="button" id="orderDate" click="changeOrder(''item.date'')" >Date order </button>`
Y luego, en la función changeOrder.
$scope.order = param;
Donde ''param'' es el campo por el que quiere ordenar. Si no hace nada más, tendrá el mismo problema que tuvo, entonces, después de haber asignado el valor correcto a la variable de orden, vaya.
$scope.order = "";
Que restablece el pedido. El resultado es que la ordenación solo será efectiva cuando se presione el botón y luego no se ordenará nuevamente a menos que usted presione nuevamente el botón. Esto se puede cambiar para que vuelva a ordenar cuando, por ejemplo, haya terminado de editar un elemento, como quería.
Un enfoque diferente puede ser no perder el enfoque para empezar. Si su principal problema es que está perdiendo el enfoque, entonces, en lugar de deshabilitar orderBy, agregue esta directiva a su entrada:
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;
});
}
};
}])
Entonces solo
<input keep-focus ng-model="item.name"/>
Sé que esto no responde directamente a su pregunta, pero podría ayudar a resolver el problema subyacente.