Angular 1 (ng1) vs Angular 2 (ng2) Two-Way Data-Binding for (nested) Components in 2017

Update: An article focusing more strongly on Angular 2 can be found here https://www.bersling.com/2017/05/24/communication-between-components-in-angular-2/. It also elaborates the observables concept in more detail.


Two-Way Data-Binding has long been one of the unique selling points of Angular 1 (ng1 in the following), until people started to complain that it slows down the apps too much. This was one of the core reasons, why the Angular Team opted to create Angular 2 (ng2 in the following): to make Angular faster by “removing” two-way data binding. But did they really remove it? And what’s the suggested way of data binding then? That’s the topic which we’ll tackle here.

Let’s start with a common misconception:

In ng2, the parent holds the data and the child can’t modify it.

That’s not entirely correct. Correct would be:

In ng2, property bindings (the ones with square braces [] ) are PASSED BY REFERENCE. Therefore the data / view is updated app-wide, when a field of a bound object is changed.

Let me prove this to you in the following ng2 app:

This was achieved by simply using

[(ngModel)]="item.name"

on the innermost element. So wait, didn’t I read like 1 Million times that when I pass down an object with [] that the child can’t modify it? Well yes, but that’s a lie. The child can modify it because it’s passed by reference, unless it’s a string or a number or another primitive that’s passed by value. Let’s capture the difference:

ng2 and ng1 data binding are only different in case of the entire bound object being replaced. This is always true for strings, numbers, booleans and other primitives.

In the example above, this would mean if I clear or reassign (e.g. item = {} ) on any nested child, I break the link of the updates in ng2 but NOT in ng1. ng1 will look through all components, searching for item in order to update it.

Okay, so this begs some questions.

  • Is modifying the data in a child-component encouraged?
  • What kinds of problems could arise leveraging the reference-binding?
  • What should I do when I need the parent to do something on the change of the data?
  • What should I do if I don’t have an object, but instead primitives, or I want to swap the entire object?

A lot of questions. Let’s first do a quick recap of the “old way” of doing two way data binding in ng1, and then looking at the new, recommended way(s).

Angular 1 two-way data-binding in components

Here’s a quick reminder how two-way binding in ng1 worked. Let’s say we have a wrapper component, holding two child components: one to edit the data and one to display the data of the wrapper.

<my-prop-wrapper my-prop="myProp">
  
  <edit-my-prop my-prop="myProp"></edit-my-prop>
  <display-my-prop my-prop="myProp"></display-my-prop>
  
</my-prop-wrapper>

The display got immediately updated when you bound my-prop to the directive like so:

scope: {
  myProp: '='
}

But this won’t work in ng2, since communication only happens from parent to child in property binding. The edit-my-prop directive doesn’t propagate changes upwards to the parent and then from the parent back to the display anymore. You’ll have to do that yourself. So how can you do it?

“Official” ng2 way to update data across components

In order to get the information from the edit to the display, you’ll  somehow need to get the wrapper to listen to events in the edit. In ng2 a [] bracket signifies a flow of information from parent to child and a () bracket signifies a flow from child to parent. So your template would need to look like so:

<my-object-wrapper my-object="myObject">
  
  <edit-my-object [myObject]="myObject" (myObjectChanged)="doOnChange($event)">
  </edit-my-object>
  <display-my-object [myObject]="myObject"></display-my-object>
  
</my-object-wrapper>

The display only needs to receive information (i.e. []), but the edit needs to receive and emit information. Now inside of the edit-compontent.ts (or whatever name it may have), the emission of information must be triggered. How? With ng2’s EventEmitter and Output classes. Import those into your file, then:

@Output() myObjectChanged = new EventEmitter();

You can then trigger an event by myObjectChanged.emit({value:this.myObject}).

This will trigger the doOnChange Function in the parent, which could for example do the following:

doOnChange(evt){
  this.myObject = evt;
}

HOWEVER, notice that it doesn’t have to be done like this. You could just as well utilise the Observable Pattern with RxJS. That’s actually what I’d recommend you to do, we’ll discuss it in a moment.

How you could do it in ng1, like you would do it in ng2

In ng1 we can bind properties with =, with @ and with & . I personally never really used & since there’s already too many concepts, but with this you can simulate the ng2 behaviour.

For example you can have in your parent template

bla bla <inner do-on-event=myFn($event, someData)></inner>

and then bind it to the child (called inner here) like so (in typescript):

<button ng-click="omgImClicked($event, 'cool stuff')">Click me</button>
bindings: {
  doOnEvent: "&"
}
...
public omgImClicked(e, data) {
  doOnEvent({
    $event: e,
    someData: data
  });
}

In case you were like “wtf” here a lot, maybe read this article: http://www.codelord.net/2016/05/13/understanding-angulars-and-binding/

However, note that this can become cumbersome quickly, as components become nested!

Deeply Nested Components

As you write a complex app and reuse more and more components, the components get smaller and and more nested as part of a process. So it’s important to understand how nested components will work.

Function Binding in ng1 (not recommended)

In ng1, if you want to go with the function binding approach, you’ll have to do something like the following. Let’s say we have a somewhat complex update function in our “data owner”:

public updateTask(updateInformation: {
  task: Task,
  field?: TaskProperty,
  listindex?: number
}) {

  let errorFn = (errorResp) => {
    this.Notify.errorResponse(errorResp);
  };

  let successFn = (resp) => {
    this.task = angular.copy(resp.data.task);
  };

  if (!updateInformation.field) {
    this.TaskService.update(updateInformation.task).then(successFn, errorFn);
  } else if (!updateInformation.listindex) {
    this.TaskService.updateProperty(updateInformation.task[updateInformation.field], updateInformation.task, updateInformation.field).then(successFn, errorFn);
  } else {
    this.TaskService.updateListItem(updateInformation.listindex, updateInformation.task[updateInformation.field][updateInformation.listindex], updateInformation.task, updateInformation.field).then(successFn, errorFn);
  }

}

I’ve already aligned this for proper usage for passing down with &, since if you would use multiple arguments instead of a json, you’re gonna have a bad time. Well actually, if you use this method you’re gonna have a bad time anyways.

youre-going-to-have-a-bad-time

This is because you’ll have to define a new function in every nested component, if you use multiple arguments. You’ll see what I mean if you try it out, but I’ll spare you this here.

Next, in the template we can call it like this:

<child update-task="$ctrl.updateTask({task: task, field: field, listindex: listindex})">
</child>

and then in the grandchild we could also use

<grandchild update-task="$ctrl.updateTask({task: task, field: field, listindex: listindex})">
</grandchild>

(exactly the same!). Let’s say the event happens in the grandchild, so we could use something like:

public updateTitle() {
  this.updateTask({
    task: this.task,
    field: 'title'
  });
}

Well, that’s it.

Anyways, I have a few problems with this passing down of an “updating function”, which now seems to be the recommended way:

  • It’s a second “update-object/function”, alongside the main object task that needs passing down. What used to be magic and nice with two-way binding, assuring my “task” was the same everywhere now requires a second object/function being passed around.
  • It’s a lot of duplicated entries (“field: field” etc), but that’s necessary for multiple arguments.
  • Those entries are in the html, how ugly is that?
  • When someone else reads my code, how is this person supposed to know what updateTask does?!?! Before it was kind of clear because I just used a service and the databinding took care of itself, but now I have to go 10 directives/components up to find the “owner of the data” and check what this owner intends to do with the data.

Using $emit (not recommended)

With emit, you’d let the child (or grandchild or whatever) “bubble up” and event. For example the innermost child can tell it’s parent “Hey I had an event, I made poopoo”. Then the parent can tell the grandparent and so forth, until the one responsible for cleaning up the poopoo will take care of the mess. This is also not really the best choice, since it’s semi-global events flying around. You’ll emit a string like OBJECT_CHANGED which then can be viewed by all parents up to the rootScope. When you accidentally give the same name to multiple events you’re going to have a bad time.

Using $broadcast (not recommended)

Instead of bubbling up with $emit, you could also broadcast an event from the rootScope. That’s also bad, since all the components with a listener $scope.on('BROADCASTED_EVENT') will react to this, so it’s global and, well, you’re going to have a bad time…

Using Observables with RxJS (RECOMMENDED)

The observable pattern is mighty, flexible and the way forward in many systems. Meteor, ng2 and ReactJS all adopt the concept, just to name a few. But observables aren’t just something you can have only in some frameworks, it’s basically just a programming pattern. And it’s quite simple, you just subscribe to events that are published. There is the framework agnostic library RxJS (Reactive Extensions for Javascript) that’s maintained by Microsoft and used by almost everyone dealing with observables in the Javascript World.

There’s plenty of pages explaining the nitty gritty of it, so here’s just the broader overview:

    1. You hold the data in a service. To do so, a kind of unique id/key is required to store the data in a map (key value pairs). Database entries are especially well suited for this, since they usually come with an id anyways.
    2. The service has a changeMyData method.
    3. The parent is subscribed to an observable in that service.
    4. When the service changes it’s data, the parent is notified, adapts its own data, and the changes are propagated to all children.

Here’s a quick example how you would go about data binding with RxJS.

In this example, a central item-service holds the data. It is always immediately clear who the “owner of the data” is (the service). It is also always clear where to apply the update, it’s also the service. What’s even nicer, the binding syntax becomes completely unnecessary. Notice how both <detail> and <remove-item> components don’t take any input properties, yet the object updates:

 <b>Angular 2 Component Using Observables!</b>
 
 <div style="border: 1px solid blue; padding: 5px; margin-bottom: 2px">
 <detail></detail>
 </div>
 
 <div style="border: 1px solid red; padding: 5px">
 <remove-item></remove-item>
 </div>

This is because <detail> listens to changes in the items stored in the item-service. That’s the simplest, cleanest and fastest approach if you ask me.

Of course this is only useful if we’re actually talking about data. If you have simple UI components that are like <my-circle color="red" size="15"></my-circle> it’s still simpler to just use property binding. But in the case of actual “data-objects”, like my-item it’s better use the approach with the service. As a rule of thumb, you could use:

If your object has an id, use the Observable + Service pattern.

Conclusion

As always in the fronend world, it’s a bit of a mess. Many concepts, many possibilities to achieve the same results, what’s the best choice? Some people would say “it depends”, but sometimes we say “it depends” too much because devs can only get really familiar with a certain number of concepts and some things are just plain stupid. The Front-End world is slowly consolidating towards observables for handling events.  And so should you.

WINNER: Observables with RxJS

6407041

Bootstrapping an Angular 1.5 Component with Typescript

Angular 1.5 introduces the “Component” concept in order to get closer to Angular 2. By now you might have started to use typescript in your project, but upgrading to Angular 2 was too big of a step. However, you can start writing “Components” in an exact-angular2-style. Here’s what you’ve got to do.

First of all you’re going to need the following code to make annotations work:

//component.ts
function Component(moduleOrName: string | ng.IModule, selector: string, options: {
  controllerAs?: string,
  template?: string,
  templateUrl?: string,
  bindings?: any
}) {
  return (controller: Function) => {
    var module = typeof moduleOrName === "string"
        ? angular.module(moduleOrName)
        : moduleOrName;
    module.component(selector, angular.extend(options, { controller: controller }));
  }
}

This will allow you to use annotations to define components.

A ready-to-use component can then be generated with the following scripts:

#creates skeletton
#argument: name in any case e.g. bla-bla or blaBla or BlaBla

pascalcase="$(node changecase.js ${1} pascalCase)"
paramcase="$(node changecase.js ${1} paramCase)"
camelcase="$(node changecase.js ${1} camelCase)"

mkdir WebContent/components/directives/${paramcase}

echo "
@Component('taskbaseApp', '${camelcase}', {
  templateUrl: '/components/directives/${paramcase}/${paramcase}-directive.html',
  bindings: {
    somebinding: \"<\" // One Way Binding
  }
})
class ${pascalcase} {

  public somebinding: string;
  static \$inject: string[] = ['Utils'];

  constructor(private Utils) {}

  public sayHello() {
    console.log('hi')
  }

}
" >> WebContent/components/directives/${paramcase}/${paramcase}-directive.ts


echo "<div class='${paramcase}-wrapper'>

  <button class=\"btn btn-default\" ng-click=\"\$ctrl.sayHello()\">Hello {{\$ctrl.somebinding}}</button>

</div>" >> WebContent/components/directives/${paramcase}/${paramcase}-directive.html


# Compile
cd WebContent/components && tsc

echo "Usage:

<${paramcase} somebinding=\"'World'\" ></${paramcase}>

"

and

//changecase.js
var changeCase = require('change-case');

var caseType = process.argv[3];
var inpt = process.argv[2];
console.log(changeCase[caseType](inpt));

Note: You need to `npm install changecase –save` in order for the scripts to run first.

That’s all.

Migrating an Angular 1 app to Typescript with Modules

Migrating an Angular App to Typescript with optional ES6 Modules

I know, I know, Angular is pretty outdated, but some of us have apps in production running on Angular and would like to introduce typescript anyways… This being said, working with an Angular 1 app with typescript you’re in a really weird place right now. Half of the time when googling “angular typescript” stuff, you’ll find angular 2 answers, and in order to get angular 1 closer to angular 2, the angular team introduced even more concepts to the already overloaded angular 1… But that’s just how it is.

Assuming ui-router is your routing solution, here are the steps for migrating an existing angular app to typescript.

The Easy Way: Without Modules

1) Rename all your js files to ts files

That’s an easy one, just rename all the files. If you have many files, you could use something like the following python script:

import os

for path, subdirs, files in os.walk("./"):
 for name in files:
 oldPath = os.path.join(path, name)
 newPath = oldPath.replace(".js", ".ts")
 os.rename(oldPath,newPath)

2) Install Typings

Angular 1 is written in js not in ts. So in order to get code completion from your IDE and tell typescript the “angular” object exists, you need to get the type definitions. You could skip this step, but it’s not a lot of effort and prevents wiggly lines in your editor and errors from the ts compiler (but it would transpile anyway).  To do so, install “typings” and then run typings install with the following typings.json file:

{
  "globalDependencies": {
    "angular": "registry:dt/angular#1.5.0+20160819155010",
    "angular-ui-router": "registry:dt/angular-ui-router#1.1.5+20160810191828",
    "jquery": "registry:dt/jquery#1.10.0+20160704162008"
  }
}

If you don’t want modules, that’s kind of all there is to it.

3) Compile your code

Put this tsconfig.json at the root of your project

{
  "compilerOptions": {
    "target": "es5"
  }
}

and then run tsc in the command line (also from the root of your project). This assumes you have the typescript compiler installed.

The Hard Way: With Modules

If you don’t know the basics of ES6 modules, maybe it’s a good idea to read this article on typescript with ES6 modules first.

In order to get things running with modules, a little more work is required. Here is a complete working example, that will be discussed in the following.

To use modules, you’ll need a module loader, here we’ll use SystemJS. You can start setting up everying like without modules, except that your tsconfig should now be:

{
  "compilerOptions": {
    "module": "system",
    "target": "es5"
  }
}

4) Loading the Main FIle With SystemJs

For using modules, you want to have one main module that you import using SystemJs. But if you just import your “app.js” with SystemJs (like so System.import('app.js')), then it will break your app. The reason for this is that ng-app="myApp" (or however you called your app) will be loaded before app.js is loaded. So here’s the first step. One possible solution for this is to bootstrap manually, so your index.html would read:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Typescript Modules</title>
    
    <!-- get angular -->
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.min.js"></script>
    
    <!-- get systemJS from somewhere -->
    <script src="https://code.angularjs.org/tools/system.js"></script>
    
    <script>
      System.config({
        baseURL: './',
        defaultJSExtensions: true
      })
    </script>
    <script>
      System.import('app.js').then(function() {
        angular.bootstrap(document, ['myApp']);
      });

    </script>


  </head>
  <body>


    <div ui-view></div>
    <!-- We'll also add some navigation: -->
    <a ui-sref="state1">State 1</a>
    <a ui-sref="state2">State 2</a>

  
  </body>
</html>

Note how there is no ng-app attribute in this code anymore!

(Another other possibility is to also load Angular with SystemJS, but this is not discussed here)

5) Rewriting Your Controllers, Services, Directives and Components to Module Syntax

Since Angular 1.5  Components are the suggested way to do things, but let’s say you still have some 1.4 code and you’re using controllers… Then those controllers would have to be rewritten like so:

export class HelloWorld {

  static $inject = ["$scope"];

  constructor (private $scope) {
    $scope.name = "World"
  }

}

This is “not recommended” as you should use “controllerAs” syntax or components, but if you’ve got a lot of code, you’ll be just glad there is a way of doing it without “controllerAs” syntax

6) Importing

Now comes the fun part, you can import your controllers. This would be the app.ts :

import {HelloWorld} from "./hello-world";
import {GoodbyeWorld} from "./goodbye-world";

var myApp = angular.module('myApp', ['ui.router']);


myApp.config(function($stateProvider, $urlRouterProvider) {
  //
  // For any unmatched url, redirect to /state1
  $urlRouterProvider.otherwise("/state1");
  //
  // Now set up the states
  $stateProvider
      .state('state1', {
        url: "/state1",
        templateUrl: "partials/state1.html",
        controller: HelloWorld
      })
      .state('state2', {
        url: "/state2",
        templateUrl: "partials/state2.html",
        controller: GoodbyeWorld
      });

That’s it. That’s how you’d use modules with systemJS and typescript. Again, here’s the complete code: Final Code.

ES6 Modules and Typescript

The whole thing is still pretty crazy as of August 2016. If you want to develop your frontend with typescript, you’ll probably encounter all of those “things”:

bower, npm, node, grunt, gulp, typescript, tsconfig, tsc, transpile, es6, javascript2015, module, module loader, import, export, require, systemjs, amd, umd, commonjs, babel, traceur, browserify, webpack…

Those are just some things mixed together in a wild manner, but the sheer amount of tools & concepts is nuts.

Okay, so what’s the whole point anyways? You want to use typescript and this usually goes hand in hand with the import / export syntax. Import / export is from “es6” = “javascript2015”, but this javascript version is not fully supported by most browsers yet. And you don’t want to build your production app in a language that won’t run in most browsers. So what can you do? You can use something that does the following:

MAP ES6 to ES5

Who can do this? Babel, typescript and traceur for example. Forget about babel and traceur and use typescript.

But if you use import / exports in your code (i.e. modules) the es5 generated by typescript will not run by itself. Here you have two choices:

  1. Don’t use modules.
  2. Use a module loader.

Unfortunately there is no way around using a module loader, if you want to use import / export in your code. If you already have a large app, you have to think this through, as introducing modules implies quite a lot of refactoring. The rest of this article assumes you decided to use modules. A possible and not all-too-stupid choice for a module loader is SystemJS.

So, in summary what happened until now:

  1. ES6 has “cool new features you want to use”, but browsers don’t support them yet. (But probably you were kinda dragged into this by starting with typescript)
  2. In order to use es6 syntax today to develop a production ready app, we thus somehow need to map es6 to es5. Typescript does this for us.
  3. The es5 generated by typescript doesn’t run by itself, in case you are using modules (i.e. there is import / export in your code). In order to load those modules, you’ll need a module loader like SystemJS.

Here’s a minimal “app” that is built around those concepts:

index.html

<!DOCTYPE html>
<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>Typescript Modules</title>
 
 <!-- get systemJS from somewhere -->
 <script src="https://code.angularjs.org/tools/system.js"></script>
 </head>
 <body>

 <script>
 // set our baseURL reference path
 System.config({
 baseURL: './'
 });

 // loads /js/main.js
 System.import('main-module.js');
 </script>

 Open your js console.
 </body>
</html>

main-module.ts

import {someVar} from "./some-es6-module.js"

console.log(someVar);

some-es6-module.ts

export var someVar = "Hello World";

tsconfig.json

{
 "compilerOptions": {
 "module": "system",
 "target": "es5"
 },
 "files": [
 "main-module.ts",
 "some-es6-module.ts"
 ]
}

To make it run:

  1. Put all those files into a folder or download them from https://github.com/bersling/minimal-typescript-es6-module-app/tree/master.
  2. Get the typescript compiler and run tsc.
  3. Start a server with python -m SimpleHTTPServer and see the app at 127.0.0.1:8000

Long to Base64 and Base64 to Long in Java

The following code converts a base64 String to a long and vice versa.

private static final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
public static String encodeBase64(long v) {
    char[] a = alphabet.toCharArray();
    v = Math.abs(v);
    String s = "";
    for (int i = 0; i < 11; i++) {
        long val = v & 63;
        s = a[(int) val] + s;
        v >>= 6;
    }
    while (s.startsWith("A") && s.length() > 1)
        s = s.substring(1, s.length());
    return s;
}
public static long decodeBase64(String s) {
    char[] a = alphabet.toCharArray();
    Map<Character, Integer> map = new HashMap<>();
    for (int i = 0; i < a.length; i++)
        map.put(a[i], i);
    char[] chars = s.toCharArray();
    long v = 0;
    for (char c : chars) {
        v <<= 6;
        v = v | map.get(c);
    }
    return v;
}

Get an A+ rating in SSL Labs

Get Certificate from Letsencrypt

sudo apt-get -y install git bc
sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
./letsencrypt-auto certonly --standalone --email yourmail@gmail.com -d www.example.com

Strong Diffie-Hellman

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Link to SSL Certificate / Key

cd /etc/nginx
mkdir ssl
cd ssl
ln -s /etc/letsencrypt/live/www.example.com/privkey.pem nginx.key
ln -s /etc/letsencrypt/live/www.example.com/fullchain.pem taskbaSe.crt

Use the following in your nginx conf

server {
 listen 80;
 server_name taskba.se;
 return 301 https://$host$request_uri;
}

server {
 listen 443 ssl;
 client_max_body_size 20M;
 server_name www.example.com;
 ssl_certificate /etc/nginx/ssl/nginx.crt;
 ssl_certificate_key /etc/nginx/ssl/nginx.key;
 
 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
 ssl_prefer_server_ciphers on;
 ssl_dhparam /etc/ssl/certs/dhparam.pem;
 ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
 ssl_session_timeout 1d;
 ssl_session_cache shared:SSL:50m;
 ssl_stapling on;
 ssl_stapling_verify on;
 add_header Strict-Transport-Security max-age=15768000;
}

Chrome Plugin to Block Game of Thrones Spoilers on 9gag

It seems to become quite popular, to post spoilers the day after an episode of some TV show has aired… I don’t know why this is, but it started to get on my nerves. Fortunately, writing a Plugin for Chrome turned out to be rather easy! In a matter of 3 hours, I had a Game of Thrones Spoiler Blocker up and running.

You can find the plugin at https://chrome.google.com/webstore/detail/9gag-got-spoiler-blocker/jagofmnlfelcophmdongolafmkjcldml and the code at https://github.com/bersling/9gagGoTSpoilerBlocker. Hope it helps some of you, either the code to get started with your own Chrome Plugin or the actual plugin to block some spoilers on 9gag…

You probably don’t need Java StringBuilder – Use a templating engine instead

NoString Builder

Does your code look like somewhat like this? Do you find \n in your code? Then you are doing it wrong. Building strings is a very, very cumbersome process. You’ll miss newlines, you can’t see what’s happening in the process, it’s inefficient if you want to wrap something and so on… Overall very error prone and time consuming. As a rule of thumb: When you write something, that could go into a file (e.g. a .tex file or a .html file), then write it into a file, and not intermixed with Java, C++ or Python code!

But I want to generate my file dynamically, so how can I do it?

Templating Engines

Instead of writing derpy stuff like

String start = "\\escaping \n too much \n"
String middle = "wow... that's weird"
String end = "homg the middle forgot the \n what amigonnadu noww\n"
String full = start + middle + end;

there is a more elegant concept for generating files dynamically. It’s called Templating Engine. In a templating engine, you write your file as you would have anyways, for example:

Hello, I'm just a .txt file... Almost... I have some special syntax enabled like variables denoted by $imAVariable.

And then I just continue writing. No chance to forget a new line.

… with a few “enhancements” to the default file:

  • write variables, for example with $variableName notation in Apache Velocity Templating engine.
  • write for loops, for example with
    #foreach ($name in $myArray)
     ...some normal derpy text
    put a $name in between
    lalala
    #end
  • … and some more functionalities, depending on the power of your templating engine.

Like this you’ll never miss a \n again and your file-to-be becomes much, much, much more readable. If you’re programming in Java, the best choice for you is probably Apache Velocity Templating Engine.

After writing your template file for example helloworld.vm

Hello $name!  Welcome to Velocity!

you can use Java to fill in the gaps, as in:

/*  first, get and initialize an engine  */
    VelocityEngine ve = new VelocityEngine();
    ve.init();
/*  next, get the Template  */
    Template t = ve.getTemplate( "helloworld.vm" );
/*  create a context and add data */
    VelocityContext context = new VelocityContext();
    context.put("name", "World");
/* now render the template into a StringWriter */
    StringWriter writer = new StringWriter();
    t.merge( context, writer );
/* show the World */
    System.out.println( writer.toString() );

Well and that’s it! Files built efficiently, readable, maintainable.

Summary

Writing files via string-concatenation is bad idea since the code is non-readable, errorprone and takes forever to write. A much better idea is to use a templating engine, where you’ll write your file as usual, with the exception of the dynamic parts. Those are inserted by the templating engine later on.