requestAutocomplete

Prendi i miei soldi, non il mio tempo

Giacomo Archibald
Jake Archibald

Introduzione

Mi piace il web. Nel complesso, penso sia una buona idea. Di conseguenza, mi imbatto in molti dibattiti sul web e su quelli nativi. Non ci vuole molto prima che l'altra persona inizi a parlare della facilità di pagamento attraverso i sistemi nativi. La mia reazione abituale è far cadere un fumogeno ed uscire dalla stanza ridendo in modo maniacale, perché non è una discussione per cui posso vincere. L'abbandono del carrello degli acquisti sul web mobile può arrivare al 97%. Immaginala nel mondo reale. Immagina che il 97% delle persone in un supermercato abbia un carrello pieno di cose che sta cercando, che capovolge il carrello ed esce. Alcune di queste persone stanno solo acquistando prezzi e non hanno mai intenzione di acquistarlo, ma l'orribile esperienza utente di acquisto sul web ha contribuito in modo significativo. Stiamo colpendo gli utenti con un'imposta sul loro stato d'animo. Pensa a un'esperienza di pagamento piacevole che hai avuto sul web, soprattutto sui dispositivi mobili. È uno store, vero? O almeno un sistema chiuso simile in cui sono già presenti i tuoi dati di pagamento. Questo è un problema. Richiede che i siti si impegnino a utilizzare un determinato fornitore di servizi di pagamento, al quale l'utente deve già avere un account e a cui deve aver effettuato l'accesso, oppure che si impegnino a utilizzare una piattaforma che richiede agli utenti di eseguire l'accesso a un determinato fornitore di servizi di pagamento, ad esempio storex che richiedono di scrivere il codice esclusivamente per quella piattaforma. Se non fai una di queste cose, l'utente è condannato a toccare lo schermo o la tastiera finché non ha la pelle del dito o si arrende. Dobbiamo risolvere il problema.

requestAutocomplete

In un mondo di WebGL, WebRTC e di altre API web fantasiose che iniziano con "Web", requestAutocomplete non è accattivante. Tuttavia, è un supereroe in abiti beige. Una piccola e noiosa API in grado di attaccare il cuore del vampiro dei pagamenti web.

Anziché affidarsi a un determinato fornitore di servizi di pagamento, richiede i dati di pagamento al browser, che li memorizza per conto dell'utente. Anche la versione requestAutocomplete() di Chrome si integra con Google Wallet per solo gli utenti negli Stati Uniti (attualmente). Provalo sul nostro sito di test.

form.requestAutocomplete

Gli elementi del modulo includono un singolo nuovo metodo, requestAutocomplete, che chiede al browser di compilare il modulo. Il browser mostrerà all'utente una finestra di dialogo che chiede l'autorizzazione e consente all'utente di selezionare i dettagli che vuole fornire. Non puoi chiamare quando vuoi, ma deve essere chiamato durante l'esecuzione di particolari eventi di interazione, come eventi di mouse su/giù, clic, tasti e tocco. Si tratta di una limitazione di sicurezza deliberata.

button.addEventListener('click', function(event) {
  form.requestAutocomplete();
  event.preventDefault();
});

// TODO: listen for autocomplete events on the form

Prima di esaminare gli eventi, dobbiamo assicurarci che il browser comprenda i campi del modulo...

Requisiti del modulo

Ai tempi in cui internet era in bianco e nero, Internet Explorer 5 adottava un nuovo attributo, autocomplete, sugli elementi di input dei moduli. Potrebbe essere impostato su "off" per interrompere il browser che offre suggerimenti e il gioco è fatto. Questa API è stata estesa per consentirti di specificare i contenuti previsti del campo senza modificare l'attributo "nome", ed è questo che requestAutocomplete utilizza per collegare i campi del modulo ai dati utente.

<input name="fullname" autocomplete="name">

Come specifica, requestAutocomplete non è specifico per i pagamenti, ma l'attuale implementazione di Chrome lo è praticamente. In futuro, aspettati che i browser siano in grado di gestire altri tipi di dati, speriamo che i browser siano in grado di gestire altri tipi di dati, come i dati di accesso e il generatore di password, le informazioni del passaporto e persino il caricamento di un avatar.

Al momento in Chrome, requestAutocomplete riconosce quanto segue:

Pagamento

  • email
  • Cc-name - nome sulla carta
  • cc-number: numero della carta
  • cc-exp-month: mese di scadenza della carta a due cifre
  • cc-exp-year: anno di scadenza della carta su quattro cifre
  • cc-csc: codice di sicurezza della carta di 3-4 cifre
<input type="email" autocomplete="email" name="email">
<input type="text" autocomplete="cc-name" name="card-name">
<input type="text" autocomplete="cc-number" name="card-num">
<input type="text" autocomplete="cc-exp-month" name="card-exp-month">
<input type="text" autocomplete="cc-exp-year" name="card-exp-year">
<input type="text" autocomplete="cc-csc" name="card-csc">

Gli attributi "name" che ho utilizzato sopra sono solo esempi, non c'è alcun obbligo di utilizzare valori particolari. Se hai intenzione di riutilizzare questo modulo per gli utenti che non hanno il criterio requestAutocomplete, che è l'ideale, ti consigliamo di aggiungere etichette, layout e la convalida HTML5 di base.

Non hai neppure bisogno di inserire elementi, puoi usare qualsiasi tipo di input di modulo. Ad esempio, puoi utilizzare <select> per i campi relativi alla scadenza della carta.

Messaggio dettagliato della console.
Messaggio dettagliato della console

Indirizzo

  • nome: nome completo. Utilizzare un nome completo come singolo campo è molto meglio che usare più campi. Più campi come il nome e il cognome mostrano un bias occidentale e potrebbero non avere senso per altre culture. Inoltre, è più facile digitare in un singolo campo.

  • tel - numero di telefono completo comprensivo del prefisso internazionale, in alternativa può essere suddiviso in

    • tel-country-code - ad es. +44
    • tel-national - il resto
  • indirizzo - indirizzo completo con componenti separati da virgole, suddivisi in

    • riga-indirizzo1
    • indirizzo-riga 2: può essere vuoto
  • località - città/paese

  • regione: codice statale, contea o cantone

  • codice postale: codice postale, codice postale, codice postale

  • country

Quanto riportato sopra deve essere utilizzato in combinazione con: - fatturazione - spedizione

<input type="text" autocomplete="billing name" required name="billing-name">
<input type="tel" autocomplete="billing tel" required name="billling-tel">
<input type="text" autocomplete="billing address-line1" required name="billing-address1">
<input type="text" autocomplete="billing address-line2" required name="billing-address2">
<input type="text" autocomplete="billing locality" required name="billing-locality">
<input type="text" autocomplete="billing region" required name="billing-region">
<input type="text" autocomplete="billing postal-code" required name="billing-postal-code">
<select autocomplete="billing country" required name="billing-country">
  <option value="US">United States</option>
  …
</select>

<input type="text" autocomplete="shipping name" name="shipping-name">
…

Ancora una volta, gli attributi del nome sono esempi e puoi usare quello che vuoi. Ovviamente non tutti i moduli devono richiedere un indirizzo di spedizione. Ad esempio, non chiedermi dove voglio che la mia stanza d'albergo venga consegnata, perché spesso il punto di forza è la posizione attuale. Esatto, abbiamo il modulo e sappiamo come fare per richiedere autocompletion. Ma...

Quando deve essere chiamato il completamento automatico della richiesta?

L'ideale sarebbe mostrare la finestra di dialogo requestAutocomplete anziché caricare la pagina che mostra il modulo di pagamento. Se tutto funziona correttamente, l'utente non dovrebbe visualizzare affatto il modulo.

Flusso di pagamenti

È prassi comune avere una pagina del carrello con un pulsante "Pagamento" che rimanda al modulo dei dettagli di pagamento. In questo caso, vuoi caricare il modulo di fatturazione nella pagina del carrello, ma nasconderlo all'utente e chiamare requestAutocomplete quando l'utente fa clic sul pulsante "Pagamento". Ricorda che dovrai pubblicare la pagina del carrello tramite SSL per evitare l'avviso di Skeletor. Per iniziare, dobbiamo nascondere il pulsante di pagamento in modo che l'utente non possa selezionarlo finché non è pronto, ma vogliamo farlo solo per gli utenti che utilizzano JavaScript. Pertanto, nell'intestazione della pagina:

<script>document.documentElement.className += ' js';</script>

E nel tuo CSS:

.js #checkout-button,
#checkout-form.for-autocomplete {
  display: none;
}

Dobbiamo includere il modulo di fatturazione nella pagina del carrello. Può andare ovunque, il CSS in alto fa in modo che non sia visibile all'utente.

<form id="checkout-form" class="for-autocomplete" action="/checkout" method="post">
  …fields for payment, billing address &amp; shipping if relevant…
</form>

Ora JavaScript può iniziare a configurare tutto:

function enhanceForm() {
  var button = document.getElementById('checkout-button');
  var form = document.getElementById('checkout-form');

  // show the checkout button
  button.style.display = 'block';

  // exit early if there's no requestAutocomplete support
  if (!form.requestAutocomplete) {
    // be sure to show the checkout button so users can
    // access the basic payment form!
    return;
  }

  button.addEventListener('click', function(event) {
    form.requestAutocomplete();
    event.preventDefault();
  });

  // TODO: listen for autocomplete events on the form
}

Chiamerai enhanceForm sulla pagina del carrello, poco dopo il modulo e il pulsante di pagamento. I browser che supportano requestAutocomplete godranno di una nuova e fantasiosa esperienza veloce, mentre gli altri browser torneranno alla tua normale forma di pagamento. Per ricevere punti bonus, ti consigliamo di caricare il modulo HTML tramite XHR come parte di enhanceForm. Ciò significa che puoi caricare il modulo solo nei browser che supportano requestAutocomplete e non dovrai ricordarti di aggiungerlo a ogni pagina da cui puoi chiamare enhanceForm. Ecco come funziona il sito dimostrativo.

Abbiamo chiamato requestAutocomplete, e ora?

Il processo di completamento automatico è asincrono e requestAutocomplete ritorna immediatamente. Per capire com'è andata, ascoltiamo un paio di nuovi eventi:

form.addEventListener('autocomplete', function() {
  // hurrah! You got all the data you needed
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    // the form was populated, but it failed html5 validation
    // eg, the data didn't match one of your pattern attributes
  }
  else if (event.reason == 'cancel') {
    // the user aborted the process
  }
  else if (event.reason == 'disabled') {
    // the browser supports requestAutocomplete, but it's not
    // available at this time. Eg, it wasn't called from an
    // interaction event or the page is insecure
  }
});

Se tutto ha funzionato, puoi fare tutto ciò che vuoi con i dati, la cosa più semplice da fare è inviare il modulo. Il server può quindi convalidare i dati e mostrare all'utente una pagina di conferma con il costo di consegna. Se i dati non sono validi, puoi mostrare il modulo ed evidenziare i campi che l'utente deve modificare. In alternativa, puoi semplicemente inviare il modulo e lasciare che si occupi della normale convalida lato server. Se l'utente ha annullato la procedura, non devi fare nulla. Se la funzionalità è disattivata, indirizza l'utente al modulo standard. Quindi, nella maggior parte dei casi, gli ascoltatori somigliano molto a...

form.addEventListener('autocomplete', function() {
  form.submit();
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    form.submit();
  }
  else if (event.reason != 'cancel') {
    window.location = '/checkout-page/';
  }
});

Dove vengono memorizzati i miei dati nel browser?

La specifica non determina dove vengono archiviati i dati, consentendo ai browser di innovare. Se hai eseguito l'accesso a Chrome, hai la possibilità di memorizzare dettagli in Google Wallet, in modo da renderli accessibili su altri dispositivi a cui hai eseguito l'accesso. Se memorizzi i tuoi dati in Wallet, il numero reale della tua carta non verrà distribuito entro il giorno requestAutocomplete, aumentando la sicurezza. Se non hai eseguito l'accesso a Chrome o se decidi di non utilizzare Google Wallet, i tuoi dati vengono eventualmente memorizzati localmente nel browser per essere riutilizzati. Questo è lo stato delle cose al momento, ma in futuro Chrome e altri browser potrebbero adottare fornitori di servizi di pagamento aggiuntivi.

Semplificare i pagamenti

È ridicolo che gli utenti debbano inserire più volte i propri dati di pagamento ogni volta che vogliono effettuare un acquisto. Le cose diventano più semplici quando un sito memorizza i tuoi dati di pagamento. Non mi è chiaro quanti siti memorizzano i dati della mia carta. Questo è un problema perfetto per gli standard web. requestAutocomplete può portare i pagamenti con un solo clic su tutto il web, senza vincoli al servizio o alla piattaforma, ed è anche quasi tempo.

Round bonus: gestione dei moduli con più pagine

È molto meglio chiamare requestAutocomplete una volta per raccogliere tutti i dati di cui hai bisogno. Se non riesci a modificare il tuo server per ricevere tutti questi dati in una volta, non c'è problema: estrai i dati dal modulo compilato e inviali nel modo più adatto alle tue esigenze. Puoi utilizzare questa ottima funzione per acquisire tutti i dati attualmente supportati come un semplice oggetto, senza dover creare un modulo. Una volta ottenuti i dati, puoi trasformarli nel formato richiesto dal server e pubblicarli in più passaggi.

checkoutButton.addEventListener('click', function() {
  requestUserData({
    billing: true,
    shipping: true
  }, function(response) {
    if (response.err == 'cancel') {
      // exit silently
      return;
    }
    if (response.err) {
      // fall back to normal form
      window.location.href = '/normal-checkout-form/';
      return;
    }

    // the rest is just made-up pseudo code as an example
    postToServer(data.shipping).then(function() {
      return postToServer(data.billing);
    }).then(function() {
      return postToServer(data.cc);
    }).catch(function() {
      // handle error
    });
  });
});