block by micahstubbs 8a21b7acf4ed2f9c3d3a3e2f3f0fabd8

intro to rxjs

Full Screen

a minimal implementation of Twitter’s “Who to follow” feature, but for github users. designed to demonstrate reactive programming patterns, where everything can to modeled as a data stream.

forked from tutorial-refactor from adrianmcli

which in turn is an iteration on the “twitter who to follow” example from @andrestaltz‘s nice Intro to Rx blog post

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
body {
    font-family: sans-serif;
    padding: 10px;
}
h2 {
    font-weight: bold;
    display: inline-block;
}
.refresh {
    font-size: 80%;
    margin-left: 10px;
}
.header {
    background: #ECECEC;
    padding: 5px;
}
.suggestions {
    border: 2px solid #ECECEC;
}
li {
    padding: 5px;
}
li img {
    width: 40px;
    height: 40px;
    border-radius: 20px;
}
li .username, li .close {
    display: inline-block;
    position: relative;
    bottom: 15px;
    left: 5px;
}
  </style>
</head>

<body>
<div class="container">
    <div class="header">
         <h2>Who to follow</h2><a href="#" class="refresh">Refresh</a>
    </div>
    <ul class="suggestions">
        <li class="suggestion1">
            <img />
            <a href="#" target="_blank" class="username">this will not be displayed</a>
            <a href="#" class="close close1">x</a>
        </li>
        <li class="suggestion2">
            <img />
            <a href="#" target="_blank" class="username">neither this</a>
            <a href="#" class="close close2">x</a>
        </li>
        <li class="suggestion3">
            <img />
            <a href="#" target="_blank" class="username">nor this</a>
            <a href="#" class="close close3">x</a>
        </li>
    </ul>
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/rxjs/2.2.26/rx.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/rxjs/2.2.26/rx.async.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/rxjs/2.2.26/rx.coincidence.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/rxjs/2.2.26/rx.binding.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/rxjs/2.2.26/rx.time.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/rxjs-dom/2.0.7/rx.dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="tutorial-refactor.js"></script>
</body>

tutorial-refactor.js

// UI Event Streams --------------------------------------------
const refreshButton = document.querySelector('.refresh');
const closeButton1 = document.querySelector('.close1');
const closeButton2 = document.querySelector('.close2');
const closeButton3 = document.querySelector('.close3');

const refreshClickStream = Rx.Observable.fromEvent(refreshButton, 'click');
const close1ClickStream = Rx.Observable.fromEvent(closeButton1, 'click');
const close2ClickStream = Rx.Observable.fromEvent(closeButton2, 'click');
const close3ClickStream = Rx.Observable.fromEvent(closeButton3, 'click');

// Helper Functions --------------------------------------------
const makeRequestUrl = () => {
  const randomOffset = Math.floor(Math.random() * 500);
  return `https://api.github.com/users?since=${randomOffset}`;
};

const getRandomUser = users => 
	users[Math.floor(Math.random() * users.length)];

// Program Logic -----------------------------------------------
// where 'startup-click' is an arbitrary string,
// could be any non-null value
const requestStream = refreshClickStream
	.startWith('startup-click')  
	.map(makeRequestUrl);

const responseStream = requestStream
	.flatMap(url => Rx.Observable.fromPromise($.getJSON(url)));

const createSuggestionStream = closeClickStream =>
  closeClickStream
    .startWith('startup-click')
    .combineLatest(responseStream, (click, users) => getRandomUser(users))
    .merge(refreshClickStream.map(() => null))
    .startWith(null);

const suggestion1Stream = createSuggestionStream(close1ClickStream);
const suggestion2Stream = createSuggestionStream(close2ClickStream);
const suggestion3Stream = createSuggestionStream(close3ClickStream);

// Rendering ---------------------------------------------------
function renderSuggestion(suggestedUser, selector) {
    const suggestionEl = document.querySelector(selector);
    if (suggestedUser === null) {
        suggestionEl.style.visibility = 'hidden';
    } else {
        suggestionEl.style.visibility = 'visible';
        const usernameEl = suggestionEl.querySelector('.username');
        usernameEl.href = suggestedUser.html_url;
        usernameEl.textContent = suggestedUser.login;
        const imgEl = suggestionEl.querySelector('img');
        imgEl.src = "";
        imgEl.src = suggestedUser.avatar_url;
    }
}

suggestion1Stream.subscribe(function (suggestedUser) {
    renderSuggestion(suggestedUser, '.suggestion1');
});

suggestion2Stream.subscribe(function (suggestedUser) {
    renderSuggestion(suggestedUser, '.suggestion2');
});

suggestion3Stream.subscribe(function (suggestedUser) {
    renderSuggestion(suggestedUser, '.suggestion3');
});