Series: Building a Social Network with Flask & Stream – Part 8

This is the eighth installment of a tutorial series focused on how to create a full-stack application using Flask and Stream. In this article, we will be walking through how to retrieve information from the Stream API client-side using Javascript to make an infinite scroll feature for our collections and content. Be sure to check out the Github repo to follow along!

Getting Started

At this point in our development, all of the requests have been done on the backend, through the server. One of the key advantages of integrating Stream is the ability to make client-side requests, using Javascript in the browser; this allows us to avoid proxying through our servers to retrieve information. In making these requests, we have to ensure that we retain control over our authentication credentials to avoid unauthorized access.

Stream provides a useful tool to generate user tokens to authenticate and limit their ability to modify data on the service. We will first have to generate these tokens on our backend and pass them to the user through a template. Much like our previous interactions with Stream, we will create user tokens as a method on the User class (in app/models.py) to be returned in a request.

https://gist.github.com/Porter97/87c2849ba7e783798685bb8b2859b4e6

Token Issues

Now that we have a way to generate tokens for the user, we will return them in the views that require them. In the last couple of articles, we made ways for a user to create, update, and delete collections and content, but no way for them to be able to view it. As collections are the highest level component created by a user, we will create a feed on the user page to view all of the collections that they’ve created. After that, the collection page will have a feed of all the content that has been added to it. Let’s update app/main/views.py to generate the Stream tokens for both and return them in their respective views:

https://gist.github.com/Porter97/62147da9115af2818b089e161df40cf7

Next, we’ll make the same adjustment for the collection view:

https://gist.github.com/Porter97/906967dad7514f3e2e5f0f88e81bf91d

Client-Based Fun

Stream provides a helpful JavaScript library to access its resources instead of building your own from scratch. In order to use it, we will have to import the package in our base.html file. While we are there, we can also update our navbar to add routes for adding collections and content:

https://gist.github.com/Porter97/15b21ecf092ed8fc766791c6cc7144c5

Templates in Templates

Users expect a visual consistency in accessing elements across a site, and you want to try and modularize components as much as possible to avoid repeating yourself (DRY!). To employ this philosophy for our app, we will create a template for rendering collections and content and simply import them to the pages where we will be using them. That way, if we make a change to the layout of a component, it will be replicated across the entire site, rather than having to recode every single page. collections and content share a number of attributes, so the layout will be rather similar between them:

app/templates/_collection.html:
https://gist.github.com/Porter97/6ebfab932bf81d6c2b190e06ca9204f7

As compared to

app/templates/_content.html:
https://gist.github.com/Porter97/0604fdcb507c922fac26434ac97664d7

Collecting Collections

Rather than paginating users’ collections with an ugly set of buttons at the bottom, we want to use an “infinite scroll” feature. Infinite scroll has become a rather ubiquitous feature in modern social media sites, and I find it makes the user experience a lot more fluid than continuously clicking to navigate through pages. Infinite scroll is actually a surprisingly simple feature to implement, when you know how to do it; with that said, there are a few “best practices” that can often slip through the development cracks. For the HTML portion, it's pretty simple. There’s the template that we just defined, a scroller to which newly formed elements are attached, and a sentinel element, which monitors for when a user (app/templates/user.html) has scrolled to a specific threshold of the screen to request and render new elements to the DOM:

https://gist.github.com/Porter97/dd73b940ca0b77ce67f18e4e8fe938aa

Following the Script

Next, we will set up a script to request and render the information on the page in our app/templates/user.html file. As this is our first time really diving into JavaScript, below, we’ll take a little time to walk through what is happening.

https://gist.github.com/Porter97/194528ef6ca24bdfce384fa28f07910a

First, when the DOM content is loaded, we create a Stream client using a public key and the token you created and passed through the view. After that, we create a variable to hold the feed of the page that we are currently viewing.

Next, we create variables for the template, scroller, and sentinel, as well as one for whether or not a collection is currently loading as a boolean value and the last ID of the most recent collection that was retrieved. As you can see at the beginning of the loadCollection() function, it first checks to make sure that the script isn’t already running to make sure we don’t render duplicates. The next step is checking to see if there is a last_id value, and if there is, including it with the user.get() function. Stream recommends you use last_id as the preferred method of pagination, as it drastically reduces the latency of the requests. Once the data is requested, it is checked to ensure there are values present in the results and, if not, the app returns a message to indicate the end to the user.

Once a response is returned with results, the script loops through it and, for each of the results, populates the template fields, appending the completed template to the scroller. Finally, it creates a new intersection observer on the sentinel component for the next time a user scrolls to that location. For the timestamp, we add a “Z” to the end of the string, to make sure that it is parsed properly for UTC with moment.js.

Once again, we are going to replicate the same steps for the collections page in rendering content. First, we insert the template, scroller, and sentinel in the collection.html page:

https://gist.github.com/Porter97/a31b1bf6393fb10dcbab7bc98d6aed6c

Next, we add in the JavaScript at the bottom in <script> tags:

https://gist.github.com/Porter97/9bf8322cc98b02c4c343efc1fab8bcd5

Sanity Check

Our user page should now render any collections a user has at the bottom of the page in an infinite scroll feed:

Once you’ve created your first collection, you can then click through the title to get to the collection page and see any content rendered at the bottom, in the same way you can see a user’s collections at the bottom of their page:

Finishing Up

Congratulations! We have now created an infinite scroll element on both user and collection pages: a way for registered users to create collections and content, as well as easily navigate the site and all of its elements. In our next article, we are going to get into allowing users to follow each other and specific collections, before creating a homepage timeline that aggregates all of the activity from each user’s follows into a customized feed!

As always, thanks for reading, and happy coding!

Note: The next post in this series can be found here.

Tutorials

Feeds