toddmotto / ama

Ask me anything!
20 stars 3 forks source link

Code organization in Angular components #65

Closed amandabot closed 7 years ago

amandabot commented 7 years ago

Hi Todd,

First I'd like to say I'm a big fan of your work. I leaned heavily on your style guide and articles in starting to transition one of my team's projects to Angular 1.5 components, and they really accelerated our progress.

One question that came up among our team was how code should be organized, specifically when it comes to component controllers. Your guide, and many others follow a pattern of encapsulating any private and public methods inside the controller function like so:

angular.module('app')
.component('test', {
   controller: function(){
      //private and public methods contained in here
  }
});

An approach we are considering is more along the lines of what is below:

//so we have access to controller properties within public and private methods
var controller; 

function init(){}

//private and public methods contained in here
function privateMethod(){}
function publicMethod(dependency){}

angular.module('app')
.component('test', {
   controller: function(dependency){
      controller = this;
      this.$onInit= init.bind(null, dependency);
      this.publicMethod = publicMethod.bind(null, dependency);
  }
});

The end result is a simple controller with a very clear interface of its lifecycle hooks and public methods.

I'm curious if there's a particular reason to prefer the first style over the second? Or more broadly, is there a precedent for why the first style seems to be more prevalent?

Thanks!

toddmotto commented 7 years ago

Hey Amanda! Glad my posts helped you and your team! :)

So, I would honestly and sincerely avoid this, few ideas/reasons:

If you are going to do this, why not just do this:

var myComponent = {
    bindings: { myBinding: '<' },
    template: `
        <div>Hi !</div>
    `,
    controller: function () {
        this.$onInit = function () {
            console.log(this.myBinding);
        };
    }
};

angular
  .module('app')
  .component('myComponent', myComponent);

If you're somewhat set on breaking things out, this approach also works, in which the controller is split out and hoisted (you could as a preference put the controller above the component object if you wanted):

var myComponent = {
    bindings: { myBinding: '<' },
    template: `
        <div>Hi !</div>
    `,
    controller: myComponentController
};

function myComponentController() {
    this.$onInit = function () {
        console.log(this.myBinding);
    };
}

angular
  .module('app')
  .component('myComponent', myComponent);
amandabot commented 7 years ago

Thank you so much for your feedback! I will definitely share this with my team.

We have plans to migrate to ES6 and the patterns outlined in your guide at some point (we're just not there yet with our build tools), but I think we can use some of the patterns you've suggested in your reply to move us in that direction (or at least better organize our code).

toddmotto commented 7 years ago

You're welcome! If you're moving to ES6 then maybe even consider using controller.prototype.$onInit - but it's a little more effort - but more "class-like". Best of luck, merry xmas! 💃