Open schmod opened 8 years ago
That would be a nice addition indeed. I am not sure if this is reasonably possible in Angular 1.x.
Note that Angular 2 has its own parsers for HTML and CSS (among other things), which gives it the ability to do much more advanced transformations. (And it also has offline compiling capabilities, which gives it the option to get rid of the bloat at runtime.)
Adding all that to Angular 1 would considerably increase the size of the framework and the internal complexity (as if $compile
is not complicated enough already :stuck_out_tongue:).
But it is a nice feature indeed. Putting it in the backlog, but don't hold your breath :stuck_out_tongue:
I would think this would be doable by creating an external module that has an extensibility hook into $compile (maybe making it exclusive to components), then adding the module as a dependency. Such a module would probably need to use the same parsing mechanism from @angular/compiler though for parity & for seamless upgrading (compiling appears to be a simple matter, as seen here. I don't think HTML parsing would be necessary, since this request sounds like it refers more to the style
option of the component decorator in Angular 2.
Combined with @angular/upgrade, this may be a doable task, although if one is going the upgrade path, I'm not sure how much value there is in duplicating logic here (it would increase the JS served to bootstrap the app). I get the impression that Angular 1's core feature set is mostly frozen due to the amount of resources shifted to Angular 2 & to create stability due to a greater focus on getting users to Angular 2, although I may be mistaken. In addition, there is the challenge of making sure it is in sync with whatever breaking changes happen in Angular 2, which there are some still yet to happen in the release candidates.
If you wanted to prototype this for interest, I actually don't think you need any extensibility hooks at all - it can be done entirely with overriding .directive
and .component
in a .config
call.
The class and/or attribute used to emulated Shadow DOM can be added by modifying the compile
function, and the addition/removal of stylesheets can be easily done in link/$destroy.
I had prototyped a project to dynamically add/remove stylesheets so that the styles only exist when a directive is actually present on the page (perf testing), but it's not that big of a stretch to expand that to this, would just need to drop a CSS parser into it.
I'm actually pretty fascinated that Angular 2 has its own (large and fairly complex) CSS parser.
I wonder if the ng2 folks have ever considered pulling it out into a standalone library...
I'd like to discuss a simple but seemingly good enough solution for this issue. What if components had a cssClassPrefix
setting? With this setting set, every class
and ng-class
directive in the component's template should work a bit differently: 1) prefix every class name, 2) understand some escaping syntax for 'global' class names.
E.g. this markup
<div class="foo bar @baz">...</div>
would become the following DOM
<div class="my-component--foo my-component--bar baz">...</div>
It's important that this setting should work on the template level and shouldn't affect any nested templates. For this to be possible, the class
and ng-class
directives need to understand somehow in which template they're located and be able to obtain the settings associated with this template. It's something that directives can't do in the current version of AngularJS.
If we had this, the rest could be done just with LESS and its &
syntax or rather with a simple custom PostCSS-based preprocessor. E.g. we can have custom syntax like:
@component my-component {
foo { color: black; }
bar { color: white; }
}
compiled to
my-component--foo { color: black; }
my-component--foo { color: white; }
Component names seem to be good enough prefixes, however it's totally easy to make class names even more unique by passing them through some function used by both AngularJS and the preprocessor.
@thorn0 That defeats the point though, no? You would need to use said prefix in all of your CSS, so you may as well just have written the prefixed className to begin with. You would also need to make sure that your prefix itself is unique between components, otherwise you again risk collisions. This also gives up a different optimization wherein the styles for a component are only present on the page if at least one component is currently present.
I have not circled back to this yet, but one idea to keep the impact of this change down would actually be to use the browser's own CSS parser for the CSS modifications, but that potentially means that any styleUrl
styles that aren't present in the local cache would need to be present on the same domain to be fetched (or have CORS enabled), but that's no different than templateUrl
I suppose.
@dcherman For a component, I'd have to write the prefix only twice: one time in its settings and one time in the LESS file. As for uniqueness, component names are unique. Why not use them as prefixes?
Instead of LESS, a simple custom build-time transformation can be easily created using a framework like PostCSS. Moreover, for something as simple as prefixing, I doubt we even need a parser. A good regexp may suffice, so the code might turn out to be really tiny and usable for a run-time transformation. (Yet I don't really think run-time transformations and optimizations are that valuable. For production, everyone uses bundling anyway. If templateUrl
got removed from Angular, I wouldn't be sad at all.)
since the #15805 was closed adding it here also:
Do you want to request a feature or report a bug?
feature
What is the current behavior?
angularjs does not include css styles loader like the html template loader as part of the components definitions.
lets say we have a component:
module.component('myComponent', {
template: '<some-html></some-html>' // or we can use templateUrl: 'path/to/template.html'
}
What is the expected behavior?
I would love to add something like:
module.component('myComponent', {
template: '<some-html></some-html>' , // or we can use templateUrl: 'path/to/template.html'
// the addion
styles: '.some-css { color: green;}' // or styleUrls: ['path/to/file.css', 'another/path/to/file.css']
}
What is the motivation / use case for changing the behavior?
Other information (e.g. stacktraces, related issues, suggestions how to fix)
+1
+1
+1
+1
Yes please!
I tried to play with the approach described in my comment. However, hacking class
and ng-class
directives, I faced problems due to #4383.
If anyone is curious to see it, a proof of concept can be found here: http://jsbin.com/timageb/edit?html,css,js,output
It might be a monstrous hack, but its potential for maintainability improvement is huge.
+1
+1
+1
Do you want to request a feature or report a bug?
Feature.
Has there been any discussion about backporting Angular 2's component CSS support (with emulated view encapsulation) support to work with Angular 1 components?
While projects like angular-css provide similar functionality, there does not appear to be a solution for Angular 1.x applications that provides true view-encapsulation.
IMO, this is one of the most useful (and under-appreciated) features of Angular 2. This feature would be an enormous benefit to existing Angular 1.x applications, and could provide another tool for owners of legacy applications to gradually adopt Angular 2 (while improving the modularity of their existing applications).
If this has been discussed before, please feel free to close as a duplicate -- I couldn't find any previous discussion on this topic.