Today I Learned

How to access refs outside a VueJs template

Sometimes you need to make use of the ref attribute to access a child component in VueJs, like so:

<input ref="someRefName"></input>
this.$refs.someRefName

But what if you need to do the same thing for an html element that's still inside your app but outside of your VueJs template or component? Maybe you've tried it and this.$refs.someRefName comes in undefined.

That's when the $root instance comes in handy. Just add the ref attribute on the target element and access it in your VueJs component like this:

this.$root.$refs.someRefName

That makes VueJs look for that reference in the root instance of your app, and not only inside your component.

Just make sure you don't overuse it. Most of the times, there's a better way to do what you need to do.

How to force a flexbox item to a new row

At some point you might end up with a challenge like this. You've got several items (we'll take an example of 3) laid out with flexbox.

<div class="container">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>

The items have fixed width and they all fit on one row, but you want the third to jump on the second row.

Like this:

====item====item====
========item========

So how do you make them stack 2 on the first row, and the third on the second row, centered to the middle?

If you try flex-wrap: wrap, depending on the device resolution, it might do the trick or not. If all 3 fit on the same row, they won't wrap.

The solution is to force them by adding a collapsed row (height 0) which takes up the entire width of the container, making it occupy an entire row, thus pushing the 3rd item on the next row. Think of it like a <br> tag.

<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="break"></div>
  <div class="item"></div>
</div>
.break {
  flex-basis: 100%;
  height: 0;
}

Neat trick, right?

And it can be adapted to other situations as well, not necessarily flexbox.

Getting exif metadata from image base64

Exif headers provide useful metadata when it comes to images such as the image's orientation.

If you have used / are using Intervention Image, you might have noticed that some of the pictures you upload are turned from portrait to landscape.

If you upload the image normally, in Laravel you can orientate the image properly like so:

Image::make(Request::file('image'))->orientate();

But if you get the image data as a base 64 string this approach won't work, but the following snippet can be used to get the desired information from the image

$stream_resource = "data://image/jpeg;base64," . $base_64_image_string;
$exif_meta = exif_read_data($stream_resource);

You can now get the image's orientation and act based on it's value

$orientation = $exif_meta["Orientation"];

Also, make sure you have this line in you php.ini file

allow_url_fopen=On

Otherwise you will get

ErrorException: exif_read_data(): Unable to open file in file [filename]

Remove a non-removable MDM profile from macOS without a complete wipe

Non-removable MDM profiles cannot officially removed without doing a full system wipe. This is a problem when you restore a system from Time Machine after you enrolled it into the MDM, as the MDM will break, leaving you unable to re-enroll the machine.

Here's how to remove a non-removable MDM profile

  1. Boot the Mac into Recovery Mode (hold down command+R during startup).
  2. Go to the Utilities menu and open Terminal and type: csrutil disable. This will disable SIP (System Integrity Protection).
  3. Reboot into the OS.
  4. Open the integrated terminal and type:
cd /var/db/ConfigurationProfiles
rm -rf *
mkdir Settings
touch Settings/.profilesAreInstalled
  1. Reboot.
  2. Boot the Mac into Recovery Mode (hold down command+R during startup).
  3. Go to the Utilities menu and open Terminal and type: csrutil enable. This will re-enable SIP.
  4. Reboot into the OS.

The profile will be now removed and you will be able to re-enroll the Mac to your MDM.

How to remove a VPN profile on a MDM enrolled macOS

Restoring from a Time Machine backup can create duplicate MDM VPN profiles.

To manually remove a profile on your macOS, follow these steps:

  • Go to System Preferences and select Profiles.
  • Delete the VPN profile, and enter the user password if requested.
  • Then, go to Network Connections.
  • If you see any connections which start with or include “VPN”, delete them.

Note

If the Button isn’t available,you have to use a terminal command to remove it. Open the integrated Terminal and type

networksetup -removenetworkservice "duplicateVPNProfile"

Using destructuring assignment to dynamically create new functions in JavaScript

// www.codewars.com/kata/525f3eda17c7cd9f9e000b39

const curry = (operand, operator) => (!operator) ? operand : operator(operand);

const [zero, one, two, three, four, five, six, seven, eight, nine] =
  [0,1,2,3,4,5,6,7,8,9].map(operand => ((operator) => curry(operand, operator)));

const plus = (first) => (second) => second + first;
const minus = (first) => (second) => second - first;
const times = (first) => (second) => second * first;
const dividedBy = (first) => (second) => Math.floor(second / first);

Prepare NuxtJS for static deployment

In order to deploy Nuxt as a static website you need to:

  1. Upgrade nuxt to 2.14.0
  2. Set target: 'static' in your nuxt.config.js
  3. Set fallback 404 page:generate: { fallback: '404.html' }
  4. Run nuxt generate

You then need to tell Nginx to properly handle slashes for subpages:


    location /.
    {
        # Remove trailing slash and redirect it
        rewrite ^(.+)/+$ $1 permanent;
        
        # Redirect index.html
        rewrite ^(.+)/index.html$ $1 permanent;
        
        # Serve folder path via index.html
        try_files $uri $uri/index.html =404;
        
        # Serve a custom static error page
        error_page 404 /404.html;
    }

Follow URL redirects from the Terminal

Sometimes you need to follow an url trough multiple redirects. I've created a simple script you can alias into your .bashrc or .zshrc file and then just use it as a regular shell command:

Add this line to .zshrc or .bashrc

# Follow URL
alias checkurl='_checkurl() { curl -v -L $1 2>&1 | egrep "^(> Host:|> GET|> Code|< HTTP|\* SSL)"}; _checkurl'

Then you can use it like so:

checkurl google.com

it will output this:

> GET / HTTP/1.1
> Host: google.com
< HTTP/1.1 301 Moved Permanently
> GET / HTTP/1.1
> Host: www.google.com
< HTTP/1.1 200 OK

Really useful when debugging URLs.

How to add dynamic images in NuxtJS & VueJS

Let's say you have a simple component in NuxtJS and VueJS, a static image for a blog post.

<template>
  <article class="post__image">
    <img class="image" src="~/assets/images/imageName.jpg" alt="post picture">
  </article>
</template>

Simple enough, right? But you don't want to have the same image for every blog post, so maybe you're trying to add it dynamically, getting the image name through a prop and using Vue's v-bind directive, like so:

<template>
  <article class="post__image">
    <img class="image" :src="`~/assets/images/${imageName}.jpg`" :alt="`${imageName} picture`">
  </article>
</template>

<script>
export default {
  name: 'PostImage',
  props: {
    imageName: String
  },
}
</script>

And then you notice that that doesn't work. But why? The vue syntax is correct, so what's the problem? Well, there's something else at play here.

Behind the scenes, webpack replaces the image path with a module request at build time. That's fine for static images, because their paths are known at build time, but for dynamic images it's a different story, as webpack can't know what their paths will evaluate to at run time, so that won't work.

The solution is to make a module request for the images, so that webpack can work its magic on them before loading them on the page. That's done by using require(...), with the correct image path.

So your images will have to be loaded like this:

<img 
    class="image" 
    :src="require(`~/assets/images/${this.imageName}.jpg`)" 
    :alt="`${imageName} picture`"
>

You could also clean that up a bit, and extract the require part into a computed property, for better readability:

<template>
  <article class="post__image">
    <img class="image" :src="imageSource" :alt="`${imageName} picture`">
  </article>
</template>

<script>
export default {
  name: 'PostWithImage',
  props: {
    imageName: String
  },
  computed: {
    imageSource() {
      return require(`~/assets/images/${this.imageName}.jpg`)
    },
  }
}
</script>