Desarrollo de aplicaciones multiplataforma 2/2

Post on 22-Jan-2018

675 views 2 download

Transcript of Desarrollo de aplicaciones multiplataforma 2/2

Aplicaciones multiplataforma

Ignacio Muñoz Vicente @imunoz_ 17 y 18 Septiembre 2015

Índice

Jueves

Viernes

- Apps híbridas - Diferencia entre nativas e híbridas - Cómo funciona - Ventajas e inconvenientes - Ejemplos

- Historia - Programar - prueba de los conceptos - Otras herramientas y tecnologías

- Single Page Applications - Frameworks - Herramientas de trabajo - AngularJS - Ionic Framework - Repaso general

Single Page Applications

Modelo tradicional

http://adrianalonso.es/2015/02/single-page-app-vs-multi-page-app/

El modelo SPA

La navegación entre páginas genera una petición al servidor que devuelve el nuevo html a mostrar por el navegador.

El cliente solicita páginas, y el servidor las crea y las devuelve en cada petición.

Sólo se utiliza una página html en todo el proceso, solicitando al servidor únicamente los datos que se mostrarán en esta página.

El cliente solicita la página una vez y al navegar realiza peticiones al servidor únicamente de los datos, siendo el cliente (navegador) el que construye el resultado final.

Ventajas

- La navegación y el renderizado se realiza en el cliente —> Liberación de carga en servidor.

- Se evita solicitar o recargar elementos que no cambian en la navegación (headers, footers, etc.) —> Renderizado de interfaz de usuario más rápido.

- Las llamadas al servidor se hacen sólo de los datos que se necesitan. —> A través de servicios web y peticiones asíncronas.

- El cacheo y almacenamiento de datos temporales se realiza en el cliente. —> Liberación de mantener sesiones en servidor.

- División total del front-end y el back-end. —> El front-end podemos usarlo tanto para web como en app híbrida

- Parte de la lógica de programación pasa del servidor al cliente. —> Liberación de procesamiento en servidor.

Single Page Applications

Inconvenientes

- Carga inicial puede ser mayor —> Necesidad de obtener todos los elementos de la interfaz para mostrarlos posteriormente.

- Totalmente basado en Javascript. Si no está habilitado en el navegador, no funcionará. —> Para Apps híbridas esto no afecta.

- Parte de la lógica de programación pasa del servidor al cliente. —> Hay que tener cuidado de no pasar partes críticas de seguridad.

Single Page Applications

Frameworks

Frameworks a patadas…

Frameworks

¿Cuál es mejor?

Depende

Frameworks

Cuestión de modas…

Frameworks

Google Trends

Frameworks

¿Por qué elegir sólo uno?

+MVW Framework

Model View

Whatever Arquitectura

=Maquetación y diseño

Herramientas de trabajo

npm gruntbower yeomanGestor de paquetes

Gestor de dependencias

Automatizador de tareas

Generador de proyectos

Herramientas de trabajo

¡Manos a la obra!

Instalar tecnologías necesarias $ npm install -g grunt-cli bower yo generator-karma generator-angular

Crear y acceder a carpeta de la nueva app $ mkdir demo && cd demo

Crear aplicación angular con yeoman $ yo angular demo

Herramientas de trabajo

app/WebApp generada con AngularJS como framework. Lo veremos luego

bower_components/ Dependencias de la aplicación obtenidas con BOWER

node_modules/Paquetes necesarios para la aplicación obtenidos con NPM

Herramientas de trabajo

bower.json Archivo que contiene las dependencias de la aplicación

{ "name": "demo", "version": "0.0.0", "dependencies": { "angular": "^1.3.0", "angular-animate": "^1.3.0", "angular-cookies": "^1.3.0", "angular-resource": "^1.3.0", "angular-route": "^1.3.0", "angular-sanitize": "^1.3.0", "angular-touch": "^1.3.0" }, "devDependencies": { "angular-mocks": "^1.3.0" }, "appPath": "app", "moduleName": "demoApp" }

Se instalan mediante $ bower install

Herramientas de trabajo

package.jsonArchivo que contiene los paquetes necesarios para el proyecto

{ "name": "demo", "version": "0.0.0", "dependencies": {}, "repository": {}, "devDependencies": { "grunt": "^0.4.5", "grunt-autoprefixer": "^2.0.0", … "load-grunt-tasks": "^3.1.0", "time-grunt": "^1.0.0" }, "engines": { "node": ">=0.10.0" }, "scripts": { "test": "grunt test" } }

Se instalan mediante $ npm install

Herramientas de trabajo

package.jsonArchivo que contiene los paquetes necesarios para el proyecto

{ "name": "demo", "version": "0.0.0", "dependencies": {}, "repository": {}, "devDependencies": { "grunt": "^0.4.5", "grunt-autoprefixer": "^2.0.0", … "load-grunt-tasks": "^3.1.0", "time-grunt": "^1.0.0" }, "engines": { "node": ">=0.10.0" }, "scripts": { "test": "grunt test" } }

Se instalan mediante $ npm install

• version Coincidir versión exacta • >version Debe ser mayor que la versión • >=version Mayor o igual • <version Menor • <=version Menor o igual • ~version Aproximadamente igual a la versión • ^version Compatible con la versión • 1.2.x Cualquier versión1.2.0, 1.2.1, etc., pero no 1.3.0 • http://... Versión de la URL ofrecida • * Cualquier versión • "" Cualquier versión también • version1 - version2 Igual que >=version1 <=version2 • range1 || range2 Condicional • git... Versión del repo git ofrecido • user/repoVersión del repo GitHub ofrecido • tag Una versión especifica tagged / etiquetada en git • path/path/path Ruta local

Herramientas de trabajo

Gruntfile.jsArchivo de automatización de tareas

Revisión sobre fichero

Se ejecuta con $ grunt <TASK> <PARAMS>

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

Toda App es un módulo

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

A su vez una App puede dividirse en varios módulos, y utilizar módulos externos o de terceros

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

Cada módulo puede configurarse de forma individual

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

La navegación en la App se gestiona a través de rutas que enlazan vista y controlador

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

La vista es el código HTML que se muestra

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

En el controlador se encuentra la lógica de la aplicación

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

El scope permite la comunicación entre vista y controlador

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

Las directivas permiten extender el código HTML

AngularJS

Estructuraroot / app module

module

config

routes

view controller

directives services

scope

Los servicios permiten organizar y compartir código y funcionalidades en distintas partes de la aplicación

AngularJS

Aplicación angular.module('demoApp', [ 'ngAnimate', 'ngCookies', 'ngResource', 'ngRoute', 'ngSanitize', 'ngTouch'

]) .config(function ($routeProvider) { $routeProvider .when('/', { templateUrl: 'views/main.html', controller: 'MainCtrl' }) .when('/about', { templateUrl: 'views/about.html', controller: 'AboutCtrl' }) .otherwise({ redirectTo: '/' }); });

app/scripts/app.js

AngularJS

Aplicación angular.module('demoApp', [ 'ngAnimate', 'ngCookies', 'ngResource', 'ngRoute', 'ngSanitize', ‘ngTouch’ // Aquí se añaden los módulos externos necesarios

]) .config([‘$routeProvider’, function ($routeProvider) { $routeProvider .when('/', { templateUrl: 'views/main.html', controller: 'MainCtrl' }) .when('/about', { templateUrl: 'views/about.html', controller: 'AboutCtrl' })

// Se pueden ir añadiendo tantos “enrutamientos” como se desee .otherwise({ redirectTo: '/' }); }]);

app/scripts/app.js

AngularJS

Controllers

angular.module(‘demoApp’).controller(‘MainCtrl’, function ($scope) { $scope.awesomeThings = [

'HTML5 Boilerplate', 'AngularJS', 'Karma'

]; });

app/scripts/controllers/main.js

AngularJS

Controllers

angular.module(‘demoApp’).controller(‘MainCtrl’, [‘$scope’, function ($scope) { $scope.awesomeThings = [

'HTML5 Boilerplate', 'AngularJS', 'Karma'

];

// Código Javascript aquí. Lógica de presentación

$scope.miFunction = function() { // También puede haber funciones invocadas desde la vista

}

$scope.on(‘destroy’, function() { // Código que se ejecuta al destruirse el controlador

}); }]);

app/scripts/controllers/main.js

AngularJS

Views

<body ng-app="demoApp">

<div class="header"> …

<ul class="nav navbar-nav"> <li class="active"><a href="#/">Home</a></li> <li><a ng-href="#/about">About</a></li> <li><a ng-href="#/">Contact</a></li> </ul>

… </div>

<div class="container"> <div ng-view=""></div> </div>

<div class="footer"> … </div>

app/index.html

AngularJS

Views

<body ng-app="demoApp">

<div class="header"> …

<ul class="nav navbar-nav"> <li class="active"><a href="#/">Home</a></li> <li><a ng-href="#/about">About</a></li> <li><a ng-href="#/">Contact</a></li> </ul>

… </div>

<div class="container"> <div ng-view=""></div> </div>

<div class="footer"> … </div>

angular.module(‘demoApp’)

Rutas con # (por defecto)

Aquí se cargarán el resto de vistas ‘parciales’ al navegar por la app

app/index.html

AngularJS

Expressions

{{ expression }}

<p>{{expression}}</p>

<p ng-bind=“expression”></p>

expression = JavaScript codeExample: <p>{{ 5 + 5}}</p>

<p ng-bind=“myScopedVariable”></p>

AngularJS

Expressions

{{ expression }}

<p>{{expression}}</p>

<p ng-bind=“expression”></p>

expression = JavaScript codeExample: <p>{{ 5 + 5}}</p>

<p ng-bind=“myScopedVariable”></p>

Utilizar ngCloak

AngularJS

Data binding

http://www.dotnet-tricks.com/Content/images/angularjs/two-waybinding.pnghttp://devgirl.org/wp-content/uploads/2013/03/concepts-controller.png

AngularJS

Data binding

¡Manos a la obra!

• Crear nuevo controlador y vista • Añadirlos en el route de la app • Compartir scope y valores entre controlador y vista • Invocar funciones del controlador desde la vista

AngularJS

http://image.slidesharecdn.com/performance-and-production-tips-150113091928-conversion-gate02/95/angularjs-performance-production-tips-27-638.jpg

Ciclo de digest

AngularJS

Directivesangular.module('app').directive('hola', function() {     return function(scope, element, attrs) {       element.text(“hola “ + scope.name + “ “ + attrs.message);

    };   });

<span hello message=“how are you”></span>

AngularJS

Directivesangular.module('app').directive('hola', function() {     return function(scope, element, attrs) {       element.text(“hola “ + scope.name + “ “ + attrs.message);

    };   });

<span hello message=“how are you”></span>

Además de devolver una función sencilla se pueden devolver también: - link: function - templateUrl: string url - template: string html - replace: boolean - restrict: char (A, C, E, M)

Attribute, class, element, comment - scope: Object - compile: function

Directivas de AngularJS más importantes: - ngRepeat - ngShow - ngSwitch - ngIf

AngularJS

Filters

{{ expression [ | filter_name[:parameter_value] … ] }}

Ejemplos:

<li data-ng-repeat=“persona in personas | orderBy:’nombre’ “></li>

<span>{{nombre | uppercase}}</span>

Filtros de AngularJS más importantes: - number - currency - lowercase - uppercase

- json - orderBy - filter

AngularJS

Filters angular.module('app').filter('mandatoryLabel', function() {     return function(input) {       return input + ‘*’;

    };   });

<span ng-bind=‘“password” | mandatoryLabel’></span>

AngularJS

Filters angular.module('app').filter('mandatoryLabel', function() {     return function(input) {       return input + ‘*’;

    };   });

<span ng-bind=‘“password” | mandatoryLabel’></span>

angular.module('app').filter('higherThan', function() {     return function(items, minValue) {       if (!minValue) return items;

return items.filter(function(element) { return element > minValue;

}     };

  });

<span ng-repeat=‘numberArray| higherThan:5’></span>

AngularJS

Services

app.factory(‘profile’, function() {      return {           “name”: “Anonymous”,           “login”: function() { … },           “logout”: function() { … }      } }

app.service(‘profile’, function() {      this.name = “Anonymous”;      this.login = function() { … };      this.logout = function() { … }; }

app.controller(…., function($scope, registration) {      $scope.title = registration.title; });

app.config(function($provide) {      $provide.provider(‘registration’, function() {           var type;           return {                setType: function(value) { type = value; },                $get: function() {                     return {                          title: ‘Service from Provider: ‘ + type                     }                }           };      }); });

app.config(function(registrationProvider) {      registrationProvider.setType(‘Angular’); });

Factory Service ProviderLa forma más sencilla.

Devuelve una simple API con métodosParecido a factory pero devuelve una

clase completa (objetos deben ser instanciados)

Es como un factory “configurable”. Es el tipo más completo y a la vez complejo.

AngularJS

$http $http( { method: ‘GET’, url: ‘/unaURLCualquiera’, params: objetoParams, data: objetoOString, headers: objetoHeaders, cache: true, timeout: 3000

}) .success(function(data, status, headers, config) {

// Ejecutar aquí el código cuando la petición se ha resuelto }) .error(function(data, status, headers, config) {

// Ejecutar aquí el código cuando la petición ha fallado });

AngularJS

$http $http( { method: ‘GET’, url: ‘/unaURLCualquiera’, params: objetoParams, data: objetoOString, headers: objetoHeaders, cache: true, timeout: 3000

}) .success(function(data, status, headers, config) {

// Ejecutar aquí el código cuando la petición se ha resuelto }) .error(function(data, status, headers, config) {

// Ejecutar aquí el código cuando la petición ha fallado });

Métodos rápidos: $http.get - $http.post - $http.put - $http.head - $http.delete - $http.json

Se puede sobreescribir la configuración por defecto mediante $httpProvider en la configuración de la aplicación o módulo: $httpProvider.defaults.headers.XXXX = YYYY;

AngularJS

Directives, services, filters

¡Manos a la obra!

• Crear un servicio que devuelva un listado de datos (JSONArray) • Utilizar ngRepeat para mostrar los resultados en la vista • Filtrar los resultados con un filtro propio • Sustituir el servicio por una petición a

http://jsonplaceholder.typicode.com/

Ionic Framework

Prototipar, maquetar y diseñar aplicaciones web de forma sencilla y rápida

Ionic Framework

Prototipar, maquetar y diseñar aplicaciones web de forma sencilla y rápida

¡Manos a la obra!

Dos opciones:

- Nuevo proyecto: $ yo ionic demo

- Proyecto existente: $ bower install ionic —save $ grunt wiredep

AngularJS

Buenas prácticas

• html5mode(true) —> URLs bonitas + SEO

• Directivas siempre como atributos —> soporte navegadores

• No modificar NUNCA el DOM en el controller —> hacerlo en la directiva (link)

• Evitar llamar a funciones del $scope en ng-repeat —> Demasiadas llamadas

• Utilizar ngIF en vez de ngShow cuando se pueda —> no modifica el DOM

• Usar one-time bindings (con ::) —> {{::miScopedVariable}}

• Utilizar siempre promesas —> Olvidarnos de los callbacks

• Utilizar $digest en vez de $apply —> $apply llama al digest desde el rootScope

• No utilizar funciones en los bindings —> son invocadas en cada digest

AngularJS

One more thing…

miFunctionPromesa() .then(miOtraFuncion) .then(miSegundaOtraFuncion) .then(miAunOtraFuncion) .catch(miFuncionParaTratarElError) .finally(miFuncionQueSeEjecutaSiempre);

PROMESAS

AngularJS

One more thing… PROMESAS

  function getData() {        var defer = $q.defer();        executeAsynchronousMethod({               success: function(data) {                          defer.resolve(data);               },               error: function(error) {                          defer.reject(error);               }         })         return _deferred.promise;   } 

Crear una promesaMetodos del objeto defer:

- resolve (value) - reject (reason) - notify (value)

Combinar promesas independientes:

- $q.all ([promesa1, promesa2]).then(…);

Encapsular objeto o función en promesa:

- $q.when (value)

AngularJS

Ignacio Muñoz Vicente@imunoz_