codelord.net

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

Using Angular 1.5’s Multiple Transclusion Slots

| Comments

Most (well maintained) Angular projects eventually reach the point where they would benefit from having a few generic components that use transclusion.

Maybe you have a timeline feed screen with multiple types of feed items.
Or some tabs widget.
Or a generic modal you use across the app.

Transclusion allows us to create very customizable components since you can inject them with other components, and not just pass rigid inputs (e.g. specific bindings). That’s pretty much how things like ng-repeat work: you provide those directives with inner HTML that they then use.

Prior to Angular 1.5 a component could only transclude a single entry: whatever you gave it was had to be used as a whole.

But, among other goodies introduced in 1.5 we also got multiple slot transclusion, which comes in handy at times.

Example

Say you want to create a generic modal, that can have both the title and body customized.

Here’s an example of someone using the modal component we’ll create:

1
2
3
4
5
6
<modal>
  <modal-title>Are you sure ?</modal-title>
  <modal-body>
    You can only do this  times
  </modal-body>
</modal>

Those modal-title and modal-body elements are the transclusion slots we will now define and use in our modal component:

1
2
3
4
5
6
7
8
9
10
11
12
13
app.component('modal', {
  template: [
      '<div ng-transclude="title"></div>',
      '<div ng-transclude="body"></div>'
  ].join(''),
  transclude: {
    title: 'modalTitle',
    body: 'modalBody'
  },
  controller: function() {
    // Stuff to make this component render as a modal
  }
});

As you can see above, we define the component’s transclude property to have 2 slots, named title and body.

Each slot also has the name of the element it expects to see its content inside.

Then in the component’s template we can decide where to insert the transcluded elements by using the ng-transclude directive and supplying it with the slot’s name.

As you can see transclusion automatically takes care of things like passing the scopes correctly so that even though the templates we passed reference the original component’s scope ($ctrl), it’s still properly visible inside.

“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!

What is the Component Router? Can you start using it?

| Comments

Update: The component router has finally been officially deprecated and discontinued. You should not be using it. This post is here for posterity’s sake, but it goes to show how flakey our industry can really be.

A new router for Angular 1.x was announced over a year ago. That router is usually called the Component Router, but you may have seen the name “new router” (or ngNewRouter) thrown around.

Its release keeps getting delayed. Documentation is scarce. The GitHub repo is abandoned.

I keep seeing people wondering whether they should be using it and how. Let’s try and answer those concerns.

What is different about it?

The component router is aimed to make routing easier in a world of components, like the awesome ones we got in 1.5.

It has some similarities to the Angular 2 router.

The component router also incorporates some features that have long been considered a standard in ui-router, such as nested routes.

The gist is that you define a root component – that’s the component that starts all your app’s rendering.

In it you render sub-routes using an outlet (<ng-outlet></ng-outlet>), much like the old ng-view or ui-router’s ui-view.

But, you can keep on nesting these outlets, which isn’t possible with ng-view.

You can read more in the design doc.

Can you start using it?

Well, it hasn’t been released yet, but according to the Angular weekly meeting notes it should be out very soon.

I wouldn’t start writing code in it just yet, but you should definitely spend a few minutes reading the code of this demo by one of the Angular core maintainers.

And if you really want to play with it, that demo is a good starting point.

Once it’ll be out officially (hopefully in a couple of weeks) check this space for more information on using it and migrating your existing apps to it.

“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!

Writing Pragmatic Angular Components

| Comments

Angular 1.5’s new components are awesome. But, as with anything new, we’re still learning, as a community, how to best use it.

There are so many different ways to use them. And the style guides aren’t clear yet.

Here are my initial thoughts/guidelines after playing with components lately:

Default to use one-way bindings

Angular 1.5 introduced one-way bindings, as opposed to the regular two-way bindings.

Since the need to override something from a child components to its parent is rare (and perhaps even a code smell), I prefer to always use one way bindings.

So make sure to pass write your bindings like so: {someBinding: '<'}, making sure to pass '<' instead of '='.

Use $onInit to initialize your component

Yes, you don’t have to use to for setting up your component. We’ve been doing just fine without it so far.

But, I think it helps makes thing clearer and explicit.

So, in your component’s controller function put all the setup code inside $onInit, e.g.:

1
2
3
4
5
6
7
8
9
10
11
12
app.component('foo', {
  controller: function() {
    var self = this;
    self.$onInit = function() {
      // Initialize here:
      self.foos = [1, 2, 3];
    }

    // Add the other functions...
    self.addFoo = function() {};
  }
});

Use require to pass dependencies between components layers

2 years ago I wrote about the benefits of using the require feature for making more maintainable and robust directives.

Now, that components have even simpler require syntax and support, there’s really no reason not to use it.

It’s a great way to pass along dependencies between your components hierarchy without having to pass bindings from parent to child, layer after layer.

If you have some top level components that exposes something you need in some grandchild component, instead of using bindings just require it from the grandchild.

It makes these dependencies explicit and also is safer for refactoring, since Angular will let you know if something you’re requiring isn’t here.

Feel free to inject $element to your component controllers

Components aren’t controllers. Components are better directives.

Just because components don’t have a link function, it doesn’t mean you can’t use them for writing something that needs to play with the DOM a bit.

A component’s controller can be injected with $element, just like you get in a directive’s link. There’s a reason it’s there – use it.

Yes, it was taboo to do DOM manipulation in controllers, but that’s the old Angular.

Embrace components and fear not having a true component that has control over its element.

“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!

Angular 2 migration: what’s ng-forward?

| Comments

Angular 2 keeps getting closer (beta2 was just released). This means everyone are getting more anxious and worried about the future of their Angular 1 code.

The migration path keeps getting clearer. I’ve shown before how easy it is to start integrating ng2 in your existing apps with ng-ugprade.

Yet I keep seeing developers confused ng-forward: Is it the same as ng-upgrade? Is it a formal part of the migration path? When should you use it?

This post will give you the background you need to wrap your head around ng-forward and whether or not you should be using it.

What’s ng-forward

ng-forward is an open source project that aims to let you write Angular 1 code that looks very similar to Angular 2. You don’t actually start to use ng2. Instead, you’re getting familiar with the syntax and a lot of your code will look almost exactly like it would have looked in ng2.

ng-forward isn’t by the Angular core team per se. It is created by the community, but with a blessing of the core team.

Here’s how a simple service would look like when written with ng-forward:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Injectable, Inject } from 'ng-forward';

@Injectable()
@Inject('$q', '$timeout')
class TestService {
  constructor($q, $timeout) {
    this.$q = $q;
    this.$timeout = $timeout;
  }

  getValue() {
    return this.$q(resolve => {
      this.$timeout(() => resolve('Value'), 3000);
    });
  }
}

As you can see, it’s much alike Angular 2, but of course we’re still making use of Angular 1 services like $q.

What’s the difference between it and ng-upgrade

ng-upgrade, which is an official part of the migration path and comes bundled with Angular 2 for now, is a mechanism to run actual Angular 2 code alongside Angular 1.

This means that while with ng-forward you’re writing services that look like Angular 2, with ng-upgrade you write actual Angular 2 services.

When should you use it

First of all, I’ll mention that ng-forward doesn’t support ES5 (yet), so you can only use it if you want to use ES6/TypeScript.

This is a big advantage of ng-upgrade: it works with ES5 (though documentation is still lacking) so you can start using it in ES5 project without making a lot of infrastructure changes.

Now, the decision of whether to use it or not boils down to personal preference. They’ve done a marvelous job of making a lot of the syntax closely resemble ng2’s.

If you don’t expect to actually start learning and migrating to ng2 in the near months after its release, ng-forward is an interesting compromise.

You can start getting used to Angular 2 syntax, and won’t have to relearn a lot of things just yet.

Just as with ng-upgrade, there’s no need to rewrite all your code, you can decide to simply write new code with it or migrate specific services/components as it suits you.

Personally, I think that if you can take the hit of bundling Angular 1 and 2 together (which is a bump in download size), you should lean towards ng-upgrade.

Yes, it will take more time (since you’ll have to learn Angular 2), but whatever code you change/write won’t have to be migrated again later.

Also, I find the almost-exact-same-syntax a bit of a disadvantage. Imagine a big project that’s written with ng-forward and that later starts an ng-upgrade migration.

It could easily become confusing to debug and make changes in a code base where neighboring files look very similar yet use a fundamentally different framework underneath.

That said, you should definitely consider using ng-forward if for some reason you won’t be adding ng-upgrade soon.

The sooner you start adjusting the easier it will be down the migration road (or path).

“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!

Caching HTTP results in Angular

| Comments

A lot of the work of web developers eventually boils down to making things smoother or nicer for the user.

HTTP calls are a big part of this mess. Web development is async. That means the users perceive slowness.

Say you’re using Trello and go back and forth between a couple of cards. Should you wait every time you click a card for it to be fetched again if it wasn’t changed?

Certainly not.

And while caching isn’t that hard to do, it’s a bit tricky to do right. Let’s take a look.

Note: I’m going to show you how to roll your own caching. In case you have no need of advanced uses, like invalidating the cache or manually changing it for performance optimizations, you might be able to simply use $http’s built in cache option.

Setting things up

Let’s say we’re going to put a cache behind our FooService. To have things work smoothly, you should make sure that you’re not returning $http promises from FooService.

$http promises has the deprecated .success function on it, which you really shouldn’t be using.

Our Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.factory('FooService',
     function($http, $cacheFactory, $q) {
  var cache = $cacheFactory(
        'fooCache', {capacity: 100}); // 1
  return {
    getFoo: function(id) {
      if (cache.get(id)) {
        return cache.get(id); // 2
      }

      var promise = $http.get('/foo/' + id).then(
        function(response) {
          cache.put(id, $q.when(response.data)); // 4
          return response.data;
        }
      );
      cache.put(id, promise); // 3
      return promise;
    }
  };
});

Note: While this is still an Angular 1 service, you should really consider writing your new services in Angular 2 like I describe here.

So, what are we looking at?

At 1 you can see that we use Angular’s $cacheFactory. This is a pretty basic object that behaves much like a regular dictionary/map/object.

But, it has the added benefit that you can specify a capacity for the max amount of items it saves. That easily turns it into an LRU cache.

Then, 2, when we are requested to get a certain value we first try to return it from the cache.

If we find nothing in the cache we make the request, store its promise in the cache (3) and return it.

And, finally, once the request returns we update the cache with the returned value (4).

Note that the cache holds promises, not the actual values. This is for an edge case: it is possible to get 2 requests for the same object before our first request completed.

In that case, we’d rather not make 2 requests. That’s why right when we create an initial request we already store its promise in the cache.

That way once a request has been made we’ll always have something to return and won’t make a request that’s not needed.

That’s it!

Yeah, you’ll probably need to add some more lifecycle management, like invalidating objects that have changed.

But, this is the gist of it.

“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!

Setting up SEO in an Angular app

| Comments

Angular and SEO don’t really go well together without some nudging.

As you probably know, the whole client-side MVC thing has its perks. But, it comes with a price: search engines usually won’t be able to scrape your site.

Angular 2 should enable us to render pages on the server as well, which will help solve this. In the meantime, let us see what you can do with your production app today.

I’ll talk about setting this up using the awesome Prerender.io service, which I’ve had great experience with. It’s also open source, so you can host it yourself if that floats your boat.

We basically set up our site so that requests from search engines get redirected to a Prerender.io server, which then serves cached content to the search engine. Magic!

Note: SEO is not a client-side only deal. You will have to make changes to whatever server you’re using to serve your app. Also, Google has officially deprecated this sort of solution on the grounds that their bots can crawl JS sites. It might be good for you, but if you look around you’ll see plenty of developers complain that it’s not perfect, not working or that they care about more than just Google’s bots.

Site preparation

While it doesn’t take a lot of changes usually, there are still some things you need to make sure you’re doing correctly before SEO will work for you.

Push-state

HTML5 push state makes your app use URLs that look “regular”, e.g. example.com/foo/bar instead of the default example.com#/foo/bar. When doing SEO, my opinion is that using push-state makes things simpler all-around.

If you’re not already using it, you can see my post about getting started with push state in Angular.

Then make sure to add this meta tag (see here why):

<meta name="fragment" content="!">

title, description, and metadata

A lot of the time when writing a simple SPA we tend to neglect the good old <title> tag (and similar tags, like meta description).

We want search engine results to show properly the content the user will find on the page, and so you should make sure to keep these updated.

For example, if you’re writing a forum, make sure to update the title tag to the current thread’s title whenever routing to a new thread.

It’s not really complicated. You should put a directive on the <title> tag that updates it according to the current page.

Pitfall: make sure you have your ng-app on the <html> tag and not the <body>, so you will be able to have directives in the <head> element as well.

ng-click pitfalls, e.g. paging

With SPAs it’s easy to get used to doing most of everything with ng-clicks on elements.

That’s not how plain sites work, right? You should use <a href=“..”> tags to move between states.

Keep in mind that search engine crawlers crawl your site by looking for links. That means that if, for example, you have several pages you’d like it to crawl, you need to use real links.

Instead of having something like <button ng-click="paging.next()">Next</button> that changes the current route to /pages/2 or whatever, change it to something along these lines:

<a ng-href="paging.urlForNextPage()">Next</a>

Setting up Prerender.io

This is actually quite straightforward. Follow these instructions and you should have something running locally in 10 minutes.

Tweaking: Optional API

Prerender.io does a pretty good job of knowing when your site has finished loading before caching it.

But, you might want to tweak it if you’re doing something complicated on page load. They have a little trick you can use to hint them, see here.

You can also look at that link to see how you can return proper HTTP status codes, like 404, in case the crawler tries scraping something it shouldn’t.

You’re good to go!

Go over the prerendered site and make sure all your links work so that the crawlers can get to all the pages you want them to. If all looks good you can go live.

“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!

Adding the first Angular 2 component to your Angular 1 app

| Comments

In my previous post we saw how easy it can be to add your first Angular 2 service to an existing Angular 1 app, using ES5. This lets you easily have Angular 1 code live alongside Angular 2 code.

This time, let’s start dipping our toes in the real deal: adding your first component.

What’s an Angular 2 component?

A component is a piece of logic (like Angular 1’s controllers) that’s coupled with a view. It’s self contained and isolated. And it can have bounded inputs and outputs.

Sounds familiar? That’s basically Angular 1.5’s .component (see here).

Setting things up

Set up takes a few minutes to add the Angular 2 dependencies and create the upgrade adapter that wires everything together. Follow the instructions from my previous post.

Our shiny new component

We’ll start from a pretty basic component. It will have a single input: that’s ng2 speak for a bounded property, except the binding is not two-way by default.

If we were to write this component in ng1 it would look something like this:

1
2
3
4
angular.module('app').component('greeter', {
  bindings: {name: '='},
  template: '<span>Hello, {{greeter.name}}!</span>'
});

Here it is in Angular 2 and ES5:

1
2
3
4
5
6
7
8
9
10
11
12
13
var GreeterComponent = ng.core.
  Component({
    selector: 'greeter',
    template: '<span>Hello, {{name}}!</span>',
    inputs: ['name']
  }).
  Class({
    constructor: function() {}
  });

 angular.module('app').directive(
    'greeter',
    upgradeAdapter.downgradeNg2Component(GreeterComponent));

Breaking it down

It takes some more lines to write it, but this is essentially the same component we saw earlier.

In Angular 2 we provide a selector to components, but it’s actually not used when using it from Angular 1. All that matters is the name we provide in the .directive() call.

Note that we’re defining the inputs, much like the bindings above.

Using it from Angular 1

When using the upgrade adapter, we still have to use the new template syntax when using the component:

1
<greeter [name]="name"></greeter>

Those brackets mean we’re setting up one way binding to pass the name parameter down to the component and it will be updated automatically whenever you change it in your Angular 1 code.

That’s it!

Where to go from here

You can read more on the upgrade guide, though it’s all in TypeScript for now.

There’s plenty more to go into here: the new template syntax, binding for changes (i.e. outputs), and more.

I’ll be covering more upgrade steps soon, sign up below to stay posted!

“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!

Adding the first Angular 2 service to your Angular 1 app

| Comments

The Angular 2 beta was released a couple of weeks ago.
We all want to be in the loop and not have our projects stay behind and become outdated.
You know that you should probably spend more time learning about ng2 and what that means for your project.

And Angular 2 comes with a huge set of new technologies to learn and problems to solve:

Should you migrate your project to ES6?
Should you migrate it to TypeScript?
What is the right way to address such a big move, if at all?

Well, we can’t answer all these questions in one post. For today, let’s look into adding your first Angular 2 service into your existing Angular 1 app.

Wait, what about all the rest?

You want to know what language should you use. And whether or not you should migrate your old code. And why are we starting with a service instead of something more sexy like a component, with a view and all?

Slow your roll. Starting with a service is a great way to take one baby step towards Angular 2. We don’t want to take on more than we can handle.

The service we will be replacing

Say that you just got a task to introduce a new service. The service is responsible for fetching some REST objects and returning them.

If we were to do it in Angular 1, it would probably look like this:

1
2
3
4
5
6
7
8
9
10
11
module.factory('FooService', function($http) {
  return {
    getFoo: function() {
      return $http.get('/foos').then(
        function(response) {
          return response.data;
        }
      );
    }
  };
});

That’s quite a straightforward service, right?

Adding Angular 2 to your existing project

Note about using ES5: Because we’re using ES5 and not ES6/TypeScript, some code needs extra boilerplate. It’s not that bad actually, and I’m sure you’ll be able to follow along. But I won’t be explaining every single character today (deep dives will be posted in the future, stay tuned!).

Bye bye ng-app

In case your app is currently bootstrapped using the ng-app directive, you need to change it. Angular can be bootstrapped with either ng-app or the manual way of calling bootstrap yourself. In Angular 2 we have to use the latter.

If you have <body ng-app="app"> you’ll need to remove the ng-app bit and add this to JavaScript code:

1
2
3
angular.element(document.body).ready(function() {
  angular.bootstrap(document.body, ['app']);
});

This is actually a pure refactoring, nothing should have changed by this point – refresh to make sure!

Adding the source files

Now we’ll need to grab Angular 2, and its dependency Rx.js, to include them in our project.

Get them however you usually get dependencies. With npm it would look like this:

npm install angular2@2.0.0-beta.0 rxjs@5.0.0-beta.0

And then add this to your index.html file:

1
2
3
<script src="node_modules/rxjs/bundles/Rx.umd.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-all.umd.dev.js"></script>

Introducing UpgradeAdapter

When I wrote about the Angular 2 migration path, I mentioned the ngUpgrade library which will be used to supply us with the ability to run Angular 1 code side by side with Angular 2 code.

With time this has basically become the UpgradeAdapter you can find in Angular 2.

We will create an instance of this adapter and use it to bootstrap our app. This initializes our app as a hybrid app that can use both Angulars.

Let’s change the bootstrap code from above to look like this:

1
2
3
4
var upgradeAdapter = new ng.upgrade.UpgradeAdapter();
angular.element(document.body).ready(function() {
  upgradeAdapter.bootstrap(document.body, ['app']);
});

Tip: you’re used to using angular. for accessing Angular 1 stuff. Angular 2 exposes all of its shiny stuff under the ng global.

That’s it, we’ve successfully included Angular 2 in our app. Refresh to make sure everything looks ok!

Writing our new service

In Angular 2 services are essentially just plain classes. Because ES5 doesn’t have classes really, we’ll use the nice wrapper Angular 2 supplies us with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
upgradeAdapter.addProvider(ng.http.HTTP_PROVIDERS); // 1

var FooService = ng.core.
  Injectable().
  Class({
    constructor: [ng.http.Http, function(http) { // 2
      this.http = http;
    }],
    getFoo: function() {
      return this.http.get('/foos').map(
        function(res) { return res.json(); }
      ).toPromise(); // 3
    }
  });

This might take a bit of getting used to.

First, at (1), we tell the upgrade provider what kind of Angular 2 dependencies our app requires. In this case it’s the HTTP library.

Then in (2) we define our service’s class and inject it the Http instance. This is a bit like injecting $http in Angular 1, except we provide the actual constructor/type of our dependency, not just a name.

And finally we just execute the AJAX request, similar to Angular 1. Note that Angular 2 works with Observables instead of promises, but observables have a toPromise() method that we use (3) in order to supply the same interface to our Angular 1 code.

Using our new service in Angular 1 code

First, let’s expose this service to our Angular 1 code:

1
2
3
4
upgradeAdapter.addProvider(FooService);
angular.module('app').factory(
  'FooService',
  upgradeAdapter.downgradeNg2Provider(FooService));

And now we can use this service as we would use any other service:

1
2
3
4
5
6
7
8
9
10
11
angular.module('app').component('foo', {
  templateUrl: 'foo.html',
  controller: function(FooService) {
    var vm = this;
    FooService.getFoo().then(
      function(foos) {
        vm.foos = foos;
      }
    );
  }
});

Victory!

Yeah, that’s it. You have a new skill and just added your first real Angular 2 code to your existing app.

Yes, there’s plenty more to do. You might want to use components. Or use Angular 1 code inside your Angular 2 code. Or write your new stuff in TypeScript.

We’ll get there. Be sure to sign up below to get it :)

For now, you can take read the official upgrade guide (TypeScript only), and Dave Ceddia’s great blog.

“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!

Automatically find links in text using Angular

| Comments

There comes in every web developer’s life a day where he needs to take some block of text and automatically find URLs inside it and transform them into links, inline.

Almost any text that a user inputted would be nicer if it did this automatically.

I don’t know about you, but I’ve accomplished this task in Angular in several ways like jQuery plugins or writing my own regular expressions. It’s not fun adding extra dependencies to accomplish this minor tasks. And it’s always a bit nontrivial to add link support without opening yourself up to some vulnerabilities.

I was quite surprised to hear that there’s a solution to this that comes builtin in Angular and since 1.0: the linky filter.

Setting it up

The linky filter does what you’d expect it to do. Let’s see an example.

First, as the docs say, you need to make sure that you include ngSanitize module file (angular-sanitize.js) and add it as a dependency to your module:

1
angular.module('myApp', ['ngSanitize']);

The basic usage goes like this:

1
<div ng-bind-html="blog.post | linky"></div>

This will take blog.post and display it regularly, except that URLs inside it, such as www.google.com would become links. Angular does this safely and sanitizes all the text.

You can quite easily make links open in a new tab or add specific attributes, such as rel=nofollow which is usually recommended when putting up links to user generated content:

1
2
3
<div ng-bind-html=
    "blog.post | linky:'_blank':{rel: 'nofollow'}">
</div>

And that’s it. Link 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!

Configuring components with ui-router and ngRoute

| Comments

Angular 1.5’s .component() method is very cool, as I wrote about previously. And in general the migration path to Angular 2 recommends that we all stop using controllers in favor of components.

A lot of us are used to using controllers as the route-level objects. Each route has a controller that’s responsible for that specific route, and comes with its own template, etc.

This was comfortable since both ui-router and ngRoute allow us to easily set a controller that handles a route and inject it with dependencies using resolve.

Achieving the same with components isn’t as straightforward, but doable. Note: You might be thinking otherwise, but yes, components should be used for things that aren’t reusable, like handling a specific route. They should actually be used by default for anything that’s not a service in your app.

ngRoute

Say that we’ve got this component:

1
2
3
4
5
myMod.component('inbox', {
  templateUrl: 'inbox.component.html',
  bindings: {mails: '='},
  controller: function() {...}
});

Passing it the mails dependency using resolve is pretty simple:

1
2
3
4
5
6
myMod.config(function($routeProvider) {
  $routeProvider.when('/inbox', {
    template: '<inbox mails="$resolve.mails"></inbox>',
    resolve: {mails: function(Mails) { return Mails.fetch(); }}
  });
});

Yes, ngRoute has a handy $resolve property exposed on the scope by default, which saves us some keystrokes and boilerplate in this case.

ui-router

While the upcoming 1.0 release will handle components in a cleaner way, the above solution is available to us since version 0.3:

1
2
3
4
5
6
7
myMod.config(function($stateProvider) {
  $stateProvider.state('inbox', {
    url: '/inbox',
    template: '<inbox mails="$resolve.mails"></inbox>',
    resolve: {mails: function(Mails) {return Mails.fetch(); }}
  });
});

Yes, that’s eerily similar to the ngRoute way. Now we get rid ourselves of controllers and get onboard the component train. Choo-choo!

“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!