Search code examples
javascriptreactive-programmingrxjscyclejs

Displaying multiple users from http data instead of a single user


I'm trying to modify the following code so that I receive an array of users from http and display all of them. This code only receives and displays a single user.

import Cycle from '@cycle/core';
import {div, button, h1, h4, a, makeDOMDriver} from '@cycle/dom';
import {makeHTTPDriver} from '@cycle/http';

function main(sources) {
  const USERS_URL = 'http://jsonplaceholder.typicode.com/users/';
  const getAllUsers$ = sources.DOM.select('.get-all').events('click')
    .map(() => {
      return {
        url: USERS_URL + 1,
        method: 'GET'
      };
    });

  const user$ = sources.HTTP
    .filter(res$ => res$.request.url.indexOf(USERS_URL) === 0)
    .mergeAll()
    .map(res => res.body)
    .startWith(null);

  const vtree$ = user$.map(user =>
    div('.users', [
      button('.get-all', 'Get all users'),
      user === null ? null : div('.user-details', [
        h1('.user-name', user.name),
        h4('.user-email', user.email),
        a('.user-website', {href: user.website}, user.website)
      ])
    ])
  );

  return {
    DOM: vtree$,
    HTTP: getAllUsers$
  };
}

const drivers = {
  DOM: makeDOMDriver('#app-main'),
  HTTP: makeHTTPDriver(),
};

Cycle.run(main, drivers);

Solution

  • You should do one request for multiple users, then iterate over them:

    Get all users:

    // rather than getting just user 1
    url: USERS_URL,
    

    Update this stream:

    const users$ = sources.HTTP // users (plural)
    .filter(res$ => res$.request.url.indexOf(USERS_URL) === 0)
    .mergeAll()
    .map(res => res.body)
    .startWith([]); // start with an empty array
    

    Generate markup for all users:

    users.map(user => 
      div('.user-details', [
        h1('.user-name', user.name),
        h4('.user-email', user.email),
        a('.user-website', {href: user.website}, user.website)
      ])
    )
    

    Here's the complete, working code:

    function main(sources) {
      const USERS_URL = 'http://jsonplaceholder.typicode.com/users/';
      const getAllUsers$ = sources.DOM.select('.get-all').events('click')
        .map(() => {
          return {
            url: USERS_URL,
            method: 'GET'
          };
        });
    
      const users$ = sources.HTTP
        .filter(res$ => res$.request.url.indexOf(USERS_URL) === 0)
        .mergeAll()
        .map(res => res.body)
        .startWith([])
    
      const vtree$ = users$.map(users => {
        return div('.users', [
          button('.get-all', 'Get all users'),
          ...users.map(user => 
            div('.user-details', [
              h1('.user-name', user.name),
              h4('.user-email', user.email),
              a('.user-website', {href: user.website}, user.website)
            ])
          )
        ])
      });
    
      return {
        DOM: vtree$,
        HTTP: getAllUsers$
      };
    }