{"action":"created","issue":{"url":"https://api.github.com/repos/angular/angular.js/issues/15270","repository_url":"https://api.github.com/repos/angular/angular.js","labels_url":"https://api.github.com/repos/angular/angular.js/issues/15270/labels{/name}","comments_url":"https://api.github.com/repos/angular/angular.js/issues/15270/comments","events_url":"https://api.github.com/repos/angular/angular.js/issues/15270/events","html_url":"https://github.com/angular/angular.js/issues/15270","id":183092650,"number":15270,"title":"Add node processing hook to $compile public API.","user":{"login":"Aaron-Pool","id":5634834,"avatar_url":"https://avatars.githubusercontent.com/u/5634834?v=3","gravatar_id":"","url":"https://api.github.com/users/Aaron-Pool","html_url":"https://github.com/Aaron-Pool","followers_url":"https://api.github.com/users/Aaron-Pool/followers","following_url":"https://api.github.com/users/Aaron-Pool/following{/other_user}","gists_url":"https://api.github.com/users/Aaron-Pool/gists{/gist_id}","starred_url":"https://api.github.com/users/Aaron-Pool/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Aaron-Pool/subscriptions","organizations_url":"https://api.github.com/users/Aaron-Pool/orgs","repos_url":"https://api.github.com/users/Aaron-Pool/repos","events_url":"https://api.github.com/users/Aaron-Pool/events{/privacy}","received_events_url":"https://api.github.com/users/Aaron-Pool/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/angular/angular.js/labels/component:%20$compile","name":"component: $compile","color":"e102d8"},{"url":"https://api.github.com/repos/angular/angular.js/labels/frequency:%20low","name":"frequency: low","color":"bfe5bf"},{"url":"https://api.github.com/repos/angular/angular.js/labels/severity:%20confusing","name":"severity: confusing","color":"cd19e7"},{"url":"https://api.github.com/repos/angular/angular.js/labels/type:%20feature","name":"type: feature","color":"00a606"}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2016-10-14T16:22:17Z","updated_at":"2016-10-15T10:47:39Z","closed_at":null,"body":"**Do you want to request a *feature* or report a *bug*?**\r\n\r\nFeature\r\n\r\n**What is the current behavior?**\r\n\r\nI have no way of modifying a node before the majority of compile functionality takes place (that I've found, and yes, I've read the source :) ).\r\n\r\nSuppose I want all components named `mySubmenu` to also have the directive `genericStateListener` applied to them. I've separated out a lot of ui-router state based functionality into it's own directive, in keeping with the separation of concerns principle. I don't want a bunch of generic state handling logic clogging up my component controller. Additionally, I may want to use this state logic on other components that are concerned with state transitions.\r\n\r\nWell, to do this, I have two options (that I know of):\r\n\r\n1) I could place the directive `genericStateListener` in every place I use `mySubmenu`. Well, that's annoying :)\r\n2) I could wrap my template for `mySubmenu` in a block which has the `genericStateListener` directive. This is workable, but it bothers me that someone else viewing my code needs to go into my template to understand that this component has state listening functionality. Additionally, if I want to interact with the `genericStateListener` directive controller, I cannot require it, because it's BELOW me now.\r\n\r\nNow the situation becomes even MORE complex (but also more simple) in the instance that, perhaps I don't want to be tied to a particular functionality/directive for listening to states. I want to abstract it further. In fact, I just want to be able to put an `isStateListener` field on my component. Then, by overriding the `.component` decorator, I can add an annotated field `$stateListener` every time I see this field on my `options` object. GREAT I now have a way to check if the user wants to have stateListener functionality on the component I'm compiling! These are the kinds of things I can EASILY do already in angular's current state. There's only one problem, even once I get said attribute on the final directive object... I can't do anything with it.\r\n\r\nThere's no way of modifying a node prior to the start of the compilation process (before directives are collected). By the time I can add functionality to the $compile process, directives have already been collected. This seriously hampers extensibility of the component object.\r\n\r\n**What is the expected behavior?**\r\n\r\nI would expect there to be a publicly accessible function to be run somewhere in the `collectDirective` function, like this:\r\n\r\n```\r\n  switch (nodeType) {\r\n        case NODE_TYPE_ELEMENT: /* Element */\r\n          // use the node name: <directive>\r\n          runNodeTransforms(nodeName_(node),node); // function exposed on $compileProvider\r\n          addDirective(directives,\r\n              directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);\r\n\r\n          // iterate over the attributes\r\n          for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,\r\n                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {\r\n            var attrStartName = false;\r\n            var attrEndName = false;\r\n\r\n```\r\n\r\nThis would enable me to implement so much additional functionality in a clean, concise, and for the sake of other developers on my project, abstractly. For example, suppose I'm using https://github.com/tenphi/angular-bem, and I want all components to also have a block\r\ndirective on them for simple, clean BEM notation. I could just do this:\r\n\r\n```\r\nfunction componentDecoratorConfig($compileProvider) {\r\n        \"ngInject\";\r\n        var oldProvider = $compileProvider.$get,\r\n            oldComponent = $compileProvider.component;\r\n\r\n        $compileProvider.component = registerComponent;\r\n\r\n        function registerComponent(name, options) {\r\n            options.$isComponent = true;\r\n            return oldComponent.bind($compileProvider)(name, options);\r\n        }\r\n\r\n       $compileProvider.addNodeTransform(function(name, node) {\r\n            if($injector.has(name + 'Directive') \r\n                && $injector.get(name + 'Directive').controller.$isComponent) {\r\n                node.attr.set('block', name);\r\n            }\r\n            return node;\r\n        });\r\n```\r\n\r\nAnd voila! It's done! I'll admit that there are some parts of the compilation process that I don't fully get, and maybe this will have unintended consequences that I don't understand, but it seems like a simple solution to a problem that provides extensibility that is more generic that traditional specific directive decorators.\r\n\r\nThere was a similar pull request done by @lgalfaso , here: https://github.com/angular/angular.js/pull/6781, it seemed to have gotten some good feedback, but it was pretty involved, and it looks like it got shelved.\r\n\r\nI'd be glad to create a pull request, if I thought this functionality had any chance of being merged.\r\n\r\n-Aaron\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/angular/angular.js/issues/comments/253976716","html_url":"https://github.com/angular/angular.js/issues/15270#issuecomment-253976716","issue_url":"https://api.github.com/repos/angular/angular.js/issues/15270","id":253976716,"user":{"login":"gkalpak","id":8604205,"avatar_url":"https://avatars.githubusercontent.com/u/8604205?v=3","gravatar_id":"","url":"https://api.github.com/users/gkalpak","html_url":"https://github.com/gkalpak","followers_url":"https://api.github.com/users/gkalpak/followers","following_url":"https://api.github.com/users/gkalpak/following{/other_user}","gists_url":"https://api.github.com/users/gkalpak/gists{/gist_id}","starred_url":"https://api.github.com/users/gkalpak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gkalpak/subscriptions","organizations_url":"https://api.github.com/users/gkalpak/orgs","repos_url":"https://api.github.com/users/gkalpak/repos","events_url":"https://api.github.com/users/gkalpak/events{/privacy}","received_events_url":"https://api.github.com/users/gkalpak/received_events","type":"User","site_admin":false},"created_at":"2016-10-15T10:47:39Z","updated_at":"2016-10-15T10:47:39Z","body":"I would like to get more opinions. My main concern is that we generally try to avoid introducing features that are difficult or impossible to map to Angular 2, as that would make it much harder for people to migrate their apps. And I am not sure if something similar is able in ng2 in a straight-forward way."}}
{"actor":{"display_login":"gkalpak"}}