88 RX – mostriamo i libri nel DOM
in questa parte andremo a mostrare i libri nella finestra del browser ricevendoli dalla nostra subscribe. Possiamo quindi eliminare il tap che ci serviva solo come controllo e mettere la sua funzione direttamente nella subscribe creando una funzione displayBook().
.subscribe( (book:Book) => displayBook(book) );
La funzione displayBook() riceverà in ingresso il libri di tipo interface Book
function displayBook(book: Book) { }
La funzione man mano che arrivano i dati li dovrà inserire all’interno del DOM utilizzando il template di bootstrap che dinamicamente verrà generato ogni volta, prendendolo dalla index.html
<div class="col-md-4"> <div class="card mb-4 shadow-sm"> <svg class="bd-placeholder-img card-img-top" width="100%" height="225" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice" focusable="false" role="img" aria-label="Placeholder: Thumbnail"><title>Placeholder</title> <rect width="100%" height="100%" fill="#55595c"/> <text x="50%" y="50%" fill="#eceeef" dy=".3em">Thumbnail</text> </svg> <div class="card-body"> <p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p> <div class="d-flex justify-content-between align-items-center"> <div class="btn-group"> <button type="button" class="btn btn-sm btn-outline-secondary">View</button> <button type="button" class="btn btn-sm btn-outline-secondary">Edit</button> </div> <small class="text-muted">9 mins</small> </div> </div> </div> </div>
Lo inseriamo dentro la nostra funzione all’interno di una nuova costante bookTpl racchiuso tra apice incerto (backtick) e lo ripuliamo delle parti che non ci servono, come l’svg o la descrizione statica. L’svg lo sostituiamo con un tag <img> e utilizziamo la forma eseguita ${book.} per inserire nel template i dati dinamicamente
function displayBook(book: Book) { const bookTpl = `<div class="col-md-4"> <div class="card mb-4 shadow-sm"> <img src="${book.thumbnail}" title="${book.title}" alt="${book.title}"> <div class="card-body"> <p class="card-text">${book.title}</p> <div class="d-flex justify-content-between align-items-center"> <div class="btn-group"> <button type="button" class="btn btn-sm btn-outline-secondary">View</button> <button type="button" class="btn btn-sm btn-outline-secondary">Edit</button> </div> <small class="text-muted">9 mins</small> </div> </div> </div> </div> `; }
adesso facciamo l’append del nostro template selezionando l’id books del <div> con classe row, creando l’elemento <div class=”col-md-4″> che elimineremo dal nostro template
function displayBook(book: Book) { const bookTpl = `<div class="card mb-4 shadow-sm"> <img src="${book.thumbnail}" title="${book.title}" alt="${book.title}"> <div class="card-body"> <p class="card-text">${book.title}</p> <div class="d-flex justify-content-between align-items-center"> <div class="btn-group"> <button type="button" class="btn btn-sm btn-outline-secondary">View</button> <button type="button" class="btn btn-sm btn-outline-secondary">Edit</button> </div> <small class="text-muted">9 mins</small> </div> </div> </div>`; const div = document.createElement('div'); div.setAttribute('class','col-md-3'); div.innerHTML = bookTpl; document.querySelector('#books').appendChild(div); }
abbiamo inserito il col-md-3 per adattare meglio le immagini, e effettuato un controllo sui dati books. Da notare il metodo setAttribute() con cui abbiamo inserito la classe
const div = document.createElement('div'); div.setAttribute('class','col-md-3'); div.innerHTML = bookTpl; const books = document.querySelector('#books'); if (books) { books.appendChild(div); }
Ora andiamo ad aggiungere il titolo nel template e nel p sostituiamo con la descrizione o stringa vuota se la descrizione non ci fosse
<h5>${book.title}</h5> <p class="card-text">${book.description || ''}</p>
Aggiungiamo una barra di ricerca
Sfruttando sempre bootstrap cerchiamo una ricerca con bottone e lo incolliamo nella nostra index.html al posto del <botton> nella navbar
<form class="form-inline mt-2 mt-md-0"> <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> </form>
per ottenere una barra di questo tipo spostando il logo sopra e cambiando la classe justify-content-end
<div class="navbar navbar-dark bg-dark shadow-sm"> <a href="#" class="navbar-brand d-flex align-items-center"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="mr-2" viewBox="0 0 24 24" focusable="false"> <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/> <circle cx="12" cy="13" r="4"/> </svg> <strong>Album</strong> </a> <div class="container d-flex justify-content-end"> <form class="form-inline mt-2 mt-md-0"> <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> </form> </div> </div>
a volte si potrebbe generare un errore per il numero di chiamate a google fatte da anonimo, quindi aggiungiamo una regola nello switchMap così non viene generato l’errore, o l’ideale è passare l’api key di google books tramite url, ma per semplificare agiamo nel primo modo
switchMap( (data:GoogleBook) => from(data.items || [])),
ora è il momento di far funzionare la ricerca, facciamo in modo che dopo 3 lettere inserite venga inviata la query, iniziamo aggiungendo un id all’ <input> search
<input class="form-control mr-sm-2" type="text" placeholder="Search" id="search" aria-label="Search">
Creiamo una nuova funzione searchBooks() dove andiamo a selezionare il tag <input> con javaScript e inseriamo un if che se esiste (diverso da 0 quindi campo non vuoto), facciamo qualcosa
function sarchBooks() { const searchEle = document.querySelector('#search'); if (searchEle) { getBooks('game of thrones'); } }
Usando rxjs, dobbiamo creare un observable che scaturisca l’evento, lo facciamo nella prossima lezione.