Fringe_Nerd |||

Commit Log - Scroll Boxes and Filters

So, this one was kind of big, we added some functionality to the website! The commit number is 0bcd2fb66256d411785c6fdec730805a98d7cf33, You can follow along at https://github.com/halfordC/GigaRoboBuilder4 The test website that we’re building is at https://proud-pond-00959fa10.1.azurestaticapps.net/ (You’ll have to wait for things to load, I do not have any loading wheels or progress bars implemented yet)

So, what got added?

React Strap

This is a bootstrap-like React package, that adds in react components for quick UI elements. While I like how bootstrap looks, remembering all the CSS tags and looking stuff up all the time is a bit of a hassle, not Ideal. For me at least, it’s easiest to remember CSS tags when you make them yourself, and not being able to just reference tags in your code doesn’t really work. But, these components are easy to understand, and their structure is super simple, they’re just react components you rap stuff in. The Pilot card section of the current UI looks like this:

import React from 'react'
import PilotCard from './PilotCard';
import "./components.css"
import { Card, CardHeader } from 'reactstrap';

const PilotCardList = ({pilotCards}) => {
return (
<Card>
    <CardHeader>Pilot Cards</CardHeader>
    <div className="scrollmenuRobotCards">
    {pilotCards.map((pilotCard) => (
        <PilotCard pilotCard={pilotCard} key={pilotCard.id} />
    ))}
    </div>
</Card>
    )
}

So, everything we want in the card gets wrapped in Card” tags. The header for the card gets wrapped in CardHeader” tags.

This also gives the React Strap grid layout tool, which I quite like to do web layouts in. You can see that this section of App.js:

<Container className="gap-3">
    <Row className="p-2">
        <h1>Choose your Robot</h1>
    </Row>

    <Row className="p-2">
        {robots.length > 0 ? (<RobotPicker robots={robots} robotSelected={selectRobot}/>) : ('No Robots from server')}
    </Row>

    <Row className="p-2">
        <h1>Choose your Pilot</h1>
    </Row>
    
        {pilots.length > 0 ? (<PilotPicker pilots={pilots} pilotSelected={selectPilot}/>) : ('No Pilots from server')}

    <Row className="p-2">
        <Col>
            {robotAbilities.length > 0 ? (<RobotAbilityList robotAbilities={filteredRobotAbilities}/>) : ('No Robot Abilities from server')}
        </Col>
        <Col>
            {pilotAbilities.length > 0 ? (<PilotAbilityList pilotAbilities={filteredPilotAbilities}/>) : ('No Pilot Abilities from server')}
        </Col>
    </Row>

    <Row className="p-2">
        <Col>
            {robotCards.length > 0 ? (<RobotCardList robotCards={filteredRobotCards}/>) : ('No Robot Cards from server')}
        </Col>
        <Col>
            {pilotCards.length > 0 ? (<PilotCardList pilotCards={filteredPilotCards}/>) : ('No Pilot Cards from server')}
        </Col>
    </Row>

You can kind of follow the tags, and see how the grid is laid out. It looks like I missed a row on the pilot picker, I should probably fix that next commit.

Scroll Boxes:

So, I didn’t know how to make these before, was pretty happy to learn. These are ways in CSS to keep your elements in your div from spilling out, or keeping your div to a specific size no matter what is contained inside of it. The CSS in component.css looks like this:

.scrollmenuRobotCards {
height: 450px;
overflow-y: auto;
}

Each card is 15px in total (text+6px of padding on each side)(px means pixel), so that means we can fit 30 cards in each card list, just about enough for each robot and pilot. The Overflow-y being enabled is what keeps everything inside the box, and enables the scroll bar on the side. This seems super simple, but it took me a bunch of digging to find it and make it work.

API Interaction Decisions

So, I knew the start of building this site that I had two ways of going about getting data from the API. The page loading was always going to have all of the possible elements loaded in the front. So all robot, pilot, ability, and card information was all going to get sent to the client on page loading. But after that, when user selects Robot and Pilot, I had 2 options:

  • Filter the cards and abilities in react, where the client is still holding all the data, but we’re filtering out what’s shown on the page

    -or-

  • Use the API to make and load in new data for that specific robot and pilot combination. So instead of calling the API at api/getAllRobots”, we would call api/robots/Ayzn” to get all the abilities and cards for that robot. Not the exact calls, but you get the idea.

I ended up going with the first option. Working with APIs in react seems a little cumbersome to me, and filtering results seems to be faster. This means that the user just has to load all the data once, and if they decide to go back on their robot or pilot choice, all that data is still there, and we don’t need to make another call to get data that we had previously but over-wrote with a call to the API. So the filtering option seems more efficient, and relies on less complex asynchronous calls and stuff.

Filtering Code:

So, in the App.js, this is the code that actually filters the card and ability selection for Pilot and Robot:

First, we have this function:

let[chosenRobot, setChosenRobot] = useState(0);

const selectRobot = async (robotId) =>
{
    console.log(robotId);
    setChosenRobot(robotId);
//This is where we want to trigger a filter in our other apps.
}

This starts the page off with no robot selected. Since our database starts with an ID of 1” for AYZN, we can use 0 as a state in our app that indicates that no robot has been selected yet. Whenever we select a robot, that calls the setChosenRobot function defined in or useState call, and sets the chosen robot state to whatever robotId we pass in this function. This gets called by the Robot button in our Robot Picker component. Like this:

{robots.length > 0 ? (<RobotPicker robots={robots} robotSelected={selectRobot}/>) : ('No Robots from server')}

The selectRobot funciton gets passed to our Robot Picker, which get’s passed to the Robot components inside the picker, which call the selectRobot function on Click. After that, we set state based on whatever gets clicked.

let filteredRobotAbilities = robotAbilities.filter((robotAbility) => {
    if(chosenRobot !== 0)//if we have clicked a robot
    {
        return robotAbility.robotId === chosenRobot;
    }else
    {
        return robotAbility;
    }
});

This is our filter variable. By setting it with the Filter function, this becomes reactive to our state. (I think?). So, filteredRobotAbilities is a big list of all the robot abilities that we get from an API call on page load. When the chosen robot from above is 0 (no robot chosen), we just return all the robot abilities that get passed into this function (all robot abilities). When the chosenRobot state changes, then this list changes, and we only populate the list with robot abilities that have the same robotId as what was selected. This makes that component get re-rendered, and we get to see a filtered list of all the abilities we are now able to use, just the 6 that our chosen robot has to pick from.

Still need ToDo’s:

So, I really want to figure out how to take all the API stuff out of our main App, and put it in separate files. Our App.js is getting really long, and that feels incorrect to me. At the very least, cumbersome to scroll through to find what you want. It’s strange that doesn’t seem to have libraries that work like C does, where you can just load a bunch of functions into one file, and then just reference that file. Maybe it does, and I just don’t fully understand the export” system yet (most likely the case).

It also seems kind of weird to me that json objects don’t get deffined before we load them in. Like, me personally, I know the data structures of the database that we’re getting data from through the API. But react doesn’t. I haven’t deffined any of what a robotCard” or robotAbility” is, it has no idea what variable and data members are contained in those structures. If something is missing and we try to call it, it probably just throws an error. The lack of explicitcy just feels strange, not what I would expect coming from a lower level background.

Next Commit:

We’re going for card tooltips! Similar to what NetRunner.db does. Those things are cool, but also seem kinda hard. I guess we’ll find out next commit log.

Thanks for reading!

Up next So, I’m learning something new The past couple of months, I’ve had this project I’ve really wanted to make. My friend Alex makes one of my favorite board games, “Giga-Robo”. The The definitive guide for the best possible platform for music discourse
Latest posts So, you want to pick up a Bass? The definitive guide for the best possible platform for music discourse Commit Log - Scroll Boxes and Filters So, I’m learning something new Intro.Bust()