24 Dec 2017, 14:53

Getting going with ES6 Maps

As we move into a world where modern browsers are supporting the nearly the entire ES6 specification, we have a variety of data structures to use for storing and accessing our data as native built-in primitives. In ES6 we specifically gain access to ‘keyed collections’. Keyed collections encompasses four built-ins, these are namely Set, Map, WeakSet and WeakMap. Here we’ll be talking about the Map in particular. Let’s get stuck in!

What is a Map?

A Map is a collection of key value pairs, where both key and values can be of any type. This differs from how one might have traditionally used a JavaScript Object as a map, as historically keys have been strings only (this has changed with the introduction of Symbols but that’s for a different blog post to come!).


const obj = { 1 : "one" }
typeof Object.keys(obj)[0] // Evaluates to string

So with Maps, we have the additional power of using anything we like as our key, even a HTMLElement, which is powerful because it makes it easy to associate data with a DOM node. To illustrate the use of none String keys, we can see this example using booleans:


const map = new Map([
    [true, "Things that are true"],
    [false, "Things that are false"]
]);

Here true and false are the respective keys in our collection. So how does JavaScript know how to evaluate something as matching a Map key? Well the approach is very similar to the === (identity) operator, with the minor caveat that NaN (Not a Number) equates to NaN even though NaN !== NaN.

How do we use it?

Maps provide a set of methods for interfacing with them such as get, set and delete. These methods provide a clean inteface for interacting with our data. Let’s see how that works in practice:


const one = "one";
const map = new Map([ ["one", 1] ])
map.get("one"); // Returns 1
map.get(one); // Returns 1

map.set("two", 2);
// Returns the Map with "two" set to 2

map.delete("one");
// Returns true if successful or false if unsuccessful

map.clear();
// Returns undefined

As you can see there’s a little gotcha here, get, set and delete all have different return behaviours. Get will return the associated value, set will return the Map itself, and delete will return a boolean, and clear returns undefined. Something to keep in mind!

We also have some really nice convenience methods to help us interface. For example, has which will tell us if a key exists in a Map:


const map = new Map([ ["one", 1], ["two", 2] ]);
map.has("two") // true

This is very useful for quickly checking the existence of key in a Map. What about if we want to iterate over a Maps contents? Firstly there are a few convenient methods in this regard: values, entries and forEach. Let’s look at values and keys. Both these methods return an iterable. Iterables are a little outside the scope of this post, but think of them as JavaScript variables that have defined behaviours for what happens when you iterate over them (for example using for…of):


// Entries
const map = new Map([ ["one", 1], ["two", 2] ]);

for (const num of map.entries()) {
    console.log(num); 
    // Logs ["one", 1]
    // Then ["two", 2]
}

// Values
for (const key of map.values()) {
    console.log(key);
    // Logs 1
    // Then 2
}

Alongside this we have the forEach method that some of you may be familiar with from the Array method of the same name. It behaves like so:


const map = new Map([ ["one", 1], ["two", 2] ]);
map.forEach((key, value) => console.log(key, value));
// Logs ["one", 1]
// Then ["two", 2]

Lastly we can quickly and conveniently get the size of a map with the size method. It is fairly straight forward and operates like so:

const pets = Map([ ["dog", "woof!"], ["cat", "meow"], ["goldfish", "bop bop bop"] ]);
animals.size(); // Evaluates to 3

Which would have been less elegant using an Object:

var pets = {"dog", "woof!", "cat": "meow", "goldfish": "bop bop bop"};
Object.keys(pets).length;

Why use a Map?

Simply put, the Map is more idiomatic and effective primitive than an Object for use as a mutable key-value pair data structure. We have the added flexibility of using anything we please as our keys, alongside a clear set of a powerful methods that we have shown above. These methods allow us to be more semantic and straightforward about interacting and manipulating our data. It also avoids some of the potential pitfalls of the Object, for example, because of the interface of a Map, we can avoid the possibility of colliding with default Object properties such as toString or hasOwnProperty. This is obviously an edge case but provides us with extra reassurance:


// With a traditional Object
const obj = {};
obj["toString"] = "woops";
console.log(obj.toString);
// Evaluates to woops

// With a Map
const map = Map();
map.get("toString") // undefined
map.set("toString", "This is fine");

Overall it expresses a lot of cool properties that suite it better to behaviours we wanted from using an Object as a Map previously. Happy Mapping!

03 Dec 2017, 10:10

Creating Gradient Borders with CSS

Products have seen a resurgence of gradients in the past year or so. I too wanted to cash in on the PowerPoint circa 2003 aesthetic and as such I took to work on finding how I could add some gradients to the button outlines on my blog. Unfortunately I really struggled to find any decent guides on the matter, but after a little bit of digging and understanding the solution was fairly straightforward. Recently I’ve been trying to write shorter blog posts more often about little things I’ve learned, so I thought I’d share that with you folks today!

So from my research, the canonical way to do gradient borders in modern browsers appears to be as such:


    .someButton {
        border-image: linear-gradient(to left, #743ad5 0%, #d53a9d 100%);
        border-image-slice: 1;
        border-width: 2px;
    }

This is the gradient I am currently using for the navigation buttons on the left. Here border-image allows a developer to pass in a image URL or a gradient (perhaps unintuitively). You can find it’s full details on MDN here. In our case we are interested in a gradient so we can use linear-gradient or alternatively a radial-gradient if you’re looking for that sort of effect. You can use a direction argument to specify a given direction for the gradient, for example in our case above to left or bottom right might be another example.

A nice little website for generating gradients is https://www.css-gradient.com/, where you can play around with different properties to get your desired result. A note however, you shouldn’t need a prefix any more for gradients so you can ignore that!

border-image-slice is the second CSS property we need to fill to get this working. As I was, you might be asking what on earth does this do? If you’re anything like me, it can be quite hard to wrap your head around. As an exact definition: “The border-image-slice CSS property divides the image specified by border-image-source in nine regions: the four corners, the four edges and the middle” (MDN). The property has less meaning in the gradient context as it specifies offsets for the image in question to position it for the border in question. border-image-slice can take up to four sets of arguments, each with different behaviours depending on the number of arguments provided. The arguments here can either be a percentage or a number, with the default value for the property being 100%. For our use case, we will be providing it a value of 1. If you want to get a clearer picture, consider seeing the docs for the property.

Finally, good old border-width will provide a given width for our border in question. You can adjust it as you see fit to get the desired effect. Here’s some little gradient buttons I made for inspiration!



.buttonOne {
    border-image: linear-gradient(to right, #b861c6 0%,#ffc7c7 100%);
    border-image-slice: 1;
    border-width: 3px;
}

.buttonTwo {
    border-image: linear-gradient(to left, #61c69d 0%, #2d72bc 100%);
    border-image-slice: 1;
    border-width: 3px;
}

.buttonTwo {
    border-image: linear-gradient(to left, #2e98bc 0%, #c66262 100%);
    border-image-slice: 1;
    border-width: 3px;
}

Which after applying the class to your button in question would look a little something like this in your browser:

Hopefully that’s been a fairly painless guide to generating your own gradient borders in CSS. Have fun!

11 Nov 2017, 15:00

Replicating JavaScripts setTimeout and setInterval in Go

In JavaScript we have two inbuilt functions for doing some work at some given point in the future. Firstly setTimeout; this allows us to run a function after a given period of time in milliseconds. We also have setInterval which allows us to run a function every x milliseconds until the interval is cancelled with clearInterval. You can find a solid overview of timers in JavaScript on MDN here.

For those unfamiliar with the two functions, let’s see how they look (in ES5):


    var timeout = 1000; // 1 second

    setTimeout(function(){
        console.log("This will happen after " + timeout + "milliseconds");
    });

    var interval = 500; // 0.5 seconds

    var anInterval = setInterval(function(){
        console.log("This will happen after " + timeout + "seconds");
    });

Recently I have been wanting to achieve the same thing in Go on a small side project I am working on. As such I thought I would share my findings with you all!

Replicating setInterval

setInterval is arguably the more complicated of the two functions to implement. The basic premise is we setup a new ticker from Go’s time package. The NewTicker function creates a channel which we can select over (see here for an overview of the select feature in Go), which passes a signal to the channel every x milliseconds, calling the arbitrary passed in function. We also select over the clear channel. This can in turn clear the interval when we pass a boolean value to it.


    func setInterval(someFunc func(), milliseconds int, async bool) chan bool {

        // How often to fire the passed in function 
        // in milliseconds
        interval := time.Duration(milliseconds) * time.Millisecond

        // Setup the ticket and the channel to signal
        // the ending of the interval
        ticker := time.NewTicker(interval)
        clear := make(chan bool)

        // Put the selection in a go routine
        // so that the for loop is none blocking
        go func() {
            for {

                select {
                case <-ticker.C:
                    if async {
                        // This won't block
                        go someFunc()
                    } else {
                        // This will block
                        someFunc()
                    }
                case <-clear:
                    ticker.Stop()
                    return
                }

            }
        }()

        // We return the channel so we can pass in 
        // a value to it to clear the interval
        return clear

    }

    func main() {

        // A counter for the number of times we print
        printed := 0
        
        // We call set interval to print Hello World forever
        // every 1 second
        interval := setInterval(func() {
            fmt.Println("Hello World")
            printed++
        }, 1000, false)
        
        // If we wanted to we had a long running task (i.e. network call)
        // we could pass in true as the last argument to run the function
        // as a goroutine

        // Some artificial work here to wait till we've printed
        // 5 times
        for {
            if printed == 5 {
                // Stop the ticket, ending the interval go routine
                stop <- true
                return
            }
        }

    }

Replicating setTimeout

Replicating JavaScripts setTimeout is slightly more straight forward. We can leverage the time package’s AfterFunc function which fires off goroutine that will run a function after a given period of time. We could do this using code like this:


    func setTimeout(someFunc func(), milliseconds int) {

        timeout := time.Duration(milliseconds) * time.Millisecond

        // This spawns a goroutine and therefore does not block
        time.AfterFunc(timeout, someFunc)

    }

    func main() {

        printed := false
        print := func() {
            fmt.Println("This will print after x milliseconds")
            printed = true
        }

        // Make the timeout print after 5 seconds
        setTimeout(print, 5000)

        fmt.Println("This will print straight away")
        
        // Wait until it's printed our function string
        // before we close the program
        for {
            if printed {
                return
            }
        }
        
    }

Hopefully this has given some insight on how we might achieve similar functionality in Go to JavaScripts setInterval and setTimeout functionality. If you see a potential problem, or have ideas about a better solution I would love to hear them!