I am trying to build a little project using web components but I'm quite unexperienced with them and I'm kind of stuck.
I would like to write something like this in my HTML file
<my-sum>
<my-unit>
<my-unit>
<my-unit>
</my-sum>
and obtain something like
1 + 1 + 1
I don't have issues rendering my-unit as 1, but I don't know how to approach the fact that my-sum needs to access its children (which number could vary) and render them putting a + in between them.
Do you have any suggestion on how to approach this?
There are multiple things you need to consider. In your my-sum component, you might want to deal with reactivity i.e., when number of children elements change, here <my-unit>, you might want to recalculate your addition. If that is the case, you need to use mutation observer.
Otherwise, if you just want to calculate it once, you can use connectedCallback event lifecycle method with setTimeout to query your custom element like:
setTimeout(() => this.querySelectorAll('my-unit'), 100);
Next, you must also consider your use of shadow DOM. If you are using it, you need a different mechanism to query the children element. It would be something like:
setTimeout(() => this.shadowRoot.querySelectorAll('my-unit'), 100);
If you are using shadow DOM, it means you must also use slot element to accept the light DOM and render it within that slot. With slot, you can use slotchange event to detect node changes and re-calculate the sum of my-unit components.
In summary, you have multiple options to acheive your goal:
Without shadow DOM + No Reactivity: Use simple this.querySelectorAll('my-unit') preferably with connectedCallback lifecycle method
Without shadow DOM + Reactivity: Use querySelectorAll combined with mutation observer. observer event can be setup within the constructor or connnectedCallback.
With shadow DOM + No Reactivity: Acquire shadow DOM or slot element and query the children elements
With shadow DOM + Reactivity: Acquire shadow DOM and then slot element - use slotchange event to re-calculate the sum
With shadow DOM + Reactivity: Setup Mutation observer on light DOM and then query as mentioned above.
Related
In the Angular 11 project I need to change ng-circle-progress library CircleProgressComponent element size dynamically.
I have found out, that size of the element can be changed by putting width/height CSS properties on the child DOM element - svg. Problem is that svg doesn't have any id or class values, so even if I could somehow query the element, this would be not that easy and flexible as it should be.
Would be extremely nice to have a parameter in the CircleProgressComponent, that listens to outer variable changes and re-renders the element with a new size.
I had never used this library, so I've read their doc and thier demo page.
If I understand, they have the parameter that you want called radius
<circle-progress
[percent]="85"
[radius]="200" // the size you want
[outerStrokeWidth]="16"
[innerStrokeWidth]="8"
[outerStrokeColor]="'#78C000'"
[innerStrokeColor]="'#C7E596'"
[animation]="true"
[animationDuration]="300"
></circle-progress>
I am implementing a recursive component that displays tabs and uses visibility to show only the active content. I choose this approach because the tab contents are expensive to generate and to layout from a DOM perspective.
based on this, i see that when i hide a tab, the nested child tabs are still visible.
I am thinking that the best way to handle this is by creating a set of css classes:
p-visible
p-visible-hidden
This way, I can recurse through the DOM elements when a tab is set to hidden and change any elements having a p-visible class to having the p-visible-hidden class instead. Similarly, when a tab is set to visible, i can switch all of the elements that have the p-visible-hidden class to p-visible.
So I'm wondering the best way to implement this in Angular2 - To me, the best way maybe to actually select the child DOM elements.
Thanks in advance for any help :)
test harness for component
tab layout component
I was able to solve the problem by creating an #Input boolean (called parentVisible) that indicates if the parent is visible or hidden. This property is cascaded down through the recursive hierarchy of components.
The parentVisible boolean is an additional filter on setting each child element's visibility (if parentVisible is false, the visibility is set to hidden, if parentVisible is true, then set the visiblity as before)
This strategy makes it possible to avoid direct DOM manipulation which is deemed good for unit testing and doing things in the Angular2 way :smile:
TL;DR
What causes Recalculate Style in Chrome and what could be done to reduce the time for this step?
Background
In an application with many elements (variable, e.g. 10,000) I observe Recalculate Style taking a long time when adding a class on the parent element of those elements. There are selectors that will affect elements of each subtree when the container has this class.
In the developer tools I was able to trace the cause of the Recalculate Style event by clicking here (screenshot of a MCVE):
From to the name I assume that this step involves calculating the effective (final) element style. I think this happens when
a changed element style,
a changed (pseudo-) class
of the element itself or
of a parent or sibling element that is related by a selector or
a changed CSS selector (importing new CSS, generating <style>)
forces the browser to recalculate the CSS attributes of an element.
Attempt to prove my thesis
I created a MCVE with the same amount of elements as static HTML and toggling a class .change on a .container using a click handler on the document - dead simple code.
The MCVE performs much better than the actual application, the step Recalculate Style takes less time. This is probably due to the simpler tree and less styles.
Then I started adding more styles to all selectors and the average time increased with every bunch of new CSS attributes. Adding more elements to the 10,000 subtrees did not change the average time.
So, I'd say that the amount of CSS attributes, the count of selectors affected and the count of elements affected influences this time.
Recalculate Style
Get all the style rules
Evaluate the selectors and match against the DOM
Calculate the computed style for every element
Basically anytime you change a classname or other operations like that.
References
https://youtu.be/0xx_dkv9DEY?t=204
https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations
Suppose I have a ui with a button. The ui has four states, each with the button in a different corner.
In Flex, this is easy to achieve, you simply define these four states (topLeft, topRight, bottomRight, bottomLeft), and each has an override for the button's position values.
How would you do this using CSS in a way that can be triggered by a simple assignment?
Flex: skin.currentState="topRight"
JS: ???
I've defined the classes in css:
#button.topRight {...}
#button.topLeft{...}
#button.bottomRight {...}
#button.bottomLeft {...}
Now, without having to know of the existence of #button, how in one line of code can I apply one of the four states to all the elements on the page that have that state defined?
jQuery provides a handy abstraction layer in JavaScript to so this:
$('.someClassName').addClass('blueOnLeft')
$('.someClassName').removeClass('blueOnLeft')
This will target every element with a class name of "someClassName".
When a Flex component moves directly, so that its x and y properties change, then a "move" event is dispatched on the component. That's all fine.
However, a component may also move as a result of its parent component moving — or its parent moving, and so on. Now when a parent component moves, its children just "move along" without any properties changing or move events being dispatched on the children. Still, the children are moving on the screen. So how can you detect this kind of generalized movement?
One workaround is to capture all move events in the application:
Application.application.addEventListener
(MoveEvent.MOVE, handleMove, true, 0, true);
The third argument is required because move events do not bubble, and so instead have to be captured. The fourth argument is unimportant, and the fifth argument turns on weak references, which is a good idea in this case because we are creating a global reference from Application.application to handleMove — a recipe for memory leaks.
Of course, this will fire too often (once each time anything whatsoever in the application moves), and in a large application could lead to performance problems. If you know that there is some component higher up in the hierarchy that’s sure to stay still, you can put the listener at that point instead of globally, which could reduce the problem.
Still, it would be nice to have a cleaner way to solve this.
Well, you've already suggested the most general solution, but I think it's possible for the child to go through parents/grandparents until it reaches one that is stationary (set by some dynamic property you set), at least this would save you some trouble in figuring out which parent handles which child.
private function addHandlerToStationaryParent(handler:function):void
{
var currentParent:DisplayObjectContainer = parent;
while(currentParent != null)
{
if(currentParent["stationary"] == true)
{
currentParent.addEventListener(MoveEvent.MOVE, handler);
return;
}
}
}
I guess it would be your preference as to whether or not this would be a better solution.