Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: angular.component helper #10007

Closed
johnlindquist opened this issue Nov 11, 2014 · 119 comments
Closed

Feature Request: angular.component helper #10007

johnlindquist opened this issue Nov 11, 2014 · 119 comments

Comments

@johnlindquist
Copy link
Contributor

@johnlindquist johnlindquist commented Nov 11, 2014

Please see this demo: https://jsbin.com/yixote/11/edit?html,js,output

Thanks to "bindToController" in angular 1.3, we're able to create a much simpler api for building components.

Just as "angular.service" helps us to easily build an "angular.provider", I strongly believe a simplified "angular.component" could help us easily build components with "angular.directive".

I'm sure everyone will have plenty of feedback :)

@caitp
Copy link
Contributor

@caitp caitp commented Nov 11, 2014

I feel like it's adding another way to do the same thing, which I tend to not like doing, buuuuut, maybe.

@petebacondarwin what do you think?

@johnlindquist
Copy link
Contributor Author

@johnlindquist johnlindquist commented Nov 11, 2014

@caitp does anyone use angular.provider? Nope, the use angular.factory or angular.service. I think it's time for angular.directive to get the same treatment :)

@caitp
Copy link
Contributor

@caitp caitp commented Nov 11, 2014

people use angular.provider if they want to be able to operate on the object meaningfully within config blocks :> anyways, my personal opinion is that we sort of offer too many flavours of koolaid already, it's much simpler for people if there's just one way to do everything.

On the other hand, the directive API is ridiculously complicated, so maybe some sugar would be useful for it. Lets see what people think

@pkozlowski-opensource
Copy link
Member

@pkozlowski-opensource pkozlowski-opensource commented Nov 11, 2014

IMO convince shortcuts are cool / important but I would rather not do it in 1.3 for 2 reasons:

  • learning directives is already hard and introducing yet another approach will only further confuse people. On the other hand guys who know what they are doing are probably having convenience shortcuts;
  • component is kind of bad name / timing given Angular2 effort.

I'm not opposed but I would prefer that we don't do it. My private, personal opinion :-)

@johnlindquist
Copy link
Contributor Author

@johnlindquist johnlindquist commented Nov 11, 2014

@petebacondarwin I agree with your points, but those of us building convenience shortcuts would love to standardize on these shortcuts for the community, teaching, etc. Having something blessed by the angular team would be wonderful, but we can figure out something else if not.

@petebacondarwin
Copy link
Member

@petebacondarwin petebacondarwin commented Nov 11, 2014

@johnlindquist - hey I haven't even commented yet!

I think this would defeat a strong reason to migrate to v2!!

But seriously while it would be nice to make directive development easier I agree that 1.3 is probably not the place.

From what I see this helper would change

mod.directive ('cmpnt', function () {
  return {
    controllerAs: 'cmpnt',
    link: linkFn,
    scope: scopeDef,
    template: template,
    controller: ControllerFn
  };
});

Into

mod.component ('cmpnt', template, scopeDef, controller, linkFn);

While it certainly has fewer chars I am not convinced this is much more grokable. Also as a general rule we are trying to move away from optional positional params.

Personally I don't think this should go in the core for 1.x but if there was large community pressure we could look at improving the defaults for the DDO in a 1.4 release.

@johnlindquist
Copy link
Contributor Author

@johnlindquist johnlindquist commented Nov 11, 2014

@petebacondarwin sorry, I thought @pkozlowski-opensource was you :)

  1. grokable - I would argue that:
mod.component('card', template);

is _much_ more grokable than

mod.directive('card', function(){
return {
template: template
}
})

The goal is to lessen the barrier between creating directives and cover the 90% scenario. Also, if the focus is on injecting providers into the controller (and not the directive), the factory function (the second param in .directive) just becomes cruft.

  1. params - I totally agree on position params. If you want lots of {options}, use .directive(), if you want to cover the 90% scenario, use .component() or whatever you want to name it.
  2. 1.3 - Agreed, 1.3 is probably the wrong place, but the Angular community now has years of experience under its belt and it feels to me like it's time to start wrapping some of the most common tasks with more helpful APIs and revisit how we introduce newcomers to Angular.

Anyway, this all stems from the larger community sentiment that "angular is hard". I teach angular all the time and I've seen people get super confused over what should be the easiest concepts because of the API. I know angular is easier than it lets on, but I think a simpler API blessed by the angular team would go a long way to convince everyone else :P.

Obviously none of this is necessary and it doesn't add any functionality, but that doesn't mean it's not worth it!

/end rant?

@petebacondarwin
Copy link
Member

@petebacondarwin petebacondarwin commented Nov 11, 2014

In many ways I agree with you John. The complicated directive api is a major factor in the drive to v2 where the api is completely reworked to get away from this unnecessary complexity.

I also note that most of the service confusion comes from the difference between service and factory rather than with provider.

The question is where is the right place to make the improvement.

@johnlindquist
Copy link
Contributor Author

@johnlindquist johnlindquist commented Nov 11, 2014

@petebacondarwin are you at Google HQ now? I'm coming over next month or so to talk with the guys about doing new videos for the homepage, etc. Would be fun/constructive to play around with simple APIs, even if they land in a different project.

@petebacondarwin
Copy link
Member

@petebacondarwin petebacondarwin commented Nov 28, 2014

I am as always in London, UK. Give me a shout when you are next over this side of the pond

@demisx
Copy link

@demisx demisx commented Dec 12, 2014

I would like to add my 2 cents since we are in the business of developing various enterprise applications. Please keep in mind that I share our team opinion only hoping it may add value.

I like the idea of simplifying the directive API, but calling this variant a 'component' would be very confusing. In our understanding, A component bears a much higher abstraction. A component is a stateless isolated chunk of product functionality (think of app features) that entire app is broken down into. A component may encapsulate a various number of resources/assets that are necessary to deliver that particular app feature. For example, a 'profile' component, besides directives, may contain services, images, SASS, filters etc. - everything that is necessary for this component/feature to work. What @johnlindquist shows here, appears to be more of a UI widget, then component, since it is implemented via one directive. So, maybe, if this was defined as module.widget instead, it would make more sense. Otherwise, there would be an overlap of concepts.

@kentcdodds
Copy link
Member

@kentcdodds kentcdodds commented Dec 15, 2014

Heard this is actually going to happen! ['hip', 'hip'] 👏

@vivainio
Copy link

@vivainio vivainio commented Dec 15, 2014

Hopefully using templateUrl instead of direct template is going to be straightforward.

@thorn0
Copy link
Contributor

@thorn0 thorn0 commented Dec 15, 2014

#5893 is related to this kind of directives, so it might make sense to consider doing it as well

@kentcdodds
Copy link
Member

@kentcdodds kentcdodds commented Dec 17, 2014

Oh, just wanted to make sure that this is mentioned, but I believe it is the desire of everyone to move to the controllerAs syntax. If this angular.component supported that by default it would be great. Not sure how to make that happen without requiring the developer to specify the controller's name (vm for example), but I definitely think that angular.component should default to bindToController and controllerAs: 'somethingSpecifiedByTheDeveloper'.

@petebacondarwin
Copy link
Member

@petebacondarwin petebacondarwin commented Dec 17, 2014

@kentcdodds - this is included in @johnlindquist's proposal. By default it uses the name provided as the first parameter to the call unless it is specifically provided as a controllerAs property on the config parameter.

@kentcdodds
Copy link
Member

@kentcdodds kentcdodds commented Dec 17, 2014

Duh, must have missed that. Thanks for setting me straight @petebacondarwin :-)

@Zizzamia
Copy link
Contributor

@Zizzamia Zizzamia commented Dec 24, 2014

In angular-seed there is already an orientation to build Component related app. I can understand can be confusing have Web Components and Angular Components, but have an official angular.component will totally #simplify the way to scaffold new projects and improve your angular.component version by version. +1 for angular.component

@petebacondarwin petebacondarwin modified the milestones: 1.4.x, 1.3.x Jan 12, 2015
@a-lucas
Copy link

@a-lucas a-lucas commented Jan 22, 2015

@demisx

I totally agree on the component naming. widget is much more appropriate than component.

@demisx
Copy link

@demisx demisx commented Jan 22, 2015

@a-lucas 👍 FYI, here is how we define and break down app into components: AngularAtom component based organization) post. A component is so much more, than just a directive.

@a-lucas
Copy link

@a-lucas a-lucas commented Jan 22, 2015

@demisx
I still don't understand the difference between a module and a component. This folder structure described in the link you provided matches almost exactly the one used in the MEAN.js project.

I usually organize my code the same way, because it makes it easier to find and visualize files in large projects. ( The project I actually work on has around a hundred controllers)

For re-usability purpose, it is better to have every folder being an independent module. But this is not that easy. Taking the example of a profile module (or profile component). One of the mandatory condition for re usability of the profile 'component' is that both project uses a very similar data structure.

But again, this can be tweaked into sub-module : I do have for example my profile module organized this way :

  • profile module
    • personal informations sub-module
      /partials & controllers & routes
    • address sub-module
      /partials & controllers & routes
    • documents sub-modules
      /partials & controllers & routes
    • status sub-modules
      /partials & controllers & routes
      and the list goes on.

I just don't get what advantages components would bring to this existing code organisation.

@caitp
Copy link
Contributor

@caitp caitp commented Jul 3, 2015

arguably, it's actually not very good to have a choice. It creates multiple ways to do a given thing, and that's generally not very good for an API (leads to confusion). This is a problem with the angular.component helper itself, but I think we've sort of let it slide this time? The point of the angular.component helper isn't really a "make migration to angular2 easier" or "make angular1 look like angular2" --- it's really just for making the common use case that a lot of people following john papa's style a lot easier to write.

We've discussed this, and we don't actually want to make angular1 look like angular2, because this will effectively make migration more difficult, not easier. The approach we're leaning on for migration right now is to support running angular1 stuff in angular2, and vice versa (I do not speak for Herr AngularTeam, but this is basically the conclusion you get from reading the plans)

@pbastowski
Copy link

@pbastowski pbastowski commented Jul 3, 2015

@caitp Ok. Good to know.

@petebacondarwin
Copy link
Member

@petebacondarwin petebacondarwin commented Jul 3, 2015

Thanks everyone who is showing an interest in this issue. We are keen to get some form of this into Angular 1.5. As is pointed out, the primary reason is to make it easier to write the most common form of directive; but there are some upgrade side-effects too.

This component style of writing directives is certainly closer conceptually to components in Angular 2, and while I am totally in agreement that we should not be trying to sugar the Angular 1 syntax to make it look superficially like that of Angular 2 the benefits of writing components in this way will lead to easier maintenance and cleaner code.

It is worth linking in here the team's document on proposed 1->2 upgrade strategies.
https://docs.google.com/document/d/1xvBZoFuNq9hsgRhPPZOJC-Z48AHEbIBPlOCBTSD8m0Y/edit
This is still a WIP progress but you can see the directions that we are considering. Feel free to comment if you would like to contribute to the discussion.

@orizens
Copy link

@orizens orizens commented Aug 23, 2015

hi.
I just saw this thread.
a couple of months ago, after reading pascal precht post about using angular 2 with ES5, I created angular2to1 npm module in order to experiment with the new component syntax.
Up to now, I implemented some of these annotations: Component, View, Class in its simple form. Still, a lot of work to do, however, it gave me the oppoertunity to explore some of angular 2 syntax and concepts whle working in angular 1.
Currently, I'm using it in my open source project Echoes Player, i.e in the "youtube-videos" component.
Do you think (as i do) that its a module that will give benefits to others?

@petebacondarwin
Copy link
Member

@petebacondarwin petebacondarwin commented Aug 24, 2015

@orizens You should be getting involved with https://github.com/ngUpgraders. This is the team that are working towards a single solution for this, which has the approval of the Angular team.

@shairez
Copy link
Contributor

@shairez shairez commented Dec 22, 2015

Sorry to nudge in with yet another question -

The problem I run into when writing lots of "component like" directives is the unnecessarily repeated configuration over and over again.

The first being the .controller registration by name, and the second one being the controllerAs as "vm".

Registering controllers

Registering controllers by name in a component based architecture is useful only for unit tests, where you'd want to use $controller to create an instance of the component's controller.

But registering it over and over again is redundant and can be done by the .component.

controllerAs

The controllerAs: "vm" is the best practice AFAIK and I think it should be the default moving forward, you can always override it.

Maybe we should add an "opt in" configuration for people who want to use a default "controllerAs", because adding it for every component is very annoying.

Example

So we should end up with something where the .component becomes a true "annotation like" thing, something like:

angular
 .module('myModule')
 .component('myComp', {
   controller: MyCompController,
   templateUrl: 'my-comp.html'
  })

function MyCompController(){

}

$controller('myComp') // <-- should be an instance of MyCompController

And we could refer to our component as "vm" in our templates.

I'd love to hear what you think about it and what are the cons of this approach

@wesleycho
Copy link
Contributor

@wesleycho wesleycho commented Dec 22, 2015

I absolutely would not want to see controllerAs: vm as default, and would be very unhappy if that were the case, as would a lot of the angular community as well that I interact with daily - as far as I've seen, controllerAs: vm is divisive, and IMO, far from a best practice.

Anyhow, such a feature request probably should belong in a separate issue rather than clutter up this one.

@shahata
Copy link
Contributor

@shahata shahata commented Dec 22, 2015

@shairez I think you are saying two things:

  1. controllerAs should default to vm and not to component name - I agree that defaulting to component name might not be the correct thing to do. It would be easier for people to always use the same name unless they need to reference different controllers in the template, which is where they would configure a custom controllerAs. We are already discussing this and will probably default to $ctrl.
  2. there should be an easy way to get the controller of a component for unit tests - $controller('myComp'). That's a nice idea. For ES6 apps you can actually do something like $controller(MyCompController) but I understand how in ES5 apps you wouldn't want to put MyCompController on the global namespace. @petebacondarwin WDYT?
@Narretz
Copy link
Contributor

@Narretz Narretz commented Dec 22, 2015

We've talked about the default controllerAs name and we will probably
change it before 1.5. We're just not sure what it'll be and we're going to
be open for suggestions.
Am 22.12.2015 20:34 schrieb "Shahar Talmi" notifications@github.com:

@shairez https://github.com/shairez I think you are saying two things:

  1. controllerAs should default to vm and not to component name - I
    agree that defaulting to component name might not be the correct thing to
    do. It would be easier for people to always use the same name unless they
    need to reference different controllers in the template, which is where
    they would configure a custom controllerAs. We are already discussing
    and will probably default to $ctrl.
  2. there should be an easy way to get the controller of a component
    for unit tests - $controller('myComp'). That's a nice idea. For ES6
    apps you can actually do something like $controller(MyCompController)
    but I understand how in ES5 apps you wouldn't want to put
    MyCompController on the global namespace. @petebacondarwin
    https://github.com/petebacondarwin WDYT?


Reply to this email directly or view it on GitHub
#10007 (comment)
.

@shairez
Copy link
Contributor

@shairez shairez commented Dec 22, 2015

@wesleycho you're right, I should have probably opened up 2 separate issues for these questions, there is a nicer way of suggesting it though.

@shahata @Narretz thanks for the comments, let me know if there is another open issue for the discussion of the consistent controllerAs name (couldn't find it), I'd love to help!

About the controller registration, I'm also waiting for @petebacondarwin response, and then we can decide whether to open up a new issue for that as well. (I will also submit a PR if we'll agree it's a good addition)

Thanks!

@drpicox
Copy link
Contributor

@drpicox drpicox commented Dec 23, 2015

+1 to controllerAs: 'vm' as default, and my reason is the following:

If all directives have the same controller name you can leverage on that:

<my-logic-toggle as="someToggle"></my-logic-toggle>
<some-content ng-show="vm.someToggle.opened></some-content>

or

<button ng-click="vm.pager.first()">First</button>
<my-pager as="pager" elements="element as vm.elements">
  <my-element element="element"></my-element>
</my-pager>
<button ng-click="vm.pager.next()">Next</button>

or

<button ng-click="vm.play()">Play</button>
<audio as="audio">
    <source src="some.mp3" type="audio/mpeg">
</audio>

and controller contains (it requires a controller because Angular forbids use DOM objects in template expressions):

vm.play = function() {
  vm.audio.play();
};

It assigns it inside vm because it is a variable for all template, it does not matters about scopes in the same template. But I have to confess that I have a second one directive to connect things inside scopes (for example inside an ng-repeat).
Anyway, it is very handy to connect component controllers just like that, ng2 introduces it but we can use it in ng1 (I'm doing it since 1.2).

Btw: it can be vm, or ctr, or anyother else, but it should be always the same name, short to save some bytes, if possible

@petebacondarwin
Copy link
Member

@petebacondarwin petebacondarwin commented Jan 2, 2016

@drpicox - I am not convinced that your suggestions are a good idea, if I understand it right.
I think you are saying that these snippets would be contained within a component that has a controller and that this controller would be attached to the scope as vm, right?

That is OK but I don't like that you are making that assumption for your custom directives, such as my-logic-toggle. This is brittle, since it is always possible that someone might choose to name their controller something else, overriding the default of vm or whatever it is. Moreover it is inconsistent, since you have one bit of template referring to something simply as someToggle and another bit referring to it as vm.someToggle.

I would be more comfortable if the as attribute referenced the controller explicitly...

<my-logic-toggle as="vm.someToggle"></my-logic-toggle>
<some-content ng-show="vm.someToggle.opened></some-content>

in which case this particular argument to have a consistent naming is no longer necessary.


That being said, I still do think that we need a consistent naming for directive controllers that are made available on the scope; just not for the reason given.

@petebacondarwin
Copy link
Member

@petebacondarwin petebacondarwin commented Jan 2, 2016

I made a new issue #13664

@drpicox
Copy link
Contributor

@drpicox drpicox commented Jan 2, 2016

@petebacondarwin You're right and I agree.

Also about being explicit, thanks, I'll introduce it.
I missed it because I was more concerned in performance than expressivity, implicit version of vm there is no need for $parse.

@shairez
Copy link
Contributor

@shairez shairez commented Jan 6, 2016

As for the second point I raised - auto creating a controller - I've opened up a separate issue #13683

let me know what you think

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.