Today I Learned

Small clippings of things I’ve learned. Not always learned on the day posted.

#10

Subscribe to Action Results in NGRX with Facade Pattern

2019-08-20

TAGS: angularngrx

At work we recently moved our state management to ngrx with a Facade pattern.

The developer who selected and implemented our facade pattern told us that it was impossible to know whether a call was successful or not. With a new hire at work and some Googling, we found a solution that works for the short term.

This response on Stack Overflow worked for the most part, but seemed to be using a different version of ngrx. Putting the methods inside a pipe made it work:

[...]
import { Actions } from '@ngrx/effects';
[...]

@Component(...)
class SomeComponent implements OnDestroy {
    destroyed$ = new Subject<boolean>();

    constructor(updates$: Actions) {
        updates$
+            .pipe(
+            ofType(PostActions.SAVE_POST_SUCCESS),
+            takeUntil(this.destroyed$),
+            tap((arg) => console.log(arg))
+            ).subscribe();
-            .ofType(PostActions.SAVE_POST_SUCCESS)
-            .takeUntil(this.destroyed$)
-            .do(() => /* hooray, success, show notification alert ect.. */)
-            .subscribe();
    }

    ngOnDestroy() {
        this.destroyed$.next(true);
        this.destroyed$.complete();
    }
}

We'll eventually abstract this away into a class that our components can extend, but this is great for now.

#9

Using LocalStorage for Quick Persistent State

2019-08-19

TAGS: javascript

LocalStorage is handy in a pinch when you don't have any better solution for saving some form of state between sessions.

In my arcade game Dogger I save the scores to Local Storage so the user can compete against their personal best. LocalStorage is also handy for persisting a user's preference for Dark Mode, if your site offers it.

LocalStorage Methods

LocalStorage comes with a few methods to help us out.

Set Item

localStorage.setItem('highScore', '1500');

Get Item

To retrieve the data from localStorage:

const highScore = localStorage.getItem('highScore');

Remove Item

localStorage.removeItem('highScore');

Clear Everything

This removes everything from localStorage on this current website. This won't affect the localStorage from other sites.

localStorage.clear();

Using with LocalHost

You'll run into an issue when developing locally, as localStorage is all domain based. It helps if you make your key specific to the account or project you're on.

So instead of just doing:

localStorage.setItem('highScore', '1500');

You'd do something like this:

localStorage[account.id] = JSON.stringify({ highScore : 1500 });
#8

CSS Selectors: Child vs. Recursive

2019-08-16

TAGS: css

For a while I thought there was little difference between div > div and div div in CSS. Turns out there's a pretty drastic difference.

All Child Elements

.container * {
  padding: 1rem;
}

That will affect all items recursively inside .container. Children, grandchildren, great-grandchildren. You get the idea.

First Level Only

.container > * {
  padding: 1rem;
}

That will only affect the first level of elements inside container. Just the children, leaving grand-children untouched.

#7

Gatsby Clean

2019-08-18

TAGS: gatsby

If you're having build trouble with Gatsby a lot of times clearing your .cache and public folders will fix the problem. There's even a Gatsby CLI shortcut to help with that.

gatsby clean

If you're still having trouble, try removing the node_modules folder and reinstalling npm packages.

Also make sure you're not mixing yarn and npm for managing your Gatsby project. It can quickly get messy.

#6

VSCode Color Coded Title Bars

2019-08-14

TAGS: vscode

If you have to switch between repositories multiple times a day, you might benefit from having your workspaces color coded. Blue for me is the UI, while our services code is orange, etc.

In the root of your project make a folder named .vscode. Inside create a settings.json file. Paste the following:

{
  "workbench.colorCustomizations": {
    "titleBar.activeBackground": "#34ace0",
    "titleBar.activeForeground": "#ffffff",
    "titleBar.inactiveBackground": "#368fb5",
    "titleBar.inactiveForeground": "#d7d7d7"
  }
}

This will give you a nice skyblue titlebar. Change the colors and repeat the process in any repo you work in to give you a nice visual cue.

Picked this one up from Wes Bos's Advanced React course a while back. Still appreciate the visual cue every day.

#5

Contentful, Gatsby, and Markdown

2019-08-14

TAGS: graphqlgatsbycontentful

When adding this TIL feature to my website I hit a snag on build in gatsby-node.

The issue came because I'm bringing in data from local markdown files as well as the Contentful API. I have a markdown content type from Contentful that gets picked up by allMarkdownRemark. That would then try and access frontmatter that wasn't there. A quick filter in my GraphQL query allowed me to only bring in local files.

{
  allMarkdownRemark(
    filter: { fileAbsolutePath: { ne: null } }
  ) {
    edges {
      node {
        fields {
          slug
        }
        frontmatter {
          type
        }
      }
    }
  }
  allContentfulTil {
    edges {
      node {
        title
        number
      }
    }
  }
}
#4

Debugging Gatsby in VSCode

2019-08-13

TAGS: vscodegatsbydebugging

I never realized just how nice the VSCode debugging was. Was having trouble debugging my Gatsby build and found these docs:

https://www.gatsbyjs.org/docs/debugging-the-build-process/

Setting VSCode's debug settings to Auto Attach and running this:

node --nolazy --inspect-brk node_modules/.bin/gatsby develop

I set up some breakpoints in the code, then I was able to see what was coming through and debug from there. Way more powerful than console logging out everything.

#3

Angular Components with Top/Bottom Spacing

2019-08-12

TAGS: angularcss

When trying to add top or bottom margin to an Angular component it has no effect unless you add display:block; to the component. Angular components default to display:inline which doesn't take top or bottom padding/margin.

Non-working example:

<my-component class="component"></my-component>
.component {
  margin: 2rem 0;
}

This has no effect because my-component is defaulting to display:inline.

Working example:

<my-component class="component"></my-component>
.component {
  margin: 2rem 0;
  display:block;
}
#2

Avoiding Undefined in Deeply Nested Objects

2019-08-12

TAGS: javascript

The Problem

When checking for a property on a heavily nested object, you can sometimes run into undefined errors.

It's not so bad with something like user.name. You can use the && operator like this:

user && user.name

This only tries to access name on user if user exists.

With this object: user.company.documents.handbook there are multiple points where it could all fall apart. The solution using && starts to get really messy.

Destructuring Solution

We can use destructuring assignment to pull the values out.

const { user: { company: { documents: { handbook:  = 'default' } = {} } = {} } = {} } } = this

This gives us fallbacks with each = {} and also makes the variables more managable to work with.

Learned this one from Brady Sutton.

Lodash Solution

Lodash gives us the get method where you pass it an object, then the path you want, then the default value you'd like returned if anything comes back undefined.

_.get(this, 'user.company.documents.handbook', 'default')

Learned this one from Brady Sutton.

Optional Chaining Solution

We have a great solution coming to JavaScript soon called Optional Chaining. This will open up this syntax:

user.address?.zipcode
#1

Naming CSS Grid Rows and Columns

2019-08-11

TAGS: csscss grid

I usually name my CSS Grid areas so I can reference them easily. If I want to name columns I usually do it like this.

.container {
  display: grid;
  grid-template-columns: 3fr 4fr;
  grid-areas: "sidebar content";
}

Turns out there’s a great shorthand if you want to name an entire column or row. You can name your CSS Grid columns and rows like this:

.container {
  display: grid;
  grid-template-columns: [sidebar] 3fr [content] 4fr;
}

Not only does it save you some lines of code, but you get the name right next to the size for easy reference.

Learned it from this article.