Using collapsible panels within react-virtualized List - reactjs

I've managed to render a react-virtulized List to which I passed an array of react-bootstrap Panels. I've measured each of my rows, and via children callback, each time one of the child panels are clicked, an attribute in the parent state is updated. Said attribute is used inside the react-virtualized List rowHeight() function top check whether that panel is currently expanded. Then, using a ref to my List, i call the recomputeRowHeights(index) and forceUpdateGrid() methods on saidref.
The thing is, while the List component correctly updates both the height and position of my rows, the animation isn't smooth. I mean, the bootstrap expand animation works fine, but the change in height of the expanded row happens instantly after the click event, and then the animation starts, feeling somewhat chopy.
Is there any workaround for this, or is this an upcoming/planned/in the works feature for react-virtualized?

Unfortunately, I have not spent much time working with or optimizing for resize animations within react-virtualized. It doesn't surprise me to hear that the resize/reposition is a bit choppy in the case you mention.
Here's a quick-and-dirty example of one way you may add animation: plnkr.co/edit/VanCAQmSkUejp3hbJUyJ?p=preview. Not meant to be bug free, just an illustration. :D

Related

React - to manipulate DOM or use state?

This Is more of a "theoretical" question that often buffles me in different situations and use cases, I will give a simple example to demonstrate it.
Let's say I have a list of 10 buttons.
Everrytime I click a button, a floating menu appears on top of the clicked button - there is only one menu visible for any given time.
Let's assume that I can't render this floating menu within the button component and I can only render it in the buttons parent level (meaning that this menu is sibling to those buttons).
I have 2 possible options to do that:
Keep the x,y position of the last clicked button and render the menu in this given position
Render the menu once and using "ref" to directly relocate the menu
On the one hand, the first approach seems more "Reactish". On the other hand, the possible implemention I can think of is pretty ugly (capturing the clicked item position and saving it to state which triggers defender), and further more, I am not so sure about re re rendering the whole container just because I need to move a small piece of it.
The second approach touches the DOM directly using refs. Although possible , doing DOM manipulations sometimes feel bad to me.
Is there a better approach? Which of the 2 makes more sense?
Any suggestion or thoughts will be appreciated!
Thanks
React uses whats called a virtual DOM, which is a representation of the DOM, that sits on top of the real browser DOM. Whenever you update state or a user performs an action the virtual DOM compares and checks the changes with the real DOM and then updates the UI accordingly.
So if certain DOM elements like a are not different between changes it does not get re rendered, only the DOM elements that have changed are re rendered. And if a property on a DOM element is changed, only the property is updated and the DOM element is not re rendered.
<div color="blue" />
to
<div color="red" />
The whole element is not destroyed and re created, only the property is changed.
However if the element in the host tree is different than the entire host tree is destroyed and recreated.
<div />
to
<p>
This is refereed to as reconciliation
https://reactjs.org/docs/reconciliation.html
So using refs is definitely more of a hacky solution since its more of an escape hatch and directly manipulates the DOM.
I would definitely stick with option 1, I think there is an elegant solution to the use case you described, it would involve just adding a click event listener in the componentDidMount and keeping track of the click position that way.
And also its hard to say without code but since your buttons will be the same, they will not be re rendered only the menu will.
Would recommend for further reading
https://overreacted.io/react-as-a-ui-runtime/

Scrolling down not working when dragging an element and simultaneously adding/removing components to the form

When I am dragging an element down, the form doesn't scroll down when the dragging reaches the bottom.
The reason for this may be that I am manipulating the content of the form by adding an empty placeholder component under the dragged component, and then removing and adding the placeholder each time the dragged component moves over another component. I call revalidate each time the placeholder is removed/added.
Strange thing is that the scrolling works fine when dragging upwards.
Any suggestions for what could be the cause and how I may fix it?
Thanks

How to apply an animation on an item that is getting removed without using a timeout

I'm using Angular 2 - RC3.
My problem is, I have an item which is shown or hidden using a *ngIf.
When the item is getting shown or hidden I want to apply an animation.
I'am able to apply an animation when the item first shows simply by adding a class. But the problem is when it's getting removed, the item gets removed from the screen before the animation can start/finish.
I know you can overcome this by setting a timer to delay removing action so that the animation can finish. But I don't want to put timers everywhere I need this functionality.
Is there an easier way in Angular to achieve this?
I don't want to use JQuery is either.
Use [hidden] directive on your element, as it does not prevent the element from rendering like *ngIf does.
[hidden] mean it takes up space in your DOM document but it's display is set to : none !important.
*ngIf on the other hand removes the element from the DOM completly

Accordion-like states on AngularJS with ui-router

I'm trying to accomplish something that seems easy at first glance, but ends up being quite the challenge. I have an accordion-like section of an app, where each accordion item should open a child state when activated, with a few extra requirements:
child states can (and should) be the same child state, with different parameters.
child states are not know up-front, they're loaded dynamically.
deeplinking to a child state should work as expected. The accordion item expanded and the proper content loaded.
The idea is easy, there should be one child state, which loads/shows different data depending on the passed parameter, but the template of that child state should be place in the activated accordion item, not in one fixed place.
I partially tried the multiple named views option from ui-router, but doesn't look promising, since it would actually load all those named views at the same time. Plus, I need them to by dynamic, and even though is possible to define states dynamically with for example with Future states, it doesn't seem to be the right choice here.
Right now, I can only see 2 options:
Re-parent the ui-view inside the desired accordion item (didn't work at first try but did if I re-parent the container of the ui-view) but has buggy side-effects right after the testing, and I fear some critical side effect later. Basically the parent controller get's reloaded for a second time, keeping the previous instance in memory. Plus i've seen some duplicated DOM content in places outside the scope of even the parent. I don't like this approach of course, but has the advantage of actually placing the content I need inside the container I need.
Leave the ui-view outside the accordion, position absolute-it, and manage it's position based on the current state when navigating. The position absolute is not a big deal, but I need to keep measuring the content's height, and dynamically set the height of the expanded accordion item to make it look like it's inside of it :S. To make things more difficult, I'll probably have to place some complex rules to position this correctly for the responsive design this needs.
In the end, it's a route/code hack vs a visual hack. I'm taking the visual hack since it sounds safer, but it's definitely going to be more work. Any other approach or comments will be highly appreciated.
-- Edit --
There's a better option at least for the 2 options I had in mind: create the different child states (1 child state, with params) but not associate it with a template. Just leave all the DOM in the parent state/view, and manage visibility with ng-if
Did you think about the option to use only one child state for all this and pass the additional information you need using parameters of the state?
so have URL-paramter for the accordion-section-id you want to open and other parameters for the different data to show.
Then open the correct accordion-section based on the stateParamter. Write a directive with private scope to render the content of the section and in each accordion reuse the same directive and pass it the correct data.
Then if the user clicks to open another accordion section, instead of the normal 'open'-action use a $state.go('myState, {accordion-id: 'newidtoopen', datatoShow: dataids}).

Dojo drop-down detaches when scrolling page containing FilteringSelect or ComboBox

Since the ComboBox and FilteringSelect use a 'dijitPopup' whose DOM element gets inserted just before the closing body tag (presumably to help with ensuring it appears above everything else z-index-wise) this means that if the ComboBox is contained in an element that scrolls independent of the window itself and the user opens the dropdown and then scrolls the window (or whatever containing element) using the scroll wheel, that the menu part doesn't move with the control itself.
Is there a straightforward way to ensure that the menu part of the view remains positioned correctly relative to the control itself rather than simply assuming that its starting position is ok?
EDIT: appears to be a known issue (http://bugs.dojotoolkit.org/ticket/5777). I understand why they put the dijit popup just before the closing body tag for z-index stacking and overflow clipping issues, but it seems like it's maybe not the ideal way to do things given the bug in question here and things like:
You can restrict the Dijit theme to only small portions of a page; you
do this by applying the CSS class of the theme to a block-level
element, such as a div. However, keep in mind that any popup-based
widget (or widgets that use popups, such as dijit.form.ComboButton,
dijit.form.DropDownButton, and dijit.form.Select) create and place the
DOM structure for the popup as a direct child of the body
element—which means that your theme will not be applied to the popup.
~ from http://dojotoolkit.org/documentation/tutorials/1.6/themes_buttons_textboxes/
Not sure if this is the very best solution, but here's what I came up with:
Since the widget may be programmatically added/removed, and to avoid coupling a solution with some particular surrounding markup that we can't always count on in all cases, what I did was to hook the _showResultList and _hideResultList methods of ComboBox and when the popup opens, traverse up the DOM till we reach the <html> tag, adding onscroll listeners on each ancestor.
The handler for the onscroll event is simply:
var myPos = dojo.position(this.domNode, true);
this._popupWidget.domNode.parentNode.style.top = '' + (myPos.y + myPos.h) + "px";
where this is the widget in question. I scope the handler to the widget using dojo.hitch. In the close method I remove the listeners. I have to clean up the code a bit before it's presentable, but when it's finalized I'll add it to this answer.
Note: I only show updating the y position here. Part of the cleanup is to add x position updating in case someone scrolls horizontally.
Though its old I just faced this same problem and it looks like a Dojo issue and the fix is available here https://bugs.dojotoolkit.org/changeset/30911/legacy

Resources