Reputation: 6074
Let's say there is a simple framework to display popups:
@Component(
selector: 'popup-host',
template: '''
<div class="popup-container">
<ng-template #popupRef></ng-template>
</div>
''',
styles: ['.popup-container { position: absolute; top: 100; left: 100; z-index: 100; }'],
)
class PopupContainerComponent {
final PopupController _controller;
final ComponentLoader _loader;
PopupContainerComponent(this._controller, this._loader);
void ngOnInit() {
_controller.container = this;
}
@ViewChild('popupRef', read: ComponentRef)
ComponentRef popupRef;
void render(PopupConfig config) {
final componentRef = _loader.loadNextTo(config.factory, popupRef);
if (componentRef.instance is HasValueSetter) {
componentRef.instance.value = config.value;
}
}
}
@Injectable()
class PopupController {
PopupContainerComponent _container;
set container(PopupContainerComponent container) => _container = container;
void showPopup(PopupConfig config) {
container.render(config);
}
...
}
class PopupConfig {
final ComponentFactory factory;
final dynamic value;
PopupConfig(this.factory, [this.value]);
}
abstract class HasValueSetter {
set value(dynamic value);
}
This can then be used like this:
// Somewhere in the root template
<popup-host></popup-host>
// In popup.dart
@Component(
selector: 'happy-popup',
template: '''
<div class="header">This is the popup content.</div>
<div class="main">The value is {{value}}.</div>
<div class="footer">I am happy!</div>
''',
)
class HappyPopupComponent implements HasValueSetter {
@override
dynamic value;
}
// In some_other.dart
@Component(
...
styles: [
'.header { font-weight: bold }',
'.main { color: red }',
'.footer { color: green; font-style: italic }',
],
...
)
class SomeOtherComponent {
final PopupController _popupController;
...
SomeOtherComponent(this._popupController, ...) ...;
void displayPopup() {
_popupController.showPopup(HappyPopupComponentNgFactory, 42);
}
}
...
Is there a way to forward styles from <some-other-component>
to <happy-popup>
without having to define them at the root of the app?
Upvotes: 8
Views: 5182
Reputation: 14577
In addition to methods already mentioned I would suggest two more avenues to explore:
since Angular scopes CSS to components and we'd like to keep it this way your crossing component boundary can be done by finding out what scope Angular assigned to it and adding manually scoped CSS into global <style>
tag on the page:
@ViewChild('popupRef') popupRef;
ngAfterViewInit() {
this.popupRef.nativeElement.attributes[0].name // this will have a value similar to _ngcontent-tro-c1
which you will need to scope all your custom CSS with.
}
one apparent drawback of this approach is that Angular conceals CSS management and therefore you'll have to resort to plain JS to manage it. (one example here)
Personally I'd explore the second option as it seems to be less hacky
Upvotes: 0
Reputation: 4193
You can send prop value to component, which can be custom class and put it in your popop html. And then in scss file add extra css overrides for specific class. So for each custom component you can have custom css code.
PS: And yes, i would suggest to import scss file like:
@Component(
styleUrls: ['./hero1.css'],
)
It is just better to seperate css from js + your css code then can be much longer, containing all styling cases.
Upvotes: 0
Reputation: 904
As your popup isn't a child of the component that opened it you cannot use ::ng-deep
the only thing I think that will work is to remove view encapsulation from the host, the popup and the component that opens the popup (try only the popup and component that opens the popup first, if that doesn't work, remove the host's encapsulation as well.)
@Component(
selector: 'happy-popup',
template: '''
<div class="header">This is the popup content.</div>
<div class="main">The value is {{value}}.</div>
<div class="footer">I am happy!</div>
''',
encapsulation: ViewEncapsulation.None // <=== no encapsulation at all
)
class HappyPopupComponent implements HasValueSetter {
Upvotes: 1
Reputation: 8292
You could achieve this by splitting your components code into separate files - or separate CSS file in your case.
Instead of writing the style straight in the component's - styles
, you would import the CSS file by using the styleUrls
. That way you can pass a file(s) with your styles, and the file can be shared amongst multiple components.
@Component(
styleUrls: ['./hero1.css', './folder/hero2.css'],
)
Bear in mind that the URLs in styleUrls are relative to the component.
Another benefit of importing the css with styleUrls
is that it also grants you the ability to use imports within that file.
hero1.css
@import './folder/hero2.css';
FYI: It's a common practice to split your components code into separate files.
And then in your dart file reference them as:
@Component(
templateUrl: './hero.html',
styleUrls: ['./hero.css'],
)
Please refer to AngularDart - Component Styles for brief information about this.
Upvotes: 6
Reputation: 20102
You can combine scss with your code
First you need to seperate the scss file you want to share accross the app
For example:
In style1.scss
.header { font-weight: bold }
Then in style2.scss
@import "style1"
Or you can combine list of scss file in your component code by define in the list of array
styleUrls: ['./style1.scss', './style2.scss'],
This is how you can manual config scss support for angular cli
In angular.json add
"projects": {
"app": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": { // add this config
"@schematics/angular:component": {
"style": "scss"
}
},
Upvotes: 0