Friday, May 24, 2013

Angular service or factory?

tl;dr is at the end

In various AngularJS tutorials and documentation, the authors choose to use service or factory but don't explain why you would use one or the other. Few mention that value and constant are also options.

Let's see why you would use one over the other. We should also understand how providers work:

provider

Here's the source for the provider method:

function provider(name, provider_) {
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
if (!provider_.$get) {
throw Error('Provider ' + name + ' must define $get factory method.');
}
return providerCache[name + providerSuffix] = provider_;
}

name is a string. provider_ can be one of three things:

  1. function

    If a function is passed in, the function is called with dependency injection and should return an object with a $get method.

  2. array

    An array will be treated like a function using Inline Annotation. It must also return an object with a $get method.

  3. object

    If an object is passed in, it is simply expected to have a $get method.

Whatever the second arg to provider is, you eventually end up with an object that has a $get method. Here's an example showing what happens:

// You can run this

// Create a module
var hippo = angular.module('hippo', []);

// Register an object provider
hippo.provider('awesome', {
$get: function() {
return 'awesome data';
}
});

// Get the injector (this happens behind the scenes in angular apps)
var injector = angular.injector(['hippo', 'ng']);

// Call a function with dependency injection
injector.invoke(function(awesome) {
console.log('awesome == ' + awesome);
});

Once you understand providers you will see that factory, service, value and constant are just convenience methods for making providers.

factory

Here's the source:

function factory(name, factoryFn) {
return provider(name, { $get: factoryFn });
}

So it lets you shorten the awesome provider creation code to this:

hippo.factory('awesome', function() {
return 'awesome data';
})

service

Here's the source:

function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}

So it lets you make a factory that will instantiate a "class". For example:

var gandalf = angular.module('gandalf', []);

function Gandalf() {
this.color = 'grey';
}
Gandalf.prototype.comeBack = function() {
this.color = 'white';
}

gandalf.service('gandalfService', Gandalf);

var injector = angular.injector(['gandalf', 'ng']);

injector.invoke(function(gandalfService) {
console.log(gandalfService.color);
gandalfService.comeBack()
console.log(gandalfService.color);
});

The above code will instantiate Gandalf, but remember that everything that uses the service will get the same instance! (which is a good thing).

value

Here's the source:

function value(name, value) {
return factory(name, valueFn(value));
}

Using value would let you shorten the awesome provider to:

hippo.value('awesome', 'awesome data');

constant

Here's the source

function constant(name, value) {
providerCache[name] = value;
instanceCache[name] = value;
}

constant differs from value in that it's accessible during config. Here's how you use it:

var joe = angular.module('joe', []);

joe.constant('bobTheConstant', 'a value');
joe.value('samTheValue', 'a different value');

joe.config(function(bobTheConstant) {
console.log(bobTheConstant);
});

joe.config(function(samTheValue) {
console.log(samTheValue);
});

// This will fail with "Error: Unknown provider: samTheValue from joe"
var injector = angular.injector(['joe', 'ng']);

Read Module Loading & Dependencies in the Modules doc for more information on usage.

In summary

If you want your function to be called like a normal function, use factory. If you want your function to be instantiated with the new operator, use service. If you don't know the difference, use factory.

This is the (great) documentation for each function in the AngularJS source:

  1. factory

    A short hand for configuring services if only `$get` method is required.

  2. service

    A short hand for registering service of given class.

  3. value

    A short hand for configuring services if the `$get` method is a constant.

  4. constant

    A constant value, but unlike {@link AUTO.$provide#value value} it can be injected into configuration function (other modules) and it is not interceptable by {@link AUTO.$provide#decorator decorator}.

Wednesday, May 22, 2013

Angular and components

I've been playing around with AngularJS lately.  It's okay.  It's very weird.  They've named some things poorly (and magically), the documentation is not great and there are some unexpected quirks.  I feel like AngularJS is the first step toward a new class of JavaScript libraries, but it's not the end.

Something is going to come along and choose good names (without magic '@', '=', '&') with great documentation.  Just today, I happened on this talk:



Which does a lot of AngularJS things.

I haven't explained thoroughly... sorry.  Maybe when I have more time, I'll post more.

Friday, May 10, 2013

@#$%!


To all you producers of words: please stop swearing.  For the sake of your audience, elevate your language above crude speech.  You lose respect when you swear.


You're not dying!

I once watched a video about API design.  Rather, I once watched part of a video about API design.  I had to stop after the 5th or 6th expletive.

API design.

API design?!  A discussion about API design is probably the last thing in the world that deserves to be littered with swearing!

You're not dying.  Your family isn't dying.  Your arm isn't being severed.  And even these terrible situations don't merit debasing yourself by swearing -- much less API design.


I really want(ed) to share your stuff...

Too frequently, I'm reading an interesting article when @#$&!  Out of nowhere (and completely out of context) I'm jarred by a four-letter word.  Why did they ruin it?  I wanted to share this and now I don't.

I don't want to share with my coworkers, family members or friends something profane -- for sharing implies endorsement, and I don't want to be associated with such things.

If you want it to be shareable, leave out the swear words.

Make me laugh, not cringe

Instead of attacking me by swearing, invite me to laugh with you.  Replace poor words with ridiculous or benign ones.  Or channel an unloveable critter/substance/thing to express your shock/displeasure/pain: Rats! Mucus! Taxes!

(Let me be clear: that was "Taxes" not "Texas.")

Yes, swearing sometimes makes some people laugh.  Bathroom humor makes some people laugh, too.  There are much better ways of making people laugh: choose a better way.

And, yes, swearing will garner attention.  A baseball bat to the head will also garner a certain amount of attention.  You don't want that kind of attention.  And in the end, it's better to lead people through charisma and intelligence than through head shots.

Use honey, not vinegar.

You're smarter than that

We don't live in a high school locker room.  Swearing is a cheap alternative to thoughtfulness.  Demonstrate your intelligence by expressing yourself accurately and powerfully through well-chosen words.  People think you're dumb when you swear.  Go ahead, A/B test it.

When your mouth is foul, your brain is discredited by association.

It's who I am

Some will say, "It's who I am.  Deal with it."  Well, they'd probably say, "$#%!, it's who I am *$!@.  @$#& deal with it.  *@&# $%@!"

Swearing isn't an identity.  You control your mouth.  You have a brain.  Use it wisely.

Thank you

To those who speak well, thank you.  I frequent an IRC channel that has an enforced family-friendly policy.  The admins gently remind people to keep it clean, which they generally do.  And it's great!  I feel comfortable there.  I respect the admins and others there.



Keep it clean and make the world better, muskrat!