The new component syntax introduced in Angular version 1.5 is nothing more than a special kind of directive with some very sensible defaults. As a reminder, a component

I am going to talk exclusively about component in this article, but the techniques describe her also apply for directive.

Let’s look at a simple ionic component that I called capture-image-gallery. This component can be used to display a list of images and also enable a user to add a picture to the list of images.

let captureImageGallery = {
 templateUrl: 'app/capture-image-gallery.html',
 bindings: {
   images: '<',
   onImageAdded: '&'
 },
 controller: captureImageGalleryController,
 controllerAs: 'vm'
};

export{captureImageGallery};

function captureImageGalleryController(imageUploader) {
 const vm = this;
 
 vm.captureImage = ()=> {
   return imageUploader.captureImage()
     .then(image=> {
       vm.onImageAdded(image);
     });
 };

 vm.deleteImage = (image) => {
   _.remove(vm.images, x=> x.src === image.src);
 };
}

This component requires two bindings:

Let’s suppose that we have a container component with the addImage function having the following signature

export class ContainerComponent{
    ...
    addImage(image){
       ...
    }
    ...
}

The addImage function contains the business logic to persist the captured image and should be the one used in the binding. The actual implementation is irrelevant for this post.

How do we pass the image as parameter to the function? In other words, how should we define the markup instantiating our component?

My first try was something like that:

<capture-image-gallery images="vm.allImages" on-image-added="vm.addImage()"></capture-image-gallery>

That should work right? We are calling the referenced function with a parameter via the onImageAdded binding. Well it does not. The image parameter is undefined! So how should that work? Passing a parameter to a binding function is actually a piece of cake, once you know how. There are at least two ways to accomplish this:

Using an object literal

This is by far the most common used method. This is how the markup would look like:

<capture-image-gallery images="vm.allImages" on-image-added="vm.addImage(image)"></capture-image-gallery>

and the call to the binding function inside the component

  ...
  vm.captureImage = ()=> {
    return imageUploader.captureImage()
      .then(image=> {
        vm.onImageAdded({image});
      });
  };
  ...

Can you see the subtle change? Instead of passing the image object to the onImageAdded function, we pass an object literal {image} which is equivalent to {image:image} using the shorthand property name syntax of ES6.
Then we add a parameter with the same name in the markup on-image-added="vm.addImage(image). It is important that the parameter name of the function (here image) matches exactly the property name in the object literal otherwise the technique won’t work.
Once you know the trick, you are good to go. But this looks like a leaky abstraction to me and is by no mean the syntax that you would expect.

Using a function reference

I haven’t seen many people using this approach to be honest, but this is my favorite. Instead of defining parameters by name, we can capture a reference to the target function and invoke it.

The markup would change and be much more consistent with our expectations:

<capture-image-gallery images="vm.allImages" on-image-added="vm.addImage"></capture-image-gallery>

Note how I have removed the () altogether. Instead of letting angular wrap the function call into its own closure, we can now reference directly the function. In order to invoke the function however, we need to add those missing () back.

  ...
  vm.captureImage = ()=> {
    return imageUploader.captureImage()
      .then(image=> {
        vm.onImageAdded()(image);
      });
  };
  ...

Calling vm.onImageAdded() returns the actual addImage function from the container component. Now I can simply invoke the function passing the parameter as usual. Of course, you would still need to define in the documentation of your component the expected signature of the binding function. But parameter names are irrelevant with this technique.

You can see that passing parameters to a binding function is not as simple as expected. Once you know the techniques however, you won’t have to think twice about it.