Action Sheet Ionic – Ejemplos / Examples y más información avanzada

En el capítulo de hoy hablaremos un poco sobre las Action Sheet Ionic Native, u hojas de acción, que encontramos en Ionic y crearemos un tutorial avanzado sobre estas. Es el típico menú que se despliega en el top del stack de vistas en una parte de nuestra pantalla que, por regla general, nos sirve para elegir alguna opciones de configuración de la aplicación. Un controlador bastante interesante que poco a poco va tomando más role y protagonismos con la entrada del uso de Material Design en nuestras apps. Visto esto, comenzamos.

Action Sheet Ionic ejemplos y más información
Imagen recogida de la página oficial de Ionic

Buenas tardes Jefazos, ¿qué tal va pasando la primera? La verdad que espero que bien, por que yo no estoy demasiado «bien». No que esté mal ni nada, es que este tiempo (climatico) me afecta bastante negativamente a la cabeza. Y si a esto le sumamos la enorme carga de trabajo que acumulamos últimamente en mi empresa y las horas de programación adicionales al curro… vamos, para explotar. Pero bueno, ahí vamos…

Basta de presentaciones y ñoñerías y entremos en materia que es lo que nos gusta.

Pero antes de empezar, déjame decirte que he migrado parte de mis webs y apis con los chicos de Raiola Netwworks y estoy encantadísimo con ellos. Te lo cuento por que he mejorado el rendimineto de mis apps y webs más de un 30% en comparación con 1&1 que es donde lo tenía antes. Si estás buscando hosting, te recomiendo que les des una oportunidad. Aquí tienes el enlace. Además te ayudan con lo que necesites. Y ahora si, vamos al lio…

ActionSheetController, ¿Qué es?

Bueno, comenzamos hablando de este controlador por que es el encargado de darnos acceso a todo el componente Action Sheet desde nuestro código TypeStript. Al tratarse de un componente púramente visual, y estar incluido en el core, no será necesaria la instalación de ningún plugin.

En primer lugar, para poder utilizarlo, como es constumbre, tenemos que importarlo en nuestras dependencias como hacemos con todos los controladores. Para ello nos vamos a dirigir a nuestro «app.modules.ts» y dentro de la construcción de nuestro @NgModule insertamos lo que vamos a ver a continuación

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    ...
  ],
  providers: [
    ...
    ActionSheetController, //Esta es la línea importante.
    ...
  ]
})

¿Sencillo verdad? Si eres nuevo, esto te parecerá un poco raro. Pero para que los que ya tenemos un poco de camino recorrido nos resultará familiar.

Con este código ya estamos en disposición de injectar nuestro controlador ActionSheet en cualquier componente de nuestra app, sigamos.

 

¿Qué plataformas soporta?

En la actualidad, a fecha de actualización del artículo, día 28/10/2019, el sistema es soportado por las siguientes plataformas:

  • Android
  • iOS
  • Browser
  • Windows
  • Windows Phone 8

Los ejemplos que vas a ver aquí te van a valer para cualquiera de las plataforemas que hemos visto en la lista.

 

¿Cómo se contruye un Action Sheet Ionic Native?

Bien, vamos a proceder a hacer una construcción simple de este component y explico un poco de que va el tema después sobre esta demo.

Nota: Este ejemplo/example es totalmente funcional. Si lo quieres utilizar, estás en todo tu derecho 🙂 Es más, te serviría para Ionic 2, Ionic 3 y Ionic 4 a fecha de publicación del artículo.

import { ActionSheetController } from 'ionic-angular'

export class MiClase{

 constructor(public miAc: ActionSheetController) {} //Injectamos el controlador en el consstructor

 presentActionSheet() {
   let actionSheet = this.actionSheetCtrl.create({ //Llamamos a la función create para contruir nuestro componente.
     title: 'Modify your album', //El título de nuestro ActionSheet
     //Este array define los botones que van a ir dentro de nuestro contenedor
     buttons: [
       {
         text: 'Destructive',
         role: 'destructive',
         handler: () => {
           console.log('Destructive clicked');
         }
       },
       {
         text: 'Archive',
         handler: () => {
           console.log('Archive clicked');
         }
       },
       {
         text: 'Cancel',
         role: 'cancel',
         handler: () => {
           console.log('Cancel clicked');
         }
       }
     ]
   });

   actionSheet.present(); //Esta es la función que llama al ActionSheet para que sea mostrado.
 }
}

Una cosa más antes de continuar, actualmente los Ionic Action Sheet no son scrollables. Por lo que no deberías agregar muchos botones de acción y siempre probar si todo va cómo quieres que se vea en varias pantallas antes de lanzar nada a producción. De otra manera, podrías encontrar sorpresas ingratas.

Aquí tienes todas las opciones / options y parámentros / parámeters de construcción que se le pueden pasar en el método create:

var options = {
    androidTheme: window.plugins.actionsheet.ANDROID_THEMES.THEME_DEVICE_DEFAULT_LIGHT, // Este es el tema por defecto, revisar las coonstantes y poréis ver más.
    title: 'Este es el title de nuetro action sheet',
    subtitle: 'Este es el subtitulo o la descripción', // Solo soportado en iOS
    buttonLabels: ['Compartir en Facebook', 'Compartir en Twitter'],
    androidEnableCancelButton : true, // por defecto false
    winphoneEnableCancelButton : true, // por defecto false
    addCancelButtonWithLabel: 'Cancelar',
    addDestructiveButtonWithLabel : 'Eliminar esto',
    position: [20, 40], //Solo es para los iPad y hay que pasarle la position X y el position Y  de donde queremos que se muestre.
    destructiveButtonLast: true // Por si quieres mostrar un botón de destrucción :)
};

 

Si por algo defiendo Ionic es por la simpleza que tiene en la elaboración, escirtura y lectura de nuestro código. Cosas así programadas en Java nativo doblan, practicamente, la cantidad de código necesaria para contruirlas.

Como hemos podido ver, solo tenemos que inyectar el controlador del ActioSheet en nuestro contructor y listo, ya lo podemos usar.

La función contruct, nos permite pasarle todos los parametros a nuestro componente para que se contruya «solo». Los componentes que contiene un ActionSheet dentro de su contenedor son todos botones, con sus respectivas reglas y demas…

A parte tiene la posibilidad de incluir en él un «title», «subtitle» y un «icono» para que queda aún más bonito.

 

¿Cómo construyo los botones / buttons?

En primer lugar comentar, como hemos visto en el código, que todos los componentes internos del contenedor son botones. Esta es una regla importante de conocer.

Todos los botones tienen la propiedad «role» aunque nosotros no se la pongamos. De forma predeterminada tomarán el aspecto de la plataforma pero podemos asignarles 2 tipos más:

  • Destructive:  Se situará en la parte superior del componente sin importar el ordern en el que se hayan agregado al array.
  • Cancel: Se pondrán en la parte inferior de nuestro componente como el típico botón de cancelar sin importar el orden en nuestra matriz. Es más, si se intenta salir del ActionSheet sin usar los botones, tocando el fondo de la pantalla, se ejecutará la función que le hayamos bindeado a nuestro botón cancel.
  • Nota: Como has podido ver, lo lógico es tener uno solo de cada uno de los citados anteriormente («cancel» y «destructive») y dejar el resto en el orden que queramos que aparezcan con la apariencia del dispositivo. De no ser así tomará el primero que aparezca en la matriz y será el que utilizará.

Por último comentar que las opciones del componente las podemos inicializar todas en la función «Create()» o asignarlas con sus funciones «set» como por ejemplo: «setTitle()». Y para agregar más botones: «addButton()».

Veamos un ejemplo de la matriz de botones:

buttons: [
  {
    text: 'Destruir AccionSheet',
    role: 'destructive',
    handler: () => {
      console.log('Destruir clicked');
    }
  },
  {
    text: 'Información sobre la aplicación',
    handler: () => {
      console.log('Información clicked');
    }
  },
  {
    text: 'Cancelar accioones',
    role: 'cancel',
    handler: () => {
      console.log('Cancelar clicked');
    }
  }
]

De manera dicional recuerda, a parte de que incurres en buenas prácticas, la traducción / translation de la app siempre tiene que estar presente en todo lo que hagas. Lo digo por las cadenas que hemos visto aquí, siempre tráelas desde una traducción.

Diferencias entre Android e iOS

No existe diferencia en el diseño alguna entre plataformas de manera programática, a excepción de la capa visual y el material design. No tienen diferencia de uso sobre el código. La Action sheet interface select en Ionic es similar, mira:

ActionSheet visto en dispositivo Android ActionSheet visto en dispositivo iOS

 

¿Cómo pongo iconos / icon en los botones de un ActionSheet?

Muchos de los compañeros con los que trabajo, y hablo, me preguntan cosillas de este tipo. Así que vamos a contestarlas en un segundo:

Mirar: Cada uno de los botones que agregamos a nuestra array de botones tiene las siguientes características:

«text» -> (String) -> Es el texto del botón.

«icon» -> (icon) -> Es el icono que va alineado a la izquierda de la caja que contiene el botón. Hablaremos sobre los iconos más adelante, por que si no tendríamos que hacer otro artículo. Aún así os dejo una referencia donde podéis ver un poco mejor como se usan: https://ionicframework.com/docs/api/components/icon/Icon/

«handler» -> (any) -> La función que se ejecutará cuando el botón sea pulsado.

«cssClass» -> (string) -> Si queremos asignar alguna clase adicional al botón para cambiar el aspecto de este. Con esta clase también podrás cambiar el Ionic Action Sheet icon color y los styles de los buttons. A parte, que no se me olvide, tambíen podrás cambiar el Text Color desde aquí.

«role» -> (string) -> Esta es la zona que hemos comentado antes que tiene dos posibilidades, «cancel y desctructive». Si queres conocer como funciona mira un poco más arriba.

 

¿Cómo cierro / close el componente?

Esta parte es muy sencilla de trabajar. Puedes cerrarlo pulsando en el botón al que le hayas asignado el «role» «cancel». También puedes pulsar fuera de la ventana para cerrarlos sí la propiedad «enableBackdropDismiss» esta seteada a «false» (de forma predeterminada es false) o cerrarlo programáticamente cuando queramos. Pero también se puede dar el caso de que queramos cerrarlos desde código. Entonces tendríamos que llamar al método dismiss de la instancia action sheet para que se cerrase el modal en Ionic.

 

¿Se puede hacer Scroll?

Normalmente, los botones de esta opción no suelen ser muchos, pero si tu app lo necesita se puede conseguir que haga Scroll. Cuando la ventan sobrepase un poco más de la mitad de la pantalla (2/3 más o menos) no aumentará más y se pondrá en modo Scrool automáticamente. Es así, tan sencillo que asusta.

 

¿Puedo hacer un ActionSheet Personalizada?

Llegará un punto, que si estás aquí será por que seguramente no has llegado, yo estoy llegando ahora, en el que «todo es posible de hacer». Te explico, de una manera sencilla no se puede personalizar del todo. Quizás si que podrás tocar las CSS del componente pero poco más.

Para ello existe algo que se llama la herencia, que seguramente hayas oido hablar de ello, o sepás perfectamente lo que es. Pero para este caso no lo voy a explicar así que ilustro un poco por encima y ya veremos más adelante en el curso como lo podemos hacer «bien».

Para solucuionar este problema tendrías que extender el AcctionSheetController con una clase propia y a partir de ahí modificar lo que veas necesario. Podríamos poner, por ejemplo, una barra de búsqueda, personalizar los eventos click, long-click, pane, etc… a placer o cambiar directivas del componente desde la misma raiz. Pero como digo, esto daría para un curso completo, así que lo veremos más adelante.

¿Not Working? ¿Not Showing? No problem

Muchos compañeros/conocidos han tenido problemas con este tipo de componentes, pero nada que no se solucione echando un ojo detallado al código y comprobando si la lógica de negocio está correcta. Estamos en una versión bastante avanzada y madura de Ionic. No tiene mucho sentido que algo así pase.

Pero para cuando sucede cada caso es un mundo. Si has tenido alguno de estos problemas mándame un mail y estaré encanto de ayudarte.

 

¿Ionic Action Sheet back button no funciona? Esta es la solución

Es posible, sobre todo en algunas versiones de Android, que cuando pulsamos el botón de regresar no se esconda la ventana de un Action Sheet. Para solucionarlo, basta con que controlemos el tap del back button con nuestro código y que escondamos nosotros de manera explicita el modal.

this.platform.registerBackButtonAction(() => {
    let nav = this.app.getActiveNav();
    if (nav.canGoBack()){ //Can we go back?
        nav.pop();
    }else{
        let actionSheet = this.actionSheetCtrl.create({
        title: 'Realmente desea salir?',
        buttons: [
            {
            text: 'Si, salir',
                handler: () => {
                    this.platform.exitApp(); //Exit from app
                }
            },{
                text: 'Cancelar',
                role: 'cancel',
                handler: () => {
                    console.log('Cancel clicked');
                }
            }
        ]
        });
        actionSheet.present();
    }
});

¿Ves que sencillo es? Pruébalo, es totálmente funcional 🙂

 

Cómo pasar datos / data en un Action Sheet

Ya son varias las preguntas que estoy procurando ir constestando a los usuarios del blog. Pues bien, para poder enviar datos desde un Action Sheet de manera dinámica lo que tenemos que hacer es construir el Action Sheer en si con esta configuración de botones:

let actionSheet = ActionSheet.create();

...

for (var i = 0; i < array.length; i++){
    actionSheet.addButton({
        text: title,
        handler: this.miFuncion.bind(this, i)
    })
}

...
miFuncion(i){
    //Entonces aquí, por ejemplo, extraemos el índice del botón que se ha pulsado
    //array[i] tendría los datos que necesitamos recuperar. Si alguna vez has programado en Android, esto lo entenderás a la primera por que es similar a las listas.
}

 

Cómo montar un ActionSheet desde una directive

Bien, aunque esto es refernte a Angular 1, hay gente que aún me lo pregunta por que tiene proyectos en esta versión del Framework y vamos a proceder a contestar esta questión. La verdad que no es algo que sea complicado, pero si que tiene un poco de miga por que el sitema no está enfocado para ello. Veamos…

angular.module('ionicApp', ['ionic'])

.service('$options', function ($ionicActionSheet) {
  return {
    show: function () {
      console.log('Inténtalo');
      
      
      var buttons = [
        {text: 'Botón 1'},
        {text: 'Botón 2'},
        {text: 'Botón 3'}
      ];
  
    
      $ionicActionSheet.show({
        titleText: 'ActionSheet de ejemplo',
        buttons: buttons,
        destructiveText: 'Eliminar',
        cancelText: 'Cancelar',
        cancel: function() {
          console.log('CANCELADO');
        },
        buttonClicked: function(index) {
          alert('BOTÓN CLICADO '+ index);
          return true;
        },
        destructiveButtonClicked: function() {
          console.log('DESTRUIDO');
          return true;
        }
      });

    }
  }
})

.directive('fOptions', function($options) {

  return {
    restrict: 'E',
    template: '<button class="button button-icon right-buttons icon ion-ios7-more"></button>',
    link: function (scope, element) {

      element.on('click', function () {
        scope.$apply(function(){
          $options.show();
        });
        console.log('Clicckkk');
      });

      element.on('$destroy', function () {
        element.off('click');
        console.log('Yeeee');
      });
    }
  };
});

Al final con el código que vemos estamos creando un servicio y una directiva a parte del $scope y lo lanzamos desde este una vez ya está inicializada la aplicación. Hay que leer en profundidad el código para entenderlo. Y a parte, la contrucción del grupo / group de botones también influye en la construcción del Action Sheet.

 

¿Se puede poner un input en un Action Sheet?

Llevo media hora investigando, mientras escribo la respuesta, de si es posible incluir un input dentro de este componente. Yo, directamente sabía que no se podía, o no era probable, y el resto de comunidad me loa ha confirmado. No se puede de manera natural incluir un input en este componente.

Ahora bien, en desarrollo se puede hacer lo que nos de la gana, con lo que nos de la gana, si sabesmo cómo hacerlo. Siempre podemos extender la funcionalidad del componente en cuestión y hacer uno custom. Es más, seguro que ya hay gente lo que ha hecho. Más adelante en el curso, yo mismo os enseñaré cómo se hace, pero hasta ahora no puedo ayudar más con esta pregunta. Lo siento 🙁

 

¿Disable buttons? O Cómo tener botones desactivados en un Action Sheet

Debido a que el artículo ya se está haciendo un poco largo de más, he decidido que sea un compañero de batalla quien os explique cómo se pueden deshabilitar los botones de un Action Sheet. La verdad que es un poco rudimentario el ejemplo, pero funcional. Aún no hay una capa de abstracción sobre esto, así que toca picar código. Todo vuestro.

 

Regalito – Videotutorial ilustrativo

 

Bueno, pues hasta aquí hemos llegado compañeros, espero que el artículo haya te alla sido de utilidad. Y si así ha sido compártelo con tus compañeros a traves de las redes con los botones que puedes ver por aquí. ¡Te estaré muy agradecido!

Un saludo y hasta la próxima.