Upload
ignacio-munoz-vicente
View
676
Download
2
Embed Size (px)
Citation preview
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_