Sådan bruges Wikipedia's API til at oprette en brugergrænseflade med RamdaJS

I denne vejledning bygger vi et brugergrænseflade ved hjælp af Wikipedia's offentlige søgnings-API sammen med noget JavaScript + RamdaJS.

Kom godt i gang

Her er GitHub-linket og Codesandbox-linket. Åbn din terminal, og vælg en mappe for at klone den.

git clone [//github.com/yazeedb/ramda-wikipedia-search](//github.com/yazeedb/ramda-wikipedia-search) cd ramda-wikipedia-search yarn install (or npm install) 

Den mastergren har det færdige projekt, så tjek den startgren, hvis du ønsker at kode sammen.

git checkout start

Og start projektet!

npm start

Din browser skal automatisk åbne localhost: 1234.

Sådan får du inputværdien

Her er den indledende app.

For at fange brugerens input, mens de skriver, har vores inputelement brug for en lytter til begivenheder.

Din src/index.jsfil er allerede tilsluttet og klar til at gå. Du vil bemærke, at vi importerede Bootstrap til styling.

Lad os tilføje en dummy begivenhedslytter for at få tingene i gang.

import 'bootstrap/dist/css/bootstrap.min.css'; const inputElement = document.querySelector('input'); inputElement.addEventListener('keyup', (event) => { console.log('value:', event.target.value); }); 

Vi ved, at event.target.valuedet er standardmetoden til at få adgang til en indgangs værdi. Nu viser den værdien.

Hvordan kan Ramda hjælpe os med at opnå følgende?

  • Tag fat event.target.value
  • Trim output (strip ledende / bageste hvidt mellemrum)
  • Som standard er tom streng hvis undefined

Den pathOrfunktion kan faktisk håndtere den første og tredje punktform. Det tager tre parametre: standard, sti og data.

Så følgende fungerer perfekt

import { pathOr } from 'ramda'; const getInputValue = pathOr('', ['target', 'value']); 

Hvis det event.target.valueer undefined, får vi en tom streng tilbage!

Ramda har også en trimfunktion, så det løser vores whitespace-problem.

import { pathOr, trim } from 'ramda'; const getInputValue = (event) => trim(pathOr('', ['target', 'value'], event)); 

I stedet for at indlejre disse funktioner, lad os bruge pipe. Se min artikel om rør, hvis den er ny for dig.

import { pathOr, pipe, trim } from 'ramda'; const getInputValue = pipe( pathOr('', ['target', 'value']), trim ); 

Vi har nu en sammensat funktion, der tager et eventobjekt, griber det target.value, som standard ''og trimmer det.

Smuk.

Jeg anbefaler at gemme dette i en separat fil. Måske kalde det getInputValue.jsog brug standardeksportsyntaxen.

Henter Wikipedia URL

I skrivende stund er Wikipedia's API-søgnings-URL //en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=

For en faktisk søgning skal du bare tilføje et emne. Hvis du f.eks. Har brug for bjørne, ser URL'en sådan ud:

//da.wikipedia.org/w/api.php?origin=*&action=opensearch&search=bears

Vi vil gerne have en funktion, der tager et emne og returnerer den fulde Wikipedia-søgnings-URL. Når brugeren skriver, bygger vi URL'en baseret på deres input.

Ramda concatfungerer pænt her.

import { concat } from 'ramda'; const getWikipediaSearchUrlFor = concat( '//en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=' ); 

concat, tro mod sit navn, sammenkædes strenge og arrays. Det er curried, så levering af URL'en som et argument returnerer en funktion, der forventer en anden streng. Se min artikel om karry, hvis den er ny!

Sæt koden i et kaldet modul getUrl.js.

Lad os nu opdatere index.js. Importer vores to nye moduler sammen med pipeog tapfra Ramda.

import 'bootstrap/dist/css/bootstrap.min.css'; import { pipe, tap } from 'ramda'; import getInputValue from './getInputValue'; import getUrl from './getUrl'; const makeUrlFromInput = pipe( getInputValue, getUrl, tap(console.warn) ); const inputElement = document.querySelector('input'); inputElement.addEventListener('keyup', makeUrlFromInput); 

Denne nye kode konstruerer vores anmodnings-URL fra brugerens input og logger den via tap.

Tjek det ud.

At lave AJAX-anmodningen

Næste trin er at kortlægge denne URL til en AJAX-anmodning og indsamle JSON-svaret.

Erstat makeUrlFromInputmed en ny funktion searchAndRenderResults,.

const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(console.warn) ); 

Glem ikke at skifte din begivenhedslytter også!

inputElement.addEventListener('keyup', searchAndRenderResults); 

Her er vores resultat.

Lav en resultatkomponent

Nu hvor vi har JSON, lad os oprette en komponent, der pynter den op.

Føj Results.jstil din mappe.

Se tilbage på vores Wikipedia-søgning JSON-svar. Bemærk dens form. Det er en matrix med følgende indekser:

  1. Forespørgsel (hvad du søgte efter)
  2. Array af resultatnavne
  3. Resume af resuméer
  4. Array of links to results

Our component can take an array of this shape and return a nicely formatted list. Through ES6 array destructuring, we can use that as our function signature.

Edit Results.js

export default ([query, names, summaries, links]) => ` 

Searching for "${query}"

    ${names.map( (name, index) => `
  • ${name}

    ${summaries[index]}

  • ` )}
`;

Let’s go step by step.

  • It’s a function that takes an array of our expected elements: query, names, summaries, and links.
  • Using ES6 template literals, it returns an HTML string with a title and a list.
  • Inside the
      we map names to
    • tags, so one for each.
    • Inside those are tags pointing to each result’s link. Each link opens in a new tab.
    • Below the link is a paragraph summary.

    Import this in index.js and use it like so:

    // ... import Results from './Results'; // ... const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(Results) .then(console.warn) ); 

    This passes the Wikipedia JSON to Results and logs the result. You should be seeing a bunch of HTML in your DevTools console!

    All that’s left is to render it to the DOM. A simple render function should do the trick.

    const render = (markup) => { const resultsElement = document.getElementById('results'); resultsElement.innerHTML = markup; }; 

    Replace console.warn with the render function.

    const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(Results) .then(render) ); 

    And check it out!

    Each link should open in a new tab.

    Removing Those Weird Commas

    You may have noticed something off about our fresh UI.

    It has extra commas! Why??

    Template Literals

    It’s all about how template literals join things. If you stick in an array, it’ll join it using the toString() method.

    See how this becomes joined?

    const joined = [1, 2, 3].toString(); console.log(joined); // 1,2,3 console.log(typeof joined); // string 

    Template literals do that if you put arrays inside of them.

    const nums = [1, 2, 3]; const msg = `My favorite nums are ${nums}`; console.log(msg); // My favorite nums are 1,2,3 

    You can fix that by joining the array without commas. Just use an empty string.

    const nums = [1, 2, 3]; const msg = `My favorite nums are ${nums.join('')}`; console.log(msg); // My favorite nums are 123 

    Edit Results.js to use the join method.

    export default ([query, names, summaries, links]) => ` 

    Searching for "${query}"

      ${names .map( (name, index) => `
    • ${name}

      ${summaries[index]}

    • ` ) .join('')}
    `;

    Now your UI’s much cleaner.

    Fixing a Little Bug

    I found a little bug while building this. Did you notice it?

    Emptying the input throws this error.

    That’s because we’re sending an AJAX request without a search topic. Check out the URL in your Network tab.

    That link points to a default HTML page. We didn’t get JSON back because we didn’t specify a search topic.

    To prevent this from happening we can avoid sending the request if the input's empty.

    We need a function that does nothing if the input's empty, and does the search if it’s filled.

    Let’s first create a function called doNothing. You can guess what it looks like.

    const doNothing = () => {}; 

    This is better known as noOp, but I like doNothing in this context.

    Next remove getInputValue from your searchAndRenderResults function. We need a bit more security before using it.

    const searchAndRenderResults = pipe( getUrl, (url) => fetch(url) .then((res) => res.json()) .then(Results) .then(render) ); 

    Import ifElse and isEmpty from Ramda.

    import { ifElse, isEmpty, pipe, tap } from 'ramda'; 

    Add another function, makeSearchRequestIfValid.

    const makeSearchRequestIfValid = pipe( getInputValue, ifElse(isEmpty, doNothing, searchAndRenderResults) ); 

    Take a minute to absorb that.

    If the input value’s empty, do nothing. Else, search and render the results.

    You can gather that information just by reading the function. That’s expressive.

    Ramda’s isEmpty function works with strings, arrays, objects.

    This makes it perfect to test our input value.

    ifElse fits here because when isEmpty returns true, doNothing runs. Otherwise searchAndRenderResults runs.

    Lastly, update your event handler.

    inputElement.addEventListener('keyup', makeSearchRequestIfValid); 

    And check the results. No more errors when clearing the input!

    This tutorial was from mycompletely freecourse on Educative.io, Functional Programming Patterns With RamdaJS!

    Please consider taking/sharing it if you enjoyed this content.

    It’s full of lessons, graphics, exercises, and runnable code samples to teach you a basic functional programming style using RamdaJS.

    Thank you for reading ❤️