Chi sono
Davide Michel [email protected]
Programmatore PHP Senior, Drupal Senior e DBA MySQLSviluppatore Web AngularJS, MongoDB (da poco) e NodeJS
Chi sono
Davide Michel [email protected]
Programmatore PHP Senior, Drupal Senior e DBA MySQLSviluppatore Web AngularJS, MongoDB (da poco) e NodeJSSviluppatore Mobile su piattaforma HTML/CSS/JS
Drupal: Services
Si installa nel solito modoSi deve creare quello che si chiama Rest point
Maggiore diversificazione delle risorse
Drupal: Services
Si installa nel solito modoSi deve creare quello che si chiama Rest point
Maggiore diversificazione delle risorse All'interno della configurazione di services si possono dare i
permessi di accesso per i singoli servizi
Drupal: Services
Si installa nel solito modoSi deve creare quello che si chiama Rest point
Maggiore diversificazione delle risorse All'interno della configurazione di services si possono dare i permessi
di accesso per i singoli servizi Attenzione: i permessi per accedere alla funzionalità del servizio
non sono i permessi di accesso di Drupal. Vanno configurati anche questi
Altrimenti si avranno degli accessi negati senza capire il perché.
Drupal: Services
Per le applicazioni mobili ci servono le chiamate che ritornino del JSON Perché è la soluzioni più pratica.
Drupal: Services
Per le applicazioni mobili ci servono le chiamate che ritornino del JSON Perché è la soluzioni più pratica.
Drupal può rispondere in 3 modi diversi
Drupal: Services
Per le applicazioni mobili ci servono le chiamate che ritornino del JSON Perché è la soluzioni più pratica.
Drupal può rispondere in 3 modi diversiCreiamo la nostra funzione che risponde in JSON
Drupal: Services
Per le applicazioni mobili ci servono le chiamate che ritornino del JSON Perché è la soluzioni più pratica.
Drupal può rispondere in 3 modi diversiCreiamo la nostra funzione che risponde in JSONUtilizziamo views_datasource che risponde in JSON
Drupal: Services
Per le applicazioni mobili ci servono le chiamate che ritornino del JSON Perché è la soluzioni più pratica.
Drupal può rispondere in 3 modi diversiCreiamo la nostra funzione che risponde in JSONUtilizziamo views_datasource che risponde in JSONUtilizziamo Services che consente i CRUD
Drupal: Services
Per le applicazioni mobili ci servono le chiamate che ritornino del JSON Perché è la soluzioni più pratica.
Drupal può rispondere in 3 modi diversiCreiamo la nostra funzione che risponde in JSONUtilizziamo views_datasource che risponde in JSONUtilizziamo Services che consente i CRUD
In Drupal Services i nodi si possono creare chiamando direttamente il servizio /node
Drupal: Services
Per le applicazioni mobili ci servono le chiamate che ritornino del JSON Perché è la soluzioni più pratica.
Drupal può rispondere in 3 modi diversiCreiamo la nostra funzione che risponde in JSONUtilizziamo views_datasource che risponde in JSONUtilizziamo Services che consente i CRUD
In Drupal Services i nodi si possono creare chiamando direttamente il servizio /nodeLa struttura deve essere come se lo stessi creando via PHP.
Title, Type, Body sono valori normali (nessuno nota l'errore?)Un FIELD è invece nella struttura: { 'und' : [ { value: ILVALORE } ]}
che corrisponde a [LANGUAGE_NONE][0][value]
Drupal: Services
Attenzione nello sviluppo nella fase di debug:Access-Control-Allow-Origin(https://github.com/systemseed/services_accept_origin)
Plugin per Chrome:“Allow-Control-Allow-Origin”
Questo problema c'è solo sui browser perché sugli smartphone l'accessoavviene da file:// e non http://
Consiglio:Testare su un device fisico è sempre meglio. Si hanno le vere risposte delle performance e si può fare il debug
dell'html tramite chrome://inspect
AngularJS
E' un MVCO meglio un MVVM perché c'è il doppio bindigSviluppato da GooglePermette di spostare la logica di funzionamento di un framework direttamente sul frontend
AngularJS
E' un MVCO meglio un MVVM perché c'è il doppio bindigSviluppato da GooglePermette di spostare la logica di funzionamento di un framework direttamente sul frontendPensato per creare SAP: Singe Application Page
AngularJS
E' un MVCO meglio un MVVM perché c'è il doppio bindigSviluppato da GooglePermette di spostare la logica di funzionamento di un framework direttamente sul frontendPensato per creare SAP: Singe Application PageMa lo si può usare in tanti modi
IonicFramework
All'inizio c'erano le applicazioni che venivano create con il linguaggio dello smartphone
IonicFramework
All'inizio c'erano le applicazioni che venivano create con il linguaggio dello smartphonePoi si è pensato di utilizzare il web per creare delle piccole pagine a modo di applicazione ed è stato inventato jQueryMobile
IonicFramework
All'inizio c'erano le applicazioni che venivano create con il linguaggio dello smartphonePoi si è pensato di utilizzare il web per creare delle piccole pagine a modo di applicazione ed è stato inventato jQueryMobilePoi c'è stato Phonegap (diventato poi cordova, ma rimasto anche Phonegap) che ha permesso di creare delle specie di applicazioni native che sfruttano il browser
IonicFramework
All'inizio c'erano le applicazioni che venivano create con il linguaggio dello smartphonePoi si è pensato di utilizzare il web per creare delle piccole pagine a modo di applicazione ed è stato inventato jQueryMobilePoi c'è stato Phonegap (diventato poi cordova, ma rimasto anche Phonegap) che ha permesso di creare delle specie di applicazioni native che sfruttano il browserPhonegap/Cordova fornisce solo l'accesso alla risorsa dello smartphone all'interno del browser
TastieraVibrazioneFotocameraFilesystemAltro...
IonicFramework
JqueryMobile ha però il concetto di unica pagina dove tutto deve essere visualizzato e poi nascosto
IonicFramework
JqueryMobile ha pero' il concetto di unica pagina dove tutto deve essere visualizzato e poi nascostoAngular ha il concetto di “vista” che può essere riempita a seconda di quello che si vuole visualizzare
IonicFramework
JqueryMobile ha pero' il concetto di unica pagina dove tutto deve essere visualizzato e poi nascostoAngular ha il concetto di “vista” che puo' essere riempita a secondo di quello che si vuole visualizzare Sullo smartphone (meno memoria, meno potenza di calcolo) è molto meglio visualizzare poco alla volta
IonicFramework
JqueryMobile ha pero' il concetto di unica pagina dove tutto deve essere visualizzato e poi nascostoAngular ha il concetto di “vista” che puo' essere riempita a secondo di quello che si vuole visualizzare Sullo smartphone (meno memoria, meno potenza di calcolo) è molto meglio visualizzare poco alla volta
Quindi come unire mobile, user interface e applicazioni native ?
IonicFramework
IonicFramework prende Cordova e lo unisce ad Angular ampliandoli
Accesso al dispositivo (cordova)
IonicFramework
IonicFramework prende Cordova e lo unisce ad Angular ampliandoli
Accesso al dispositivo (cordova)Gestione della visualizzazione, del reperimento dei dati (angularjs)
IonicFramework
IonicFramework prende Cordova e lo unisce ad Angular ampliandoli
Accesso al dispositivo (cordova)Gestione della visualizzazione, del reperimento dei dati (angularjs)Attività normali dello smartphone rese disponibili
IonicFramework
Via JS
Slide menuTabSwipeRouting per le pagine interneFinestre modaliFinestre di loading (spinner)
IonicFramework
Come fare le chiamate con Ionic, o meglio via AngularJS:
3 alternative praticabili$http$resourceRestangular
Sono messe in ordine di “livello di programmazione”. Dal più basso al più alto.
IonicFramework
Per questo talk ho usato Restangular, anche se ci sono cose che non mi piacciono:
Il risultato della chiamata viene restituito come oggettoRestangularMa quello che abbiamo richiesto è messo allo stesso livello delle funzioni native.Quindi se riceviamo un array di informazioni non possiamo utilizzare angular.forEach() perché andremmo a prendere anche le funzioni native.
IonicFramework
Per questo talk ho usato Restangular, anche se ci sono cose che non mi piacciono:
Il risultato della chiamata viene restituito come oggetto RestangularMa quello che abbiamo richiesto è messo allo stesso livello delle funzioni native.Quindi se riceviamo un array di informazioni non possiamo utilizzare angular.forEach() perché andremmo a prendere anche le funzioni native.
Per usarlo con drupal è necessario modificarne il funzionamento (tramite apposita funzione addResponseInterceptor, nessuna modifica al codice di Restangular) perché Services ritorna una serie di oggetti, mentre Restangular vuole un elemento solo oppure un array.
IonicFramework
Per questo talk ho usato Restangular, anche se ci sono cose che non mi piacciono:
Il risultato della chiamata viene restituito come oggetto RestangularMa quello che abbiamo richiesto è messo allo stesso livello delle funzioni native.Quindi se riceviamo un array di informazioni non possiamo utilizzare angular.forEach() perché andremmo a prendere anche le funzioni native.
Per usarlo con drupal è necessario modificarne il funzionamento (tramite apposita funzione addResponseInterceptor, nessuna modifica al codice di Restangular) perché Services ritorna una serie di oggetti, mentre Restangular vuole un elemento solo oppure un array.
Per un altro progetto ho usato $http. Meno funzioni evolute, ma più usabile
IonicFramework
Vediamo come IonicFramework gestisce le varie “view”.
Prima di tutto il file principale: INDEX.HTML
IonicFramework<!DOCTYPE html><html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width"> <title>"Utrend"</title>
<!-- build:css styles/vendor.css --> <!-- <link rel="stylesheet" href="vendor/some.contrib.css"> --> <!-- bower:css --> <link rel="stylesheet" href="lib/ionic/release/css/ionic.css" /> <!-- endbower --> <!-- endbuild -->
<!-- build:css({.tmp,app}) styles/main.css --> <link rel="stylesheet" href="styles/main.css"> <!-- endbuild --> </head>
<body ng-app="Utrend"> <ion-nav-view></ion-nav-view>
<!-- build:js scripts/vendor.js --> <!-- <script src="vendor/someContribJs.js"></script> --> <!-- bower:js --> <script src="lib/angular/angular.js"></script> <script src="lib/angular-animate/angular-animate.js"></script> <script src="lib/angular-sanitize/angular-sanitize.js"></script> <script src="lib/angular-ui-router/release/angular-ui-router.js"></script> <script src="lib/collide/collide.js"></script> <script src="lib/ionic/release/js/ionic.js"></script> <script src="lib/ionic/release/js/ionic-angular.js"></script> <!-- endbower --> <!-- endbuild -->
IonicFramework <!-- cordova script (this will be a 404 during development) --> <script src="cordova.js"></script>
<!-- build:js scripts/scripts.js --> <script src="scripts/common/angular-cookie.min.js"></script> <script src="scripts/common/underscore-min.js"></script> <script src="scripts/common/restangular.min.js"></script>
<script src="scripts/config.js"></script> <script src="scripts/app.js"></script> <script src="scripts/controllers.js"></script>
<script src="scripts/common/restfulServices.js"></script> <script src="scripts/common/sharedService.js"></script> <script src="scripts/user/loginCtrl.js"></script> <script src="lib/sweetalert/lib/sweet-alert.min.js"></script> <link rel="stylesheet" href="lib/sweetalert/lib/sweet-alert.css"> <script src="scripts/posts/picture.js"></script> <script src="scripts/posts/singlePostCtrl.js"></script> <script src="scripts/homeCtrl.js"></script> <!-- endbuild --></body></html>
L'unico motivo per modificare questo file è per inserire i vari SCRIPT dei nostri controller
IonicFramework
Ed il file che gestisce le view: app.js
'use strict';// Ionic Starter App, v0.9.20
// angular.module is a global place for creating, registering and retrieving Angular modules// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)// the 2nd parameter is an array of 'requires'angular.module('Utrend', ['ionic', 'config', 'Utrend.controllers','restangular','ipCookie'])
.run(function($ionicPlatform) { $ionicPlatform.ready(function() { // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard // for form inputs) if(window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); } if(window.StatusBar) { // org.apache.cordova.statusbar required StatusBar.styleDefault(); } });})
IonicFramework
Ed il file che gestisce le view: app.js
.config(function($stateProvider, $urlRouterProvider,$compileProvider,RestangularProvider) { $stateProvider
.state('app', { url: '/app', abstract: true, templateUrl: 'templates/menu.html', controller: 'AppCtrl' }) .state('app.home', { url: '/home', views: { 'menuContent' :{ templateUrl: 'templates/home.html', controller : 'homeCtrl' } } })
.state('app.login', { url: '/login', controller: 'loginCtrl' }) })
IonicFramework
Ed il file che gestisce le view: app.js
.state('app.browse', { url: '/browse', views: { 'menuContent' :{ templateUrl: 'templates/browse.html', controller: 'singlePostCtrl' } } }) .state('app.getPicture', { url: '/getpicture', views: { 'menuContent' :{ templateUrl: 'templates/getPicture.html', controller: 'pictureCtrl' } } });
IonicFramework
Ed il file che gestisce le view: app.js
// if none of the above states are matched, use this as the fallback $urlRouterProvider.otherwise('/app/home'); $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/); RestangularProvider.setBaseUrl('http://MYDOMAIN/'); RestangularProvider.setResponseExtractor(function(response) { var newResponse = response; newResponse.originalElement = angular.copy(response); return newResponse; });});
Drupal Service + IonicFramework
Per collegarci a Drupal abbiamo detto che utilizzeremo ServicesMa dobbiamo prestare attenzione ad una cosa molto importante: il token CSRF
Drupal Service + IonicFramework
Per collegarci a Drupal abbiamo detto che utilizzeremo ServicesMa dobbiamo prestare attenzione ad una cosa molto importante: Il token CSRFE' stato aggiunto dalla versione 3.5 del modulo services
Drupal Service + IonicFramework
Per collegarci a Drupal abbiamo detto che utilizzeremo ServicesMa dobbiamo prestare attenzione ad una cosa molto importante: Il token CSRFE' stato aggiunto dalla versione 3.5 del modulo servicesLega a doppio mandato la sessione attuale con quella registrata sul serverPer fare qualsiasi operazione che non sia un GET è richiesto questo TOKEN negli header della richiesta
Drupal Service + IonicFramework
Per collegarci a Drupal abbiamo detto che utilizzeremo ServicesMa dobbiamo prestare attenzione ad una cosa molto importante: Il token CSRFE' stato aggiunto dalla versione 3.5 del modulo servicesLega a doppio mandato la sessione attuale con quella registrata sul serverPer fare qualsiasi operazione che non sia un GET è richiesto questo TOKEN negli header della richiestaPer rendere il codice scritto più gestibile e leggibile è consigliabile creare un service di angular che gestisca per noi le connessioni
Drupal Service + IonicFramework
(function () {
angular.module('MyM').service('restfulService',['ipCookie','Restangular','$q',restfulService]);
var tokenVar = '';
function restfulService(ipCookie,Restangular,$q) {//Qui le chiamate REST
return { //Setta la directory di partenza del service rest. In questo modo non devo sempre definirlo restfulBase : function() { return Restangular.oneUrl('rest','http://MioDominio/rest'); }, }
})();
Drupal Service + IonicFramework
Prendiamo il token
getToken : function(reset) { if (tokenVar != '' && !reset) { var deferred = $q.defer(); deferred.resolve(tokenVar); return deferred.promise } return Restangular.oneUrl('services/session/token','http://MIODOMINIO/services/session/token').get().then(function (token) { tokenVar = token; return token; });},
Notate come non abbia utilizzato restfulBase ma solamente per unaquestione di demo
Drupal Service + IonicFramework
E' facile creare una app che permetta di gestire gli utenti collegati e quelli non collegati (anonimi)
Drupal Service + IonicFramework
E' facile creare una app che permetta di gestire gli utenti collegati e quelli non collegati (anonimi)
Per farlo utilizzeremo AngularJS e il suo ng-if modificando il file di template del menù slide
Drupal Service + IonicFramework<ion-side-menus>
<ion-pane ion-side-menu-content drag-content="false"> <ion-nav-bar class="bar-positive"> <!--<ion-nav-back-button class="button-clear"><i class="icon ion-ios7-arrow-back"></i> Back</ion-nav-back-button>--> </ion-nav-bar> <ion-nav-view name="menuContent" animation="slide-left-right"></ion-nav-view> </ion-pane>
<ion-side-menu side="left"> <header class="bar bar-header bar-stable"> <h1 class="title">Left</h1> </header> <ion-content class="has-header"> <ion-list ng-if="user.uid == 0"> <ion-item nav-clear menu-close ng-controller="loginCtrl" ng-click="login()"> Login </ion-item> </ion-list>
Drupal Service + IonicFramework <ion-list ng-if="user.uid > 0">
<ion-item nav-clear menu-close > Hi, {{user.name}} </ion-item> <ion-item nav-clear menu-close > MyPage </ion-item> <ion-item nav-clear menu-close href="#/app/getpicture"> upload photo </ion-item> <ion-item nav-clear menu-close href="#/app/browse"> Browse </ion-item>
<ion-item nav-clear menu-close href="#/app/search"> Search </ion-item>
<ion-item nav-clear menu-close ng-controller="loginCtrl" ng-click="logout()"> Logout </ion-item>
</ion-list> </ion-content> </ion-side-menu></ion-side-menus>
Drupal Service + IonicFrameworkVediamo il controller per il login (notate cosa usa)
/** * Created by ziobudda on 05/11/14. */
(function () { angular.module('Utrend').controller('loginCtrl',['$scope','$ionicModal','$state','sharedService','restfulService','$rootScope', loginCtrl]);
function loginCtrl($scope, $ionicModal,$state,sharedService,restfulService,$rootScope) { $scope.error_message = '';
sharedService.getToken();
// Form data for the login modal $scope.loginData = {};
// Create the login modal that we will use later $ionicModal.fromTemplateUrl('templates/login.html', { scope: $scope }).then(function(modal) { $scope.modal = modal; });
// Triggered in the login modal to close it $scope.closeLogin = function() { $scope.modal.hide(); },
Drupal Service + IonicFramework
// Open the login modal $scope.login = function() { $scope.modal.show(); };
// Perform the login action when the user submits the login form $scope.doLogin = function() { console.log('Doing login22', $scope.loginData);
restfulService.login($scope.loginData) .then(function(result) { $rootScope.$broadcast("login",{user: result.user}); restfulService.getToken(true).then(function(result) { $scope.closeLogin(); swal({title: "Login OK", text: "Now you are a loggedin user!", type: "success"}); $state.go('app.browse') })
}, function (result) { $scope.error_message = result.data[0];
}); }
Drupal Service + IonicFramework
$scope.logout = function () { restfulService.logout() .then(function(result) { sharedService.user = {}; sharedService.user.uid = 0; swal({title: "Logout OK", text: "Now you are a logged out user!", type: "success"}); $rootScope.$broadcast("logout"); $state.go("app.home"); }); }
};
})();
Drupal Service + IonicFramework
In questo controller abbiamo:
Le finestre modali (per chiedere login e password)
Drupal Service + IonicFramework
In questo controller abbiamo:
Le finestre modali (per chiedere login e password)
La gestione automatica del menù slide fatto tramite una semplice valorizzazione di sharedService.user
Drupal Service + IonicFramework
E per visualizzare dei dati presi via GET ? Nella nostra app di prova sonodelle immagini
Il controller è puro AngularJS
Drupal Service + IonicFramework
E per visualizzare dei dati presi via GET ? Nella nostra app di prova sonodelle immagini
Il controller è puro AngularJS
Al div principale sono state definite le funzioni per gestire swipe a sinistra swipe a destra
<div on-swipe-left="onSwipeLeft()" on-swipe-right="onSwipeRight()" >
E' IonicFramework che rende facilmente disponibile il service $swipe di AngularJS
https://docs.angularjs.org/api/ngTouch/service/$swipe
Drupal Service + IonicFrameworkIl codice HTML alla base della visualizzazione delle nostre immagini:
<ion-view title="Browse"> <ion-nav-buttons side="left" class="bar-positive"> <button menu-toggle="left"class="button button-icon icon ion-android-contact"></button> </ion-nav-buttons> <ion-content class="has-header"> <div on-swipe-left="onSwipeLeft()" on-swipe-right="onSwipeRight()" >
<div class="item item-body"> <img class="full-image" ng-src="{{post.fullimage}}"> <p> {{post.body.und[0].value}} </p> <p> <a href="#" class="subdued">{{post.like_count}} Like</a> <a href="#" class="subdued">{{post.comment_count}} Comments</a> </p> </div>
<div class="item tabs tabs-secondary tabs-icon-left"> <a class="tab-item" href="#"> <i class="icon ion-thumbsup"></i> Like </a> <a class="tab-item" href="#"> <i class="icon ion-chatbox"></i> Comment </a> <a class="tab-item" href="#"> <i class="icon ion-share"></i> Share </a> </div>
</div> </ion-content></ion-view>
Drupal Service + IonicFrameworkE questo è il controller
(function () { angular.module('Utrend').controller('singlePostCtrl', ['$scope','$ionicLoading', '$timeout', 'sharedService', 'restfulService', '$rootScope', singlePostCtrl]);
function singlePostCtrl($scope, $ionicLoading, $timeout, sharedService, restfulService, $rootScope) { $scope.searchParams = {from : sharedService.fromPost, limit : 1};
if (typeof $scope.post == 'undefined') { console.log("Azzero $scope.post"); $scope.post = {}; } $scope.getPost = function () { return restfulService.postSearch($scope.searchParams) .then(function(result) { sharedService.log("postSearch",result); return result; }) }
//Questo prende il primo post quando viene instanziato questo controller restfulService.getToken().then(function (result) { $ionicLoading.show({template: '<i class="button-icon icon ion-loading-a"></i>'}); $scope.getPost().then(function (result) { $scope.post = result.value[0]; sharedService.log("post",$scope.post); $timeout(function() { $scope.$apply(); $ionicLoading.hide(); }); }); });
Drupal Service + IonicFramework
$scope.onSwipeLeft = function() { console.log("onSwipeLeft"); $scope.searchParams.from++; sharedService.fromPost = $scope.searchParams.from; console.log($scope.searchParams.from); $ionicLoading.show({template: '<i class="button-icon icon ion-loading-a"></i>'}); $scope.getPost().then(function (result) { console.log("getToken -> getPost"); $scope.post = result.value[0]; sharedService.log("post",$scope.post); $timeout(function() { $scope.$apply(); $ionicLoading.hide(); }); }); }
Drupal Service + IonicFramework $scope.onSwipeRight = function() { console.log("onSwipeRight"); $scope.searchParams.from = ($scope.searchParams.from == 1) ? 0 : ($scope.searchParams.from-1); sharedService.fromPost = $scope.searchParams.from; console.log($scope.searchParams.from); $ionicLoading.show(); $scope.getPost().then(function (result) { console.log("getToken -> getPost"); $scope.post = result.value[0]; sharedService.log("post",$scope.post); $timeout(function() { $scope.$apply(); $ionicLoading.hide(); }); }); } }})();
Riassumendo
Per creare applicazioni mobili che sfruttano l'html5:
AngularJS IonicFramework (per velocizzare lo sviluppo) Un servizio remoto che permetta di ricevere le informazioni da visualizzare in formato JSON
Link utili
AngularJS: https://angularjs.org/
IonicFramework: http://ionicframework.com/
IonicFramework Generator: https://github.com/diegonetto/generator-ionic
La mia rivista flipboard dedicata ad angularJS e gli altri JShttps://flipboard.com/section/angularjs%2C-nodejs-e-gli-altri-js-bTb8rt
Icone per le app: http://ionicons.com/
Usare FontAwesome (Bootstrap): http://blog.nraboy.com/2014/10/
use-font-awesome-glyph-icons-ionicframework/