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.