polymer: 9. arrays

Cómo manipular arrays con polymer

Vincent Van Gogh

archivado en: JavaScript / 7 marzo, 2016 / taller:

Como decía en la entrada anterior de este taller dedicado a los web components y polymer, cuando las propiedades son arrays, el bindeo es un poco más complejo que cuando son primitivas. Ahora veremos cómo hacerlo, pero antes es importante recordar qué los paths en polymer son la indicación donde está algo. Si es una variable, lo que se conoce como un tipo primitivo, con el nombre basta, pero en casos más complejos como los arrays o los objetos hay que indicar el path. Por ejemplo, el path para llegar a los cocos de este objeto:

alimentos: {

verduras: ['lechuga', 'tirabeques'],

frutas: ['cocos', 'kiwis']

}

sería:

alimentos.frutas['cocos']

Como vimos, para mejorar el rendimiento, polymer no lanza toda la ristra de escuchas sobre cada uno de los ítems de los objetos y los arrays, por lo que cuando cambiamos algo en este tipo de elementos hay que avisarle:

— hey, polymer, ten en cuenta que estoy cambiando un array y esta es la «ruta», el path, de lo que quiero cambiar.

Lo primero se consigue mediante una serie de métodos que siempre debemos usar en lugar de los nativos para manipular arrays. Salvo por un detalle, son idénticos a los normales:

  • push(path, item1, [..., itemN]): añade uno o más elementos al final del array.
  • unshift(path, item1, [..., itemN]): añade uno o más elementos al principio.
  • pop(path): elimina y devuelve el último elemento.
  • shift(path): elimina y devuelve el primer elemento.
  • splice(path, index, removeCount, [item1, ..., itemN]): elimina o añade elementos.

Por ejemplo, así añadiríamos una fruta al pulsar un botón:

<dom-module id="foo-component">

<template>

<button on-tap="addFruit">Añadir fruta</button>

</template>

<script>

Polymer({

is: 'foo-component',

properties: {

fruits: {

Type: Array,

value: ['coco', 'cerezas', 'higos']

}

},

addFruit: function() {

this.push('fruits', 'mandarinas');

}

})

</script>

</dom-module>

Observers en arrays

En la entrada dedicada a las propiedades vimos que a la hora de declararlas podemos añadir un observer, esto es, una función que salta cuando se cambia el valor de la propiedad. Y esto marcha de perlas cuando se trata de un valor primitivo o, si es un objeto, cuando especificamos el path, pero para los arrays no va de la misma manera. Es decir, algo así, no funciona.

...

properties: {

fruits: {

Type: Array,

value: ['coco', 'cerezas', 'higos'],

observer: 'observeFruits'

}

},

observeFruits: function() {

/* Ni caso 😛 */

console.log(this.fruits);

},

Lo que se debe hacer, en cambio, es añadir el observer al array de observers indicando el método, al cual se le pasa como parámetro el array observado seguido de .splices. Algo así:

...

observers: ['observeFruits(fruits.splices)'],

observeFruits: function() {

console.log(this.fruits);

},

...

Es un poco farragoso, pero a cambiola función que observa recibe un argumento muy útil, un objeto con dos propiedades-objeto: indexSplices y keySplices.

En indexSplices, cada ítem, tiene estas propiedades:

  • index: la posición donde ha empezado el splice
  • removed: un array con los ítems removidos.
  • addCount: el número de ítems que se han añadido.
  • type: la acción que se ha realizado.
  • object: el array tal y como ha quedado después del cambio.

Por ejemplo:

observeFruits: function(changes) {

if ( !changes ) {

return;

}

changes.indexSplices.forEach(function(item) {

var i = 0;

var len = item.removed.length;

console.log('Los elementos suprimidos son: ');

for (; i<len; i++) {

console.log(item.removed[i]);

}

console.log('y la operación realizada ha sido un ', item.type);

});

}

/* Los elementos suprimidos son:

higos

y la operación realizada ha sido un splice */

Hay que poner un cortafuegos como el indicado en el ejemplo (si !changes, return) para que no casque si intenta aplicar el forEach a undefined, que es el valor que tiene cuando se instancia.

keySplices en teoría funciona de manera similar, pero de momento da bastante la murga y con indexSplices nos vale para todo.

Y ahora que ya sabemos observar arrays en polymer, veamos cómo bindearlos, para lo cual necesito explicar antes una cosa sobre las expresiones.

Expresiones

En angular es posible ejecutar cosas dentro de las expresiones, esto es, en el contenido enmarcado por el par de llaves:

el total es : {{ cantidad * porcentajeIva }}

En polymer, sin embargo, solo podemos hacer dos tipos de operaciones dentro de una expresión: negarla y lanzar una función. Cualquier otra cosa no funcionaría.

Por ejemplo, si tuviéramos estas dos propiedades:

prop1: {

type: Number,

value: 3

},

prop2: {

type: Number,

value: 5

}

NO podríamos hacer algo así en la expresión:

Resultado: {{prop1 + prop2}}

Para que funcione, debemos pasar el resultado por una función- Es lo que en polymeresco se conoce como computed bindings.

Resultado: {{sumProps(prop1, prop2)}}

....
sumProps(value1, value2) {

return value1 + value2;

},

Comprendido esto, volvamos con los arrays.

Bindear arrays

Supongo que lo arreglarán en futuras versiones, porque es muy farragoso, pero el caso es que de momento no podemos referirnos a los ítems de un array por su índice dentro de una expresión. Es decir, algo así no funciona.

<p>Mi fruta favorita es: {{fruits[1]}}</p>

...

En cambio, mediante la notación de puntos, que es un path, sí que podríamos mostrar el ítem del array.

La primera fruta es: {{fruits.0}}

Sin embargo, así  se perdería el bindeo, por lo que debemos emplear una fórmula algo más engorrosa. Una opción sería añadir observers que devolvieran una primitiva, que es la que bindeamos en la vista. Otra es recuperando el valor bindeado mediante una función a la que le pasamos el path del array con un wildcard (*) para indicar que no queremos ninguna clave en concreto y el índice que buscamos.

La primera fruta es: {{getFruit(fruits.*, 0)}}

...

getFruit(arr, index) {

console.log(arr);

},

En el path van tres campos que son base, el array al que estamos apuntando, el path propiamente dicho y los valores.

polymer-arrays-00

Por lo tanto, lo único que tenemos que hacer es devolver el ítem que nos piden en el index.

getFruit(arr, index) {

return arr.base[index];

},

Y de esta manera sí que se bindean los cambios. En fin, es un poco lío y, dada la espesura de la documentación oficial, os recomiendo un polycast de Rob Dobson titulado binding to Arrays en el que queda más claro. En cualquier caso, sospecho que lo harán más sencillo para próximas versiones.

He dejado el ejemplo completo en git.

|| Tags: ,

valoración de los lectores sobre polymer: 9. arrays

  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • 5 sobre 5 (3 votos)

¿Te ha parecido útil o interesante esta entrada?
dormido, valoración 1 nadapensativo, valoración 2 un poco sonrisa, valoración 3 a medias guiño, valoración 4 bastante aplauso, valoración 5 mucho

Tú opinión es muy importante, gracias por compartirla!

2 respuestas a “polymer: 9. arrays

  1. Artículos super interesantes de una tecnología de la que hay muy poca información en castellano. Espero que la serie continue lo máximo posible. Muchas gracias