codelord.net

Code, Angular, iOS and more by Aviv Ben-Yosef

CSS Tip: Stop Your Buttons from Flickering

| Comments

With the rise of flat design and it taking over the whole web, I’ve got this pet peeve with buttons that “wiggle” on hover. It’s becoming more and more common to have buttons where in one state they are flat and just have a nice background color, and in the hover state the background color changes and a border is added. Let’s have a look:

The CSS looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
.wiggle-button {
    height: 3em;
    width: 20em;
    background: #007aff;
    border-radius: 5px;
    color: white;
}

.wiggle-button:hover {
    background: white;
    color: #007aff;
    border: 1px solid #007aff;
}

As you can see, hovering over the button causes it to wiggle, and the rest of the content below it to move. Not good enough.

The problem is caused because the button has no border on the regular state and a border is added on hover. The new border adds to the actual height and width of the button, making it wiggle and push all elements after it.1

I’ve seen CSS newbies solve this by adding a border with the same color to the normal state, which would work, but isn’t to my taste.

Whenever you want to have an element’s size not change due to inner changes such as borders, paddings, etc. you’re actually thinking about box-sizing: border-box.

So, just adding box-sizing: border-box to our .wiggle-button class gives us this new sexy button:

This is a cleaner solution, in my opinion, since it makes sure the border doesn’t cause size changes to the button. This magical attribute solves our problems in this case just like that, and is supported on all latest browsers2.

I hope you learned something new. Happy coding!

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!


  1. See here for calculating a CSS element’s size

  2. Some browsers need a vendor prefix, see full information here

Stop Using Key Up Events When You Don’t Need To

| Comments

A common task for web developers is capturing the case where the user presses the enter/return key on his keyboard when filling out a form, instead of clicking the “submit” button.

I’ve seen many, many developers reach for the key press events and check whether enter was pressed (oh, char code 13, how I hate you). That of course works, but is nasty. Here’s is an example using Angular.js (which I’m sure you can translate easily to your favorite way of doing this, such as jQuery’s .keyup()):

1
2
3
4
<div class="sign-up-section">
    <input type="email" ng-model="email" ng-keyup="signUpIfEnterPressed($event)">
    <button ng-click="signUp()">Sign up</button>
</div>
1
2
3
4
5
6
7
function signUpIfEnterPressed(event) {
    if (event.keyCode == 13) {
        signUp();
        return false;
    }
    return true;
}

And of course, as you can see, signUpIfEnterPressed() is a function that has to check the event’s keyCode and compare it to the value of enter (13) and then, and only then, call the signUp() function. Bleh. Not good enough!

Turns out the people who wrote browsers already did most of the work related for us, we just have to reach out and use their work.

The trick is basically that the <form> element already is listening for these enter presses on all the inputs inside it. Pressing enter in an input in a form triggers the form’s submit event to be fired.

That means that we can now cleanly remove signUpIfEnterPressed() and replace the code with:

1
2
3
4
<form class="sign-up-section" ng-submit="signUp()">
    <input type="email" ng-model="email">
    <button type="submit">Sign up</button>
</form>

And of course the solution is pretty much the same regardless of what JS libraries you’re using (e.g. in jQuery you can do $('.sign-up-section').submit(signUp)), since this is purely done by the browsers.

Happy coding!

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Adapting Scroll Views to iOS 7

| Comments

In order to get to know some of the differences in iOS 7 and practice transitioning from iOS 6, I decided to transition a little toy app that consisted of a screen similar to the Messages.app: a navigation bar, most of the screen taken by a scroll view with content and on the bottom a text view and a button for adding more content to the scroll view. The app is extremely basic, but resizes properly when the keyboard is shown and, as in Messages.app, scrolls to the bottom of the content when the text view is focused and when a new message has been added.

I put together some of the things that weren’t obvious at first. It might be just me, but I’m hoping other developers will find this useful.

Handling navigation bar on top of our scroll view

The iOS 7 view of course comes with the new look where scroll views go under the navigation bar for a nice effect. One can change the scroll view’s contentInset manually to cover for the portion of it that is being overlapped at the top, but doing so manually is tedious and not fun. I was very thrilled to discover handling it should come at no cost if my ViewController has automaticallyAdjustsScrollViewInsets set to YES.

This didn’t work for me out of the box since it turns out for the magic to happen the scroll view has to be the first subview of your ViewController’s UIView. I had to reorder my subviews and then the magic started rolling.

Resizing when keyboard shows up

In my iOS 6 version, my app responded to the keyboard appearing with autolayout: I’d adjust the constraint holding the bottom view to go up by whatever the height of the keyboard is, which would cause the scroll view to shrink as well automatically. I liked this solution since it repositioned everything on the screen pretty easily.

The idiom for iOS 7 though is to place the scroll view across the whole screen, and placing the text view above it. Then, resizing for the keyboard should not actually change the height of the scroll view, but instead change its content insets. This is preferable since it means that scroll view’s content is still below the keyboard which is now semitransparent and so everything looks cool and shiny.

Layout of the scroll view, before and after:

So after I dragged things in Interface Builder to their new locations I changed the autolayout constraints: the text view is pulled up when a keyboard appears using a constraint as before, but that does not cause the scroll view to shrink. Unfortunately, content insets can’t be controlled with constraints and so I was forced to add more code the the keyboard handling that changes the insets manually. Apple’s Text Progamming Guide instructs to do this:

1
2
3
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;

This is actually a bit problematic since it overrides the top inset and thus screws up the inset put there by automaticallyAdjustsScrollViewInsets, so I changed the code to:

1
2
3
4
UIEdgeInsets contentInsets = UIEdgeInsetsMake(
    scrollView.contentInset.top, 0.0, kbSize.height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;

Animating resizing and scrolls

This is actually pretty basic stuff, except for the fact that in iOS 7 the keyboard’s appearance animation is using a new undocumented curve function. This means that it’s no longer enough to grab the animation duration from the keyboard notification, but one must also grab the animation curve from it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[info[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[info[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
[UIView setAnimationBeginsFromCurrentState:YES];

self.textViewKeyboardConstraint.constant = height;
UIEdgeInsets insets = UIEdgeInsetsMake(
    scrollView.contentInset.top, 0, textView.bounds.size.height + height, 0);
scrollView.contentInset = insets;
scrollView.scrollIndicatorInsets = insets;
[view layoutIfNeeded];

[scrollView setContentOffset:CGPointMake(0, newOffset) animated:NO];

[UIView commitAnimations];

Summary

The steps needed to make the transition are not complicated, but not trivial at first sight (well, at least they weren’t for me). I’d love to hear and see how other people have made these transitions, or even be shown that I did some stupid stuff here :)

Please Use Labels Properly

| Comments

Another issue that I frequently see junior web developers have trouble with is proper use of the <label> element.

First, let’s have a look at a lousy, label-less control:

1
<input type="checkbox"> This is my sucky control

This is my sucky control

To check that box one has to carefully aim her cursor to a tiny square with ninja-like precision. Doable, but no fun.

Many think that labels are just a semantic element for writing text next to controls and so just don’t use them. After all, if we wrap the above text so it becomes <label>This is my sucky control</label> nothing changes, so why bother?

Enter: labels

Labels are a magic way of getting the browser to do work for you. Connecting a label with an input field has some magic effects:

1
2
<input type="checkbox" id="check">
<label for="check">This is my better control</label>

All of a sudden we can also click on the text and the checkbox will change value! Life have just become that easier. Labels are also used for different accessibility measures.

Awesomer labeling

There’s another syntax for associating labels with inputs which I prefer. The problem with the above syntax is that it requires us to have a specific ID for each input element to then put in the label’s for attribute. This is usually messy and even requires extra coding if, for example, you’re generating forms on the fly.

Lucky for us, if a label contains a single input element it is automatically associated with it, meaning we can now write:

1
2
3
<label>
    <input type="checkbox"> This is my awesome control
</label>

Happy coding!

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

CSS Tip: Overflowing with Text

| Comments

Simply making sure some text that might be long doesn’t break our layout is trivial, but I’ve seen several CSS newbies have trouble with this or simply miss it altogether just to have QA (or worse, a user) file a bug about it.

The naive approach is usually just adding a width to the element and assume the problem is solved. But that is not so, my friends:

Some longer than expected text

1
2
3
<div style="width: 10em;">
    Some longer than expected text
</div>

As we can see, the text is causing the element’s height to increase. Assuming that’s going to work with our layout, you might assume we’re all ready to go. But are we, really?

Some longer than expected text with antidisestablishmentarianism

1
2
3
<div style="width: 10em;">
    Some longer than expected text with antidisestablishmentarianism
</div>

Ah, it’s leaking there. We can of course add overflow-x: hidden but what if we want all the content to be displayed? That’s, my friends, a job for word-wrap: break-word:

Some longer than expected text with antidisestablishmentarianism

1
2
3
<div style="width: 10em; word-wrap: break-word;">
    Some longer than expected text with antidisestablishmentarianism
</div>

OK, that seems to work (note: you can make the text hyphenated on some browsers). Now, stepping back a bit, what if we can’t have it take multiple lines? We can limit that too by adding a height to the element:

Some longer than expected text

1
2
3
<div style="width: 10em; height: 1.2em;">
    Some longer than expected text
</div>

Bummer. Oh, I know! Let’s add overflow-y: hidden:

Some longer than expected text

OK, this seems to do the trick. Or does it?

Now a long woooooooooooooooooooooooooooooooord

1
2
3
<div style="width: 10em; height: 1.2em; overflow-y: hidden;">
    Now a long woooooooooooooooooooooooooooooooord
</div>

Humph. A horizontal scroller even though the displayed contents aren’t that long. Guess we’ll have to go with overflow: hidden altogether then:

Now a long woooooooooooooooooooooooooooooooord

1
2
3
<div style="width: 10em; height: 1.2em; overflow: hidden;">
    Now a long woooooooooooooooooooooooooooooooord
</div>

OK, I think I’ll stop pulling your leg. I’ll just add that I like adding an ellipsis for making it clear that some text was trimmed with text-overflow: ellipsis. Problem is that text-overflow only works on single-line content, so we have to make sure our element’s text doesn’t wrap by also adding white-space: nowrap:

Now a long woooooooooooooooooooooooooooooooord

1
2
3
<div style="width: 10em; height: 1.2em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
Now a long woooooooooooooooooooooooooooooooord
</div>

Overflow away :)

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Rails 4 with Ruby 2 on Heroku

| Comments

A few days ago I started a new project, and thought why not go with the latest and greatest, Rails 4 and Ruby 2.
Surprisingly I had to copy-paste snippets from several different places in order to get everything up and running.
In an effort to make that time go to good use, I put up a simple 3 page guide showing the steps I had to take to get it to work, just in case anyone else needs it.

You can find the guide here.

Edit: Well, the guys at Heroku are fast! Their tutorial now contains most of the pitfalls I talk about in my guide and will work for everyone that already knows how to get Ruby 2 on their computer.

Let me know if you found it helpful!

Do-It-Yourself Twitter Triggers for IFTTT

| Comments

I like twitter, but some parts of it, like the fact you simply can’t get all of your past tweets once you go over 3000 or so, make me crazy. Once I realized twitter data is write only, I started backing up my tweets and favorites to Evernote using the great IFTTT service.

A few months ago twitter’s changes caused IFTTT’s twitter triggers to no longer work. I quickly hacked up a workaround using the deprecated twitter RSS feed API and blogged about it.

A week ago twitter finally took down the deprecated API, rendering my hack useless and me IFTTT-less once more. I saw no simpler way than writing my own little server that uses twitter’s new API to actually fetch my twitter streams as JSON and translate them into RSS so that I could easily wire that up to IFTTT.

Lucky for me it required less than one hour and roughly 50 lines of code. Setting it up on heroku is free and works smoothly so far. In case you would like to use such a server yourself I’ve made the code public with instructions to do so here.

Hope you find this helpful!

Optimizing Angular Templates with Grunt on Heroku

| Comments

So it’s been a few months now of developing with AngularJS and we finally needed to do some optimizing. Specifically, we felt the need to bundle the dozens of separate HTML template files into a single file to save time on roundtrips to the server (especially with the latency heroku’s servers are showing in Israel).

Some googling showed that the best solution would be to use Grunt with grunt-angular-templates. Since we couldn’t easily find a complete example for Grunt newbies, I thought I’d share what we came up with. It might not be perfect, but it seems to work!

First we created a package.json file with the needed grunt dependencies and made sure to add a postinstall step that runs grunt. Turns out that heroku’s node buildpack runs that step after each deploy:

package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
  "name": "MyApp",
  "version": "0.1.0",
  "dependencies": {
    "grunt": "~0.4.1",
    "grunt-cli": "~0.1.9",
    "grunt-contrib-jshint": "~0.1.1",
    "grunt-contrib-nodeunit": "~0.1.2",
    "grunt-angular-templates": "~0.3.8"
  },
  "scripts": {
    "postinstall": "./node_modules/grunt-cli/bin/grunt"
  }
}

And then we just created a straightforward Gruntfile.js with the appropriate options for grunt-angular-templates specifying which files to bundle and where and the grunt boilerplate for telling it to run that task by default:

Gruntfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    ngtemplates: {
        myapp: {
            options: {
                base: "web",
                module: "app",
            },
            src: "web/templates/**/*.html",
            dest: "web/js/templates.js"
        }
    }
  });

  // Load the plugin
  grunt.loadNpmTasks('grunt-angular-templates');

  // Default task
  grunt.registerTask('default', ['ngtemplates']);

};

And that’s it!

Also, if by any chance you, like us, don’t use Node for the server but still want to use the node buildpack for grunt’ing stuff for the client-side, and still need some stuff for the server buildpack, there’s a solution for you! There’s a buildpack called heroku-buildpack-multi that allows you to use multiple buildpacks for your project. Just switch your project to use it and then create a matching .buildpacks file. For example, for our Python tornado + Angular project it looks like:

.buildpacks
1
2
https://github.com/heroku/heroku-buildpack-python.git
https://github.com/heroku/heroku-buildpack-nodejs.git

Have fun! For more in-depth Angular stuff you might find this book useful.

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

My First 5 Minutes Learning AngularJS

| Comments

There’s been some debate online this week about how hard or easy it is to learn Ember. It just so happened that a couple of days ago I spent a couple of hours starting to learn about AngularJS and I thought I’d share how the first 5 minutes went.

I started learning with the nice screencasts on Egghead.io. I then reached a screencast with the following code snippet:

1
2
3
4
5
6
7
8
9
10
11
12
var myApp = angular.module('myApp', []);
myApp.factory('Data', function () {
    return {message:"I'm data from a service"};
});

function FirstCtrl($scope, Data) {
    $scope.data = Data;
}

function SecondCtrl($scope, Data) {
    $scope.data = Data;
}

In that code, it’s explained, we define what “Data” is and when AngularJS sees a controller that uses Data, such as our FirstCtrl and SecondCtrl, it will inject it. At this point my partner and I stopped in our tracks together and noticed some unknown magic is happening. After all, neither of us knew of a way in JavaScript to see how a function’s arguments are named, and so how can AngularJS use that for injecting?

After googling a bit we came across a StackOverflow answer that said a function’s toString method can be used to parse out the argument names. Staring at each other puzzled, we didn’t want to believe it, saying there’s no way that’s what’s going on. Then he suggested I override FirstCtrl.toString and lo and behold, the injection broke.

Now that’s some magic that I joked was “even too much for DHH”, and I find it hard to believe anyone that knows a bit of JavaScript can start learning AngularJS without going through what we just did. But then, we realized something more.

Most sites, on production, minify js files in a way that mangles names. How is that supposed to work with this sorcery? Googling some more we found in the AngularJS docs that there’s simply a workaround, a different syntax that’s used in a way that survives minification.

Now don’t get me wrong, I’m just starting to get to know AngularJS, and it looks like it has some really nice features, but having to go through this whole ordeal the first 5 minutes I’m learning something new, only to realize that syntax is actually useless and that I’ll never use it, is weird. It made me feel as if someone wanted to put in a “cool” feature, and when they noticed it actually won’t work for most production uses they left it in for the coolness factor, instead of removing it.

The bottom line is, no project is perfect, and usually once you’ve already learned something, it looks so much simpler than the rest!

You should follow me on twitter!

Don’t allow your team to just go through the motions

| Comments

So many people I know claim to be doing agile, and are crafting software, and whatever. Unfortunately, from my experience it is clear that while everyone like saying they do stuff, they aren’t actually doing it.

Going through the motions, instead of understanding what you’re doing, is basically useless. The only way to get better at something is through introspection, that requires you to be aware of your actions and the wanted outcomes.

Some examples:

Do the people on your team know why you have to stand up at the daily standup? Are members told what kind of information to share and what not? Or is it simply 10 minutes of everyone not listening?

Does your team pull up estimates for tasks? Why? Do you look at the estimates at the end of an iteration? Will you cut features in case the estimations show you won’t complete all the tasks?

Are your automatic tests valuable? I’ve seen mountains of useless tests that do not aid refactoring, super slow or simply just don’t really test anything. If people don’t understand why they’re writing them, how can you expect them to write good ones?

Are your retrospectives just 30 minutes that you’re waiting to get over with, with basically no action items that change things?

There’s a reason software developers have grown to hate process, and it’s because most of the times process is just that, stuff that needs to be done without a lot of benefit or apparent logic. Make sure you and your team know why you’re doing stuff, that’s the only way to get better.