• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Google Books - API

Object Storage Arubacloud
0 głosów
586 wizyt
pytanie zadane 6 czerwca 2020 w JavaScript przez Allen Obywatel (1,010 p.)
zamknięte 7 czerwca 2020 przez Allen

Postępuje zgodnie z dokumentacją Googla: https://developers.google.com/books/docs/viewer/developers_guide

Zmienna isbn zawiera poprawny identyfikator, wydaje mi ię że cała reszta również jest w porządku. Pojawia się taki błąd: 

readBtns.forEach(btn => {
  btn.addEventListener('click', (event) => {
    let title = event.path[2].querySelector('.title-ex').textContent;
    let gbUri = 'https://www.googleapis.com/books/v1/volumes?key=MY_KEY&cx=017576662512468239146:omuauf_lfve&q=' + title;
    fetch(gbUri).then(response => response.json()).then(response => {
      //let gbId = response.items[0].id;
      let isbn = response.items[0].volumeInfo.industryIdentifiers[1].identifier;
      google.books.load();
      google.books.setOnLoadCallback(initialize(isbn));
    });
  });
});

function initialize(isbn) {
  const viewerCanvas = document.createElement('div');
  viewerCanvas.id = 'viewerCanvas';
  const viewer = new google.books.DefaultViewer(viewerCanvas);
  viewer.load('ISBN:' + isbn, BookNotLoaded, BookLoaded);
};

 

komentarz zamknięcia: Otrzymałem odpowiedź

1 odpowiedź

+1 głos
odpowiedź 6 czerwca 2020 przez ScriptyChris Mędrzec (190,190 p.)
wybrane 6 czerwca 2020 przez Allen
 
Najlepsza

Postępuje zgodnie z dokumentacją Googla:

google.books.setOnLoadCallback(initialize(isbn));

Chyba nie do końca ;) W dokumentacji do metody setOnLoadCallback przekazywana jest referencja do funkcji initialize a nie wynik jej wywołania:

google.books.setOnLoadCallback(initialize);

Jeśli chcesz przekazać dodatkowy parametr, to możesz przekazać funkcję anonimową:

google.books.setOnLoadCallback(() => initialize(isbn));

P.S. Na przyszłość, nie umieszczaj kluczy do API w kodzie, który wstawiasz w jakiekolwiek publiczne miejsca w sieci - zastąpiłem ten fragment kodu w pytaniu frazą MY_KEY.

komentarz 7 czerwca 2020 przez Allen Obywatel (1,010 p.)
edycja 7 czerwca 2020 przez Allen

console.log(google.books.load()) podpięte tuż pod jsapi.ja pokazuje, że funkcja jest dostępna.

const deleteBtns = document.querySelectorAll('.delete-btn-form');
const readBtns = document.querySelectorAll('.read-btn');
 
deleteBtns.forEach(btn => {
    btn.addEventListener('click', () => {
      btn.submit();
    });
  });
 
readBtns.forEach(btn => {
  btn.addEventListener('click', (event) => {
    google.books.load();
    let title = event.path[2].querySelector('.title-ex').textContent;
    let gbUri = 'https://www.googleapis.com/books/v1/volumes?key=MY_KEY&cx=017576662512468239146:omuauf_lfve&q='+ title;
    fetch(gbUri).then(response => response.json()).then(response => {
      let isbn = response.items[0].volumeInfo.industryIdentifiers[1].identifier;
 
      google.books.setOnLoadCallback(() => initialize(isbn));
    });
  });
});
 
function initialize(isbn) {
    const viewerCanvas = document.createElement('div');
    viewerCanvas.id = 'viewerCanvas';
    const container = document.querySelector('.container');
    container.appendChild(viewerCanvas);
    const viewer = new google.books.DefaultViewer(viewerCanvas);
    viewer.load('ISBN:' + isbn, bookNotLoaded, bookLoaded);
};
 
function bookNotLoaded () {
  console.log('Unable to load book');
}
 
function bookLoaded () {
  console.log('The book has loaded successfully');
  }

Teraz występuje błąd: google.books.setOnLoadCallback is not a function. Gdy linię 18 przeniosę pod 38 zmienna isbn nie jest dostępna.

komentarz 7 czerwca 2020 przez ScriptyChris Mędrzec (190,190 p.)

Hmm..., trudno mi powiedzieć dlaczego tak się dzieje. Wychodzi na to, że w późniejszym etapie działania aplikacji obiekt google.books zmienia swoją strukturę, stąd na etapie obsługi Promisa nie ma dostępu do metod load ani setOnLoadCallback. Żeby znaleźć przyczynę, trzeba by debugować kod.

Może wystarczy funkcję initialize zawołać raz, a potem wołać viewer.load z kolejnymi wartościami isbn operując na referencji viewer i już nie wołać google.books.[load/setOnLoadCallback] więcej niż raz?


Zadam trochę głupie pytanie, ale ile razy wywołujesz setOnLoadCallback? To dzieje się na klik - za którym kliknięciem to nie działa?

komentarz 7 czerwca 2020 przez Allen Obywatel (1,010 p.)
edycja 10 czerwca 2020 przez Allen

Gdy wywołuję funkcję google.books.load() oraz google.books.setOnLoadCallback(initialize), to element viewer jest niezdefiniowany. 

readBtns.forEach(btn => {
  btn.addEventListener('click', (event) => {
    google.books.load();
    console.log('Pierwszy');
    let title = event.path[2].querySelector('.title-ex').textContent;
    let gbUri = 'https://www.googleapis.com/books/v1/volumes?key=MY_KEY&cx=017576662512468239146:omuauf_lfve&q=' + title;
    fetch(gbUri).then(response => response.json()).then(response => {
      let isbn = response.items[0].volumeInfo.industryIdentifiers[1].identifier;
      google.books.setOnLoadCallback(() => initialize(isbn));
    });

    const bookNotLoaded = () => {
    console.log('Unable to load book');
      const fillMsg = document.createElement('div');
      fillMsg.className = 'warningMsg';
      const fillTextMsg = document.createTextNode('Unable to load book');
      fillMsg.appendChild(fillTextMsg);
      const contentModal = document.querySelector('.msg-banner');
      contentModal.appendChild(fillMsg);
    };
    
    const bookLoaded = () => {
    console.log('The book has loaded successfully');
      const warningMsg = document.querySelector('.warningMsg');
      if (warningMsg !== null) {
        warningMsg.parentNode.removeChild(warningMsg);
      }
    };

    const initialize = (isbn) => {
      console.log('Drugie');
      const viewerCanvas = document.createElement('div');
      viewerCanvas.id = 'viewerCanvas';
      const container = document.querySelector('.container');
      container.appendChild(viewerCanvas);
      const viewer = new google.books.DefaultViewer(viewerCanvas);
      viewer.load('ISBN:' + isbn, bookNotLoaded, bookLoaded);
    };
  });
});

W tym kodzie po pierwszym kliknięciu w konsoli pojawia się "Pierwszy", a błąd wyskakuje po drugim i każdym następnym kliknięciu. Gdy po odświeżeniu strony szbko klikam wiele razy w readBtn w konsoli pojawia się kilka razy "Pierwszy" i dopiero błąd.

komentarz 7 czerwca 2020 przez ScriptyChris Mędrzec (190,190 p.)

Przenieś google.books.load() na początek kodu - niech to się wykonuje raz w trakcie działania aplikacji (a nie przy każdym kliku, jak teraz).

Gdy wywołuję funkcję google.books.load() oraz google.books.setOnLoadCallback(initialize), to element viewer jest niezdefiniowany

W którym miejscu viewer jest niezdefiniowany? Tą zmienną tworzysz w funkcji initialize i tylko tu masz teraz do niej dostęp.

Wywołaj funkcję initialize po google.books.load(), ale zmienną viewer trzymaj w zewnętrznym scope - niech w funkcji initialize będzie tylko zainicjowana przez new google.books.DefaultViewer. Dopiero na kliknięcie wołaj funkcję, do której przekażesz isbn i tam dopiero wołaj viewer.load z przekazaniem tego isbn (na takiej zasadzie jak robisz teraz, z tym że inicjuj API tylko raz, na początku).

Coś takiego:

    let viewer = null;
    
    google.books.load();
    google.books.setOnLoadCallback(initialize);

    function initialize () {
      const viewerCanvas = document.createElement('div');
      viewerCanvas.id = 'viewerCanvas';
      const container = document.querySelector('.container');
      container.appendChild(viewerCanvas);
      viewer = new google.books.DefaultViewer(viewerCanvas);
    };

   function loadPage (isbn) {
     viewer.load('ISBN:' + isbn, bookNotLoaded, bookLoaded);
   }

   /* kod obsługujący Promisa zwróconego przez fetch*/
   .then(response => {
      let isbn = response.items[0].volumeInfo.industryIdentifiers[1].identifier;
      loadPage(isbn);
   })
komentarz 7 czerwca 2020 przez Allen Obywatel (1,010 p.)
Wszytko działa. Bardzo dziękuję za pomoc i poświęcony czas, w życiu bym tego sam nie ogarnął.

Podobne pytania

0 głosów
0 odpowiedzi 108 wizyt
pytanie zadane 7 czerwca 2020 w Android, Swift, Symbian przez Paweł123 Nałogowiec (33,500 p.)
0 głosów
1 odpowiedź 219 wizyt
pytanie zadane 19 listopada 2018 w JavaScript przez niezalogowany
0 głosów
2 odpowiedzi 833 wizyt
pytanie zadane 26 maja 2020 w JavaScript przez frederrer Użytkownik (740 p.)

92,583 zapytań

141,434 odpowiedzi

319,669 komentarzy

61,966 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...