Tu primera app con Sencha Touch

El Modelo Más videos

Descripción del tema

Hasta ahora nos hemos concentrado en la parte visual de nuestra aplicación, ya hemos creado la interface principal y también hemos creado un tema completamente personalizado.

En este tutorial vamos a definir el modelo de datos que necesitamos para desplegar los productos en el grid de resultados. Así mismo explicaremos algunos detalles importantes para tener una mejor comprensión de los modelos.

Definición de un modelo

Para los que aún no tienen claro como funciona el patrón MVC, les recomiendo investigar al respecto, en este curso estamos usando este patrón para desarrollar la aplicación. La capa de modelo en Sencha Touch incluye los Stores y Models. En este tema solo nos enfocaremos en el modelo. 

Primeramente vamos a crear el archivo app/model/Product.js donde escribiremos el siguiente código.

Ext.define('Itunes.model.Product', {  //Step 1
    extend: 'Ext.data.Model',         //Step 2

    config: {
        
    }
});
  1. En el primer paso creamos la clase Product, es importante notar que el paquete donde estamos creando esa clase esta en Itunes.model, aquí es donde vamos a crear todos los modelos de nuestra aplicación.
  2. En el segundo paso extendemos de la clase Ext.data.Model, esta clase es la que nos provee todo el funcionamiento necesario para manejar nuestra información de manera sencilla.
En esas pocas líneas de código hemos definido nuestro modelo, por el momento esta completamente vacío, es hora de comenzar a modelar la información que contendrá.

Definición de los campos

Los campos de un modelo son los responsables de almacenar la información, la idea es que cada campo pueda dar alguna descripción sobre el modelo, en este caso los campos para un producto podría ser precio, título, fecha de publicación, etc. El nombre que asignemos a cada campo debe ser los suficientemente descriptivo y debe ser coherente con el modelo que estamos definiendo.

Para nuestra aplicación usaremos los siguientes campos:

Ext.define('Itunes.model.Product', {
    extend: 'Ext.data.Model',

    config: {
        fields  : [          //Step 1
            'artwork',       //Step 2
            'name',
            'artist',
            'albumn',
            'genre',
            'duration',
            'price',
            'releaseDate',
            'preview'
        ]
    }
});
  1. En el paso uno usamos la propiedad fields, esta propiedad nos permite definir los campos que usaremos para este modelo.
  2. En el paso dos definimos un arreglo con el nombre de los campos que usaremos.

Así de sencillo es como definimos un modelo, simplemente extendemos de la clase Model y especificamos los campos que tendrá nuestro modelo. 

Definiendo los mappings

Si dejamos el modelo de esa manera, cuando se creen las instancias de esta clase debemos asignarle cada propiedad con el valor que tendrá, el problema que se nos presenta es que la respuesta del API de Itunes es de la siguiente manera:

GET https://itunes.apple.com/search?term=maroon
{
   "resultCount":50,
   "results": [{
     "wrapperType":"track",
     "kind":"song",
     "artistId":1798556,
     "collectionId":542468867,
     "trackId":542468928,
     "artistName":"Maroon 5",
     "collectionName":"Overexposed (Deluxe Version)",
     "trackName":"One More Night",
     "collectionCensoredName":"Overexposed (Deluxe Version)",
     "trackCensoredName":"One More Night",
     "artistViewUrl":"https://itunes.apple.com/us/artist/maroon-5/id1798556?uo=4",
     "collectionViewUrl":"https://itunes.apple.com/us/album/one-more-night/id542468867?i=542468928&uo=4",
     "trackViewUrl":"https://itunes.apple.com/us/album/one-more-night/id542468867?i=542468928&uo=4",
     "previewUrl":"http://a760.phobos.apple.com/us/r1000/109/Music/37/0f/44/mzi.ucwvxang.aac.p.m4a",

"artworkUrl30":"http://a4.mzstatic.com/us/r30/Music/v4/db/8c/c8/db8cc841-47a0-2845-5116-e1762dbd711e/UMG_cvrart_00602537109692_01_RGB72_1200x1200_12UMGIM26178.30x30-50.jpg",

"artworkUrl60":"http://a1.mzstatic.com/us/r30/Music/v4/db/8c/c8/db8cc841-47a0-2845-5116-e1762dbd711e/UMG_cvrart_00602537109692_01_RGB72_1200x1200_12UMGIM26178.60x60-50.jpg",

"artworkUrl100":"http://a5.mzstatic.com/us/r30/Music/v4/db/8c/c8/db8cc841-47a0-2845-5116-e1762dbd711e/UMG_cvrart_00602537109692_01_RGB72_1200x1200_12UMGIM26178.100x100-75.jpg",
     "collectionPrice":11.99,
     "trackPrice":1.29,
     "releaseDate":"2012-07-17T07:00:00Z",
     "collectionExplicitness":"explicit",
     "trackExplicitness":"notExplicit",
     "discCount":1,
     "discNumber":1,
     "trackCount":16,
     "trackNumber":1,
     "trackTimeMillis":219392,
     "country":"USA",
     "currency":"USD",
     "primaryGenreName":"Pop",
     "radioStationUrl":"https://itunes.apple.com/station/idra.542468928"}
   ]},
   {
       ...
   },
 
   ...
}

Como se puede observar, los nombres de los campos que contiene la respuesta del API de Itunes no coinciden con los que definimos en nuestro modelo. Para solucionar esto tenemos dos opciones, cambiamos los nombres en nuestro modelo o agregamos mappings. En este caso vamos a agregar los mappings a cada campo para que pueda sacar la información del lugar correcto.

Ext.define('Itunes.model.Product', {
    extend: 'Ext.data.Model',

    config: {
        fields  : [
            {name:'artwork',mapping:'artworkUrl100'},
            {name:'name',mapping:'trackName'},
            {name:'artist',mapping:'artistName'},
            {name:'albumn',mapping:'collectionName'},
            {name:'genre',mapping:'primaryGenreName'},
            {name:'duration',mapping:'trackTimeMillis'},
            {name:'price',mapping:'trackPrice'},
            {name:'releaseDate'},
            {name:'preview',mapping:'previewUrl'}
        ]
    }
});

En lugar de definir únicamente el nombre del campo, ahora usamos un objeto de configuración, donde le asignamos un nombre al campo mediante la propiedad name y también definimos el mapping para ese campo. Algo interesante de notar es que el campo releaseDate no le definimos mapping, esto es poque los nombres coinciden y no tendremos problemas.

Asignando el tipo de datos

Por defecto tipo de información que recibirá cada campo será cualquier cosa que venga en la respuesta de API, en algunos casos es conveniente pero esto no siempre es así, en nuestro ejemplo tenemos un campo para la fecha, si queremos desplegar correctamente cada fecha deberíamos definir que el campo es de tipo fecha para que la fecha que viene en formato string se pueda convertir correctamente en un objeto de tipo date.

Ext.define('Itunes.model.Product', {
    extend: 'Ext.data.Model',

    config: {
        fields  : [
            {name:'artwork',mapping:'artworkUrl100'},
            {name:'name',mapping:'trackName'},
            {name:'artist',mapping:'artistName'},
            {name:'albumn',mapping:'collectionName'},
            {name:'genre',mapping:'primaryGenreName'},
            {name:'duration',mapping:'trackTimeMillis'},
            {name:'price',mapping:'trackPrice'},
            {name:'releaseDate',type:'date'},      //<-----
            {name:'preview',mapping:'previewUrl'}
        ]
    }
});

El tipo de dato lo definimos mediante la propiedad type,  en este caso usamos un date, pero podríamos usar un int, string, boolean o cualquier otro que tengamos disponible

En el caso de la fecha que nos envía el API de Itunes, el formato es reconocido automáticamente y se convierte sin problema, pero si la fecha viniera en un formato personalizado por ejemplo 22-11-2005 ó 1/5/2013, entonces tendríamos que usar la propiedad dateFormat para definir el formato que se debe usar al intentar convertir el string a date.

{name:'releaseDate',type:'date',dateFormat:'d-m-Y'},

Con eso la fecha se convertiría correctamente. Para nuestra aplicación no es necesario definir esta propiedad, pero es importante conocerla.

Validaciones

En ocasiones es necesario definir algunas validaciones sobre los campos que tenemos, podemos hacer que un campo sea requerido, definir un máximo o mínimo, inclusive definir una expresión regular para que se valide.

Ext.define('Itunes.model.Product', {
    extend: 'Ext.data.Model',

    config: {
        fields  : [
            //...
        ],

        validations: [  //Step 1
            {type: 'presence',  field: 'name'}, //Step 2
            {type: 'length',    field: 'name',     min: 2},  //Step 3
            {type: 'format',    field: 'preview', matcher: /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&\/=]*)/} //Step 4
        ]
    }
});
  1. Mediante la propiedad validations podemos definir todas las validaciones necesarias, al ser un arreglo recibe objetos de configuración para cada validación, podemos agregar cuantas validaciones necesitemos para cada campo.
  2. En el paso dos definimos que el campo name sea requerido.
  3. En el paso tres hacemos que el campo name tenga como mínimo dos caracteres.
  4. En el paso cuatro definimos una expresión regular para validar que el campo preview sea un URL bien formada.

Los modelos también cuentan con asociacione y algunas otras validaciones, te recomiendo revisar la documentación para conocer mejor esta clase.

Te gustaría recibir más tutoriales como este en tu correo?

Este tutorial pertenece al curso Tu primera app con Sencha Touch, te recomiendo revises el resto de los tutoriales ya que están en secuencia de menor a mayor complejidad.

Si deseas recibir más tutoriales como este en tu correo te recomiendo registrarte al curso, si ya eres miembro solo identifícate y registrate al curso, si no eres miembro te puedes registrar gratuitamente!

Si no gustas registrarte en este momento no es necesario! Aún así puedes recibir los nuevos tutoriales en tu correo! Jamás te enviaremos Spam y puedes cancelar tu suscripción en cualquier momento.

¿Olvidaste tu contraseña?

Se el primero en comentar!

Instructor del curso

Crysfel3

Autor: Crysfel Villa

He desarrollado varias aplicaciones con Sencha Touch, algunas las puedes encontrar en el App Store de apple.

Regístrate a este curso

Este tutorial pertenece al curso Tu primera app con Sencha Touch, revisa todos los tutoriales que tenemos en este mismo curso ya que están en secuencia y van de lo más sencillo a lo más complicado.

Ya que este curso no está finalizado al registrarte podrás recibir en tu correo los nuevos tutoriales de este curso!

Tendrás acceso a descargar los videos, códigos y material adicional.

Podrás resolver los ejercicios incluidos en el curso así como los Quizzes.

Llevarás un registro de tu avance.