I want to set a class active on a div (part of a component) if a variable is true (workspace.active here) AND an ancestor element has class .home.
Something like:
<div [ngClass]="{'active': workspace.active && ':host-context(.home)', }">
Can I use somehow this pseudo selector :host-context in such an conditional expression for ngClass ?
Details:
I want to use same component in two use cases. Only some css properties should be different on the two cases. So I want to customize a css class set on a div on my component based on decision: "there is an ancestor home in the dom tree or not" - this should differentiate the two use cases.
I could do things like this in css:
:host-context(.home) .active {
background-color: #405976;
}
but then all selector combinations containing .active class should be combined also with :host-context and I I don't want to grow the complexity in css as it is already complex.
I would prefer to just set the class .active based on the condition. In css file !, not in code. (This is why :host-context exists in the end.)
In angular you should not make any logical decisions in the code based on the html content properties such as classes or attributes, but vice versa - you should render classes and attributes in html based on data bindings. That's the main idea of angular - rendering view based on data bindings. Component's code should not really care too much about view structure.
So, in this case if your class should be based on some external information you need to #Import() that data through data bindings into your component and then use component properties in the ngClass directive. Yes, it moves logic into the component instead of html/css, but that's where it's supposed to be anyway: in the model/controller code, not in the view markup. Also, this way it will be much more convenient to test such a component.
Related
When creating Web Components with encapsulated styles using Shadow DOM, parts of the shadowed markup can be styled using the ::part pseudo selector (https://developer.mozilla.org/en-US/docs/Web/CSS/::part).
Can the part selector be used to target nested shadow parts?
<custom-element>
#shadow-root
<div part="thats-easy"></div>
<another-custom-element part="proxy-part">
#shadow-root
<div part="target-me"></div>
</another-custom-element>
</custom-element>
Current efforts were fruitless:
another-custom-element::part(target-me) { }
custom-element::part(proxy-part) another-custom-element::part(target-me) { }
custom-element::part(proxy-part another-custom-element::part(target-me)) { }
custom-element::part(proxy-part::part(target-me)) { }
```
Nope. It is not possible. It kind a breaks the encapsulation principle. The right way is to use proper theming. That means using a combination of:
::part - For direct theming of the component
:host-context - for theming based on the context
::slotted - For styling the slotted element inside the styling
For more dynamic theming, you can use above styles in combination with Element.matches API. Whatever the class/context that the user of the component has set, you can then change the styling of nested children component.
On a side note, modifying the styling of a decadent component (children of children) is a bad practice even when not using Shadow DOM or Web Components. It will result in a brittle non-maintainable CSS.
Edit Note:
:host-context is not implemented in all browsers and probably never will.
Fun twist, it is possible and TIL about exportparts
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/exportparts
How do I define a style in a parent component and then pass it to a child component e.g.?
<style>
.teststyle {
background-color: red;
width: 100px;
}
</style>
I thought if I did not use scoped the .teststyle would be available to the child, but it didn't work for me.
I can pass the style to use in a v-bind:style command using props cannot find a way to pass (or make available) for use with v-bind:class.
The child component is for re-use by many parent components each parent component with different style/class attributes each with different properties.
In one example the child component is a generic table and it needs things like column widths, cell colors etc.
In another instance the child component is a grid css layout and that needs no, columns, column layout etc.
What I normally do is I try to design the component as simply and cleanly as possible:
Give the root element a sensible class name (e.g. flyout).
Give child elements class names that use the root element's class name as a prefix (e.g. flyout-title, flyout-content, etc). Sometimes I'll abbreviate the root element's class name if it is long (as fly- or whatever).
<div class="flyout">
<div class="flyout-title">{{ title }}</div>
<div class="flyout-content"><slot/></div>
</div>
This is just my own class naming convention, but you can use whatever as long as it's consistent and unlikely to clash with other class names app-wide.
Now, when you use <flyout> as a child component and you want to style it with CSS, you give it a class name specific to the parent component. For example, if your parent component is app-menu then give the flyout the class name app-menu-flyout. Notice that this convention is the same as the aforementioned; always try to be consistent.
<flyout class="app-menu-flyout"/>
In your <style> section of the parent component, you can declare styles for the child component as follows:
.flyout.app-menu-flyout {
/* Root element */
}
.flyout.app-menu-flyout .flyout-content {
/* Child element */
}
I'm using selectors like this so that they are more specific and will override any styles defined on the child component itself. It'll also work regardless of the order in which the CSS ends up being (order may not be guaranteed by Webpack).
Note that this makes the parent and child components tightly coupled regarding the structure of the child component's template and the class names used. If you change the child component's template and/or class names, then you need to change the corresponding CSS in every other component that declares overriding styles for that component.
If you are using scoped CSS, then pay attention to how child components should be styled.
For example, .button{} selects Button class and .text-area{} selects TextArea class. So when it does that, does that select the entire class itself(opposed to specific instances of a class)? If it does, is there any way for Javafx CSS to select a specific instance of a class or just in general, a variable?
You're selecting every Node containing the style class contained in the location where you apply the css stylesheet.
For some nodes one or more style classes are added, it's also possible to modify them.
someNode.getStyleClass().setAll("my-class");
To select individual nodes though usually a id selector is used:
mySpecialButton.setId("special-button");
CSS
#special-button {
/* TODO... */
}
I've been using BEM style CSS to style my angular directives and usually use replace: true to so that my Block level class can be on the "root" of the custom element. This makes it so that I can write all my CSS primarily with classes.
However, replace: true sometimes causes issues (having two ng-if, etc...) and is now marked as deprecated. So I'm starting to try to stay away from replace completely.
But now I'm having trouble applying BEM to these elements that have an actual custom tag the DOM -- now I have to use a tag name instead of a class name, which means I can't really use BEM anymore (since I'll have to use the tag name since I can't apply classes directly to my element in my template). Additionally, using modifiers on my custom element now seems impossible, as does using sibling CSS selectors.
Here's an example that hopefully will illustrate what I mean:
The directive:
angular.module('my.module')
.directive('customElement', function() {
return {
restrict: 'E',
scope: {
isSpecial: '='
},
template: '<div class="custom-element" ng-class="{\'custom-element--special\': isSpecial"></div>'
};
});
The CSS:
.custom-element {
background-color: white;
}
.custom-element--special {
background-color: red;
}
.custom-element--special + .custom-element--special { // this won't work without replace: true
background-color: blue;
}
If I use replace: true everything works as expected (but then it comes with its own headaches).
If I don't use replace, the classes are not applied to the root custom element so the child selector doesn't work.
I could always add classes to the element in the postLink function, but that makes the template much less clear.
Does anyone have any experience using BEM with angular and using classes instead of tag names in your custom directives? What did you do to solve this problem?
i known it's a problem having replace:false for readability purpose.
The actual problem is that we need our OOCSS but you are handling Angular Components with custom tags has CSS Objects, and is not the case.
There is no practical solution for this, i won't recommend you to start adding classes on postLink function.
However what we are use to do is treat the custom tag as is own CSS Object besides the inner object structure. Forcing us to implement an extra CSS class for the custom tag.
block-context
block-context__element
custom-element
Why doing this when block-context__element is a redundant' class?
Because the rest of your BEM structure is the one you will maintain, the custom-element block should have meaning by it self and the block-context__element element is no expected to, you should abstract the CSS Objects from the directive's implementation, if you in some point start changing your html components your classes should still apply.
I hope this answer helps you
I'm familiar with assigning CSS classes to GWT elements to control their formatting, but what if I want to change an attribute in one of those CSS classes?
I've got a styled list of data. CSS classes are used to indicate the various data types (important, routine, trivial). I wish to allow the user to hide trivial entries. I'd like to modify the span.trivial CSS class to set display:none
I'm aware I could loop through the entries, see if an entry is trivial and add a noShow class (which itself has display:none) - but then I'm doing the looping, I'd rather let the browser do the work.
Is this possible in GWT?
Ian
I assume we have a structure similar to the following one
<div>
<span class="routine">A</span>
<span class="trivial">B</span>
<span class="trivial">C</span>
<div>
This is how I would solve the problem:
.hideTrivial span.trivial {
display: none;
}
<div class="hideTrivial">
<span class="routine">A</span>
<span class="trivial">B</span>
<span class="trivial">C</span>
<div>
The ".hideTrivial span.trivial" selector applies only to "trivial" spans, if they occur within another element that has the class "hideTrivial". (Note: The span doesn't have to be a direct child of the "hideTrivial" div - it's ok, if you have a deeper element hierarchy.)
So to turn on/off hiding, you simply add/remove the "hideTrivial" class from the outer div.
(This technique can be used with and without GWT.)
AFAIK, javascript can not change the CSS file and have it reapplied. The same goes for GWT (since it compiles down to JS). So, you can not change a CSS rule and have all elements in your DOM reflect the change.
However, you can get a style of a DOM element and change that style. But that is for a particular element. In your case you'd still need to write code to traverses a set of element and make the change.
My suggestion would be to look at gwtQuery (a port, not a wrapper, of jQuery to GWT). It's super-efficient and super-compact. Here is a one-liner to do what you need:
$("span.trivial").hide()
Fot those who need to modify global CSS property values: you can choose StyleInjector for that purpose.
http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/dom/client/StyleInjector.html