tablas - obtener datos de una tabla html javascript
mover elementos hacia arriba y hacia abajo en una selección múltiple que no funciona (2)
swapIf
actualizar su implementación swapIf
para que swapIf
el modelo, no las opciones de la vista:
function swapIf(sel,i1,i2) {
if ( ! select[i1].selected && select[i2].selected) {
var obj1 = $scope.peoples[i1];
var obj2 = $scope.peoples[i2];
$scope.peoples[i2] = obj1;
$scope.peoples[i1] = obj2;
select[i1].selected = true;
select[i2].selected = false;
}
}
Además, elimine el orderBy
la vista e inicialice el pedido en el controlador utilizando el servicio $filter
. La razón por la que necesita hacer esto es porque la lista se reordena cada vez que el usuario hace clic en el botón arriba / abajo.
He creado una aplicación angularjs con selección múltiple sobre la que tengo el botón arriba y abajo, dentro de la cual, cuando hago clic en el botón arriba y abajo, el movimiento correspondiente de los elementos debe hacerse dentro de la selección múltiple, tengo un material de muestra que se ha realizado con javascript normal que hace lo mismo correctamente como se muestra en este violín , pero cuando traté de implementar lo mismo en AngularJS no funcionaba correctamente
¿Puede alguien decirme alguna solución para esto
Mi código es como se indica a continuación
html
<div ng-app=''myApp'' ng-controller="ArrayController">
<select id="select" size="9" ng-model="persons" ng-options="item as item.name for item in peoples | orderBy:''name''" multiple></select>
<br/>
<button ng-click="moveUp()">Up</button>
<br/>
<button ng-click="moveDown()">Down</button>
<br/>
</div>
guión
var app = angular.module(''myApp'', []);
app.controller(''ArrayController'', function ($scope) {
$scope.peoples = [{
name: ''Jacob''
}, {
name: ''Sunny''
}, {
name: ''Lenu''
}, {
name: ''Mathew''
}, {
name: ''Ferix''
}, {
name: ''Kitex''
}];
$scope.moveUp = function () {
var select = document.getElementById("select");
var i1=0, i2=1;
while (i2 < select.options.length) {
swapIf(select,i1++,i2++);
}
};
$scope.moveDown = function () {
var select = document.getElementById("select");
var i1=select.options.length-1, i2=i1-1;
while (i1 > 0) {
swapIf(select,i1--,i2--);
}
};
var swapVar = '''';
function swapIf(sel,i1,i2) {
if ( ! select[i1].selected && select[i2].selected) {
swapVar = select[i2].text;
select[i2].text = select[i1].text;
select[i1].text = swapVar;
swapVar = select[i2].value;
select[i2].value = select[i1].value;
select[i1].value = swapVar;
select[i1].selected = true;
select[i2].selected = false;
}
}
});
persons
devolverán una selección de los elementos seleccionados en la lista. Una solución es crear un bucle for que obtenga el indexOf
de cada elemento en el conjunto de persons
. splice
esos elementos de la matriz de peoples
, incremente / disminuya el índice y splice
nuevo en la matriz de peoples
.
Aquí hay una nueva función moveUp()
que puede mover hacia arriba varios elementos seleccionados:
$scope.moveUp = function () {
for(var i = 0; i < $scope.persons.length; i++) {
var idx = $scope.peoples.indexOf($scope.persons[i])
console.log(idx);
if (idx > 0) {
var itemToMove = $scope.peoples.splice(idx, 1)
console.log(itemToMove[0])
$scope.peoples.splice(idx-1, 0, itemToMove[0]);
}
}
};
Aquí está la función moveDown()
actualizada:
$scope.moveDown = function () {
for(var i = 0; i < $scope.persons.length; i++) {
var idx = $scope.peoples.indexOf($scope.persons[i])
console.log(idx);
if (idx < $scope.peoples.length) {
var itemToMove = $scope.peoples.splice(idx, 1)
console.log(itemToMove[0])
$scope.peoples.splice(idx+2, 0, itemToMove[0]);
}
}
};
Aquí está la demostración de trabajo (No funciona tan bien, solo se conserva como referencia, ver abajo)
Esta solución también mantiene la separación entre la Vista y el Controlador. El controlador tiene la tarea de manipular los datos, la vista muestra esos datos. De esta forma podemos evitar cualquier enredo poco agradable. Las manipulaciones DOM desde dentro del controlador son increíblemente difíciles de probar.
EDITAR después de algunos retoques: Entonces mi solución anterior funcionó en algunos casos, pero funcionaría extrañamente con diferentes combinaciones de selección. Después de algunas excavaciones, me pareció necesario agregar track por:
<select id="select" size="9" ng-model="persons" ng-options="item as item.name for item in peoples track by item.name" multiple>
Parece que seleccionar devolvería el objeto de persons
con órdenes de selección arbitrarias y esto estaba estropeando las cosas, especialmente después de hacer clic varias veces, parecía confundirse acerca de dónde estaban las cosas.
Además, tuve que clonar e invertir la matriz de personas al mover elementos hacia abajo porque al agregar la track by item.name
devuelve los elementos en orden, pero si tratas de iterar a través de la matriz, moviendo cada uno hacia abajo, estás impactando potencialmente en el ubicación de otros elementos en la matriz (produciendo además un comportamiento impredecible). Por lo tanto, debemos comenzar desde abajo y trabajar hacia arriba al mover varios elementos hacia abajo.
Aquí hay una solución en la que parece que eliminé cualquier comportamiento impredecible al hacer múltiples selecciones arbitrarias:
EDITAR: Un error que he encontrado es que ocurren cosas raras cuando mueves múltiples elementos seleccionados hacia arriba o hacia abajo, y luego tratas de moverlo en esa dirección una vez más. Cualquier movimiento adicional sin volver a seleccionar produce resultados impredecibles.
EDITAR: El comportamiento impredecible mencionado en la edición anterior se debía a que las funciones veían que, aunque el primer elemento estaba en su posición final, los elementos segundo, tercero, cuarto, etc. no estaban en una posición final, y por lo tanto intentaron muévelos, lo que llevó a un reordenamiento loco de los artículos que ya habían sido empujados hacia arriba o hacia abajo. Para resolver esto, establecí una var que rastrearía la posición del elemento movido previamente. Si se encuentra que el elemento actual está en la posición adyacente, simplemente lo dejará allí y continuará.
Las funciones finales se ven más o menos así:
$scope.moveUp = function () {
var prevIdx = -1;
var person = $scope.persons.concat();
console.log($scope.persons);
for(var i = 0; i < $scope.persons.length; i++) {
var idx = $scope.peoples.indexOf($scope.persons[i])
console.log(idx);
if (idx-1 === prevIdx) {
prevIdx = idx
} else if (idx > 0) {
var itemToMove = $scope.peoples.splice(idx, 1)
console.log(itemToMove[0])
$scope.peoples.splice(idx-1, 0, itemToMove[0]);
}
}
};
(Afortunadamente) Demostración final
EDITAR: Disfruté este problema y quería tener una mejor solución en caso de que hubiera elementos de lista duplicados. Esto fue bastante fácil de resolver al darle a cada objeto de la matriz una clave de identificación única, y luego cambiar la track by item.name
para track by item.id
, y todo funciona como antes.