View

DOM API for jQuery users

General hints on the DOM

  • the root of the DOM is document
  • custom elements inherit from HTMLElement. They need a - (dash) in their name, e.g. <notification-box>.
  • event listeners don't have event delegation à la .on('click', cssSelector, handler)

Comparison

Action jQuery DOM API equivalent
Find descendant(s) by CSS selector .find(selector) one: `.querySelector(selecto…
Repeats

Unpoly: Automatically show the full better_errors page when Rails raises an error

When an AJAX request raises an exception on the server, Rails will show a minimal error page with only basic information. Because all Unpoly updates work using AJAX requests, you won't get the more detailled better_errors page with the interactive REPL.

Below is an event listener that automatically repeats the request as a full-page load if your development error shows an error page. This means you get…

Repeats

RubyMine: Efficiently filtering results in the "Finder" overlay

RubyMine comes with a nice way to grep through your project's files: The finder (ctrl + shift + f). Don't be discouraged about the notice 100+ matches in n+ files if your searched keyword is too general or widely used in your project.

Image

RubyMine comes with a few ways to narrow down the resulting list, don't hesitate to apply those filters to speed up your search. Your keybinding might vary based on your personal settings.

File mask (alt + k)

If you already know the file extension of your …

Repeats

Webpack(er): A primer

webpack is a very powerful asset bundler written in node.js to bundle (ES6) JavaScript modules, stylesheets, images, and other assets for consumption in browsers.

Webpacker is a wrapper around webpack that handles integration with Rails.

This is a short introduction.

Installation

If you haven't already, you need to install node.js and Yarn.

Then, put

```ruby
gem 'webpacker', '~> 4.x' # check if 4.x is still cu…

Repeats

Capybara/Selenium: evaluate_script might freeze your browser, use execute_script

In a nutshell: Do not use evaluate_script. Use execute_script instead!


Capybara gives you two different methods for executing Javascript:

page.evaluate_script("$('input').focus()")
page.execute_script("$('input').focus()")

While you can use both, the first line (with evaluate_script) might freeze your Firefox window for 10 seconds.

The reason is that evaluate_script will always return a result. The return value will be converted back to Ruby objects, which in case of complex objects (e.g. a jQuery collection) is *ver…

Adding Jasmine JavaScript specs to a Webpack(er) project

The goal is to get Jasmine specs running in a Rails project using Webpacker, with the browser based test runner. Should be easily adaptable to a pure Webpack setup.

Image

Step 1: Install Jasmine

yarn add jasmine-core

Step 2: Add two separate packs

Since we do not want to mix Jasmine into our regular Javascript, we will create two additional packs. The first only contains Jasmine and the test runner. The second will contain our normal application code and the specs themselves.

We cannot…

Repeats

Cucumber: Clear localStorage after each scenario

Capybara clears cookies before each scenario, but not other client-side data stores. If your app is using localStorage or sessionStorage, contents will bleed into the next scenario.

Use this hook to remove all site data after each scenario:

After do
  if Capybara.current_driver == :selenium && !Capybara.current_url.starts_with?('data:')
    page.execute_script <<-JAVASCRIPT
      localStorage.clear();
      sessionStorage.clear();
    JAVASCRIPT
  end
end

Unpoly: Testing values for presence or blankness

In Ruby on Rails, all objects have a useful blank? method. It returns true for nil but also for empty strings or empty arrays. There is also a universal method present? which returns true for all values that are not blank?.

In JavaScript you need to roll your own implementation of blank? and present?.

If your application uses [Unpoly](…

LoDash: isBlank and isPresent mixins

When you need to check a value for presence, don't rely on JavaScript since it considers 0 or "0" false. Also don't rely on LoDash's _.isEmpty:

if ('0') { ... } // false
if (0) { ... } // false
if (!_.isEmpty('0')) { ... } // true (= good)
if (!_.isEmpty(0)) { ... } // false (= not good)

This is because isEmpty it is only meant for objects with a length.

While the name implies that it's meant only for collections, you probably still want something like isBlank or `is…

Repeats

Using regular expressions in JavaScript

Regular expressions in Javascript are represented by a RegExp object. There also is a regex literal as in many other languages: /regex/. However, they are used slightly differently.

Regex literal

  • Usage: /foo+/
  • Shorthand for creating a regular expression object

RegExp() object

  • Usage: Regexp("foo+") or new RegExp("foo+")
  • No surrounding slashes required (they're the literal markers)
  • Since the argument is a string, backslashes need to be escaped as well: RegExp("\\d+")

Gotchas

  • Regex objects [never eq…

Some hints on upgrading to Unpoly 0.60.0

Unpoly 0.60.0 removed the jQuery dependency to improve performance (see Hennings talk about Javascript without jQuery). I upgraded one of our applications which used a lot of JavaScript with Unpoly compilers and jQuery and want to mention some aspects I had trouble with:

Use up.$compiler as a first step

up.compiler now yields a native DOM element instead of jQuery element. In order to get the old behavior, use up.$compiler. This is u…

Repeats

Events triggered by jQuery cannot be observed by native event listeners

jQuery has a function $.fn.trigger(). You can use it to dispatch an event on a jQuery object:

let $element = $('.foo')
$element.trigger('change')

A caveat is that such an event will be received by jQuery event listeners, but not by native event listeners:

let $element = $('.foo')

$element.on('change', event => console.log('I will be called'))
$element[0].addEventListener('change', event => console.log('I WON'T be called'))

$element.trigger('change')

This is currently a WONTFIX for jQuery (see c…

How to: Migrate from CoffeeScript to ES6

It is quite easy to migrate from CoffeeScript to ES6. You can use decaffeinate to convert your CoffeeScript source to modern JavaScript.

Installation

  • Install the NPM module globally yarn global add decaffeinate
  • Add the following line to your ~/.bashrc to export the Yarn binaries in your Bash
export PATH="$PATH:$(yarn global bin)"
  • Run decaffeinate some.coffee to get the converted modern JavaScript file.

Notes

  • decaffeinate will add some [suggestions](https://gith…
Repeats

Webpack: Automatically generating an icon font from .svg files

Over the years we have tried several solution to have vector icons in our applications. There are many ways to achieve this, from SVGs inlined into the HTML, SVGs inlined in CSS, JavaScript-based solutions, to icon fonts.

Out of all these options, the tried and true icon font seems to have the most advantages, since

  • icon fonts are supported everywhere
  • they perform well and require no JavaScript at all
  • their icons align nicely with text
  • their icons automatically inherit color and size of the surrounding text

The big issue used to b…

Webpack: How to split your bundles

To keep JavaScript sources small, it can sometimes make sense to split your webpack bundles. For example, if your website uses some large JavaScript library – say TinyMCE – which is only required on some select pages, it makes sense to only load that library when necessary.

In modern webpack this is easily doable by using the asynchronous import function.

Say we have an unpoly compiler that sets up TinyMCE like this (code is somewhat simplified):

```
// TinyMCE as part of the main bundle!

import tinymce from 'tinymce/tinymce'

// UI
im…

Cucumber: Inspecting the Chrome download folder to test file downloads with Selenium

We already have some approaches on how to test file downloads withe selenium. Nonetheless here is another approach, which inspects the Chrome download folder. This way you do not need a separate logic on whether a file is served from a controller or a public path. The DownloadHelpers might also be re-used for reading e.g. a PDF file and checking its content.

Note: The step below will override a [spreewald step](https://gith…

Repeats

Webpack(er): Analyze the size of your JavaScript components

We're always striving towards keeping our website's JavaScript as small as possible.

If you're using webpack(er), you can use the webpack-bundle-analyzer plugin to get a good overview, which of your JavaScript modules take up how much space, and where you can optimize.

To use it, add it via npm or yarn

yarn add webpack-bundle-analyzer

Then add this to your environment.js:

```
// Uncomment this code to show statistics of bundle sizes. Generated file will automatically o…

SameSite Cookies

The SameSite cookie attribute was first drafted in 2016. It defines under which circumstances a cookie should be sent to the server, putting cookies into three different classes:

SameSite variants

SameSite=None

Send the cookie whenever a request is made to the cookie domain. A cookie without the SameSite attribute will currently be handled as if it was sent with SameSite=None.

Note: Googl…

This website uses cookies to improve usability and analyze traffic.
Accept or learn more