React: attaching event handlers and/or styles to injected content (svg) - javascript

What I am trying to do, within a react component, is take a piece of svg, stick it inside a div to render, and then attach mouse event handlers to it's elements. And then I want to dynamically change for example the fill of an element when hovered over or clicked on.
I have browsed a lot of react libraries related to svg, that all do not really seem to do what I need, such as react-svg, react-samy-svg, svg-injector, stuff like that.
Besides they all seem to rely on calling an outside url (i have the content i want to render stored in redux), (and this does not seem to work on my dev server), i am not sure how to attach react-style classNames or onClicks to injected html, or how to store that in the component state.
So now i am falling back on: dangerouslySetInnerHTML to inject the svg content, and dropping a piece of jQuery on it that takes care of the dom manipulations and mouse events, but it's not pretty. Does anyone have another, more react-style, solution? If needed, I can elaborate with pieces of code or whatever. Thanks.

Related

When is it safe (if at all) to manually relocate a Vue-rendered DOM node?

I understand that you should not manually manipulate the DOM nodes rendered by a Vue component for reasons including:
After another render, Vue can override any changes you did
It can interfere with Vue's patching algorithm
My use case is I would like to implement a way to move a DOM node to a separately-controlled location for the purpose of displaying it fullscreen. Imagine an editor widget with a fullscreen button that "pops out" the editor and overlays it fullscreen.
I understand that I can achieve this with CSS alone using fixed positioning, but I'm not interested in that, I'm particularly interested in the consequences of moving the DOM node out from wherever it is and appending it directly to the <body> element. Will Vue still be able to patch the nodes correctly after the parent component re-renders?
I have experimented with this already and I have a working implementation, and I haven't encountered any issues yet. Still, this doesn't ease my concern, and the Vue docs don't talk about doing something like this.
What potential issues, if any, might I encounter?
portal-vue is unsuitable because it recreates the component instance each time it is relocated, which I do not want.
Depending on how the component lifecycle works in Vue, moving a component in the DOM might trigger lifecycle methods. E.g. with Custom Elements, moving means triggering disconnectedCallback of the component, and subsequently connectedCallback. This is often where the component initialization takes place.
Rather than moving the component manually from the outside, consider giving the component itself the ability to relocate.

Alter style in JavaScript without affecting what gets rendered in the browser

I extract several blocks that are spread across the page, draw them onto a canvas, via Canvas​Rendering​Context2D.draw​Image(), and then I export the canvas to PDF/JPG.
Now, while drawing them, I also want to tidy their looks and/or remove/display parts of some blocks, because the styling no longer makes sense from a static point of view.
I can append a class on body, style blocks differently while body has that class, build the canvas, export it to a content type of choice and remove body class, but this makes the page look quirky for 1 - 2 seconds. (I could just cover the page with a loader, I guess)
I can clone the block, style it differently or apply whatever styling (inline or via classes) and draw an image from that, but this is not optimal.
Any idea on how to do this properly? I'm inclined to go for something like emulation. Have the whole "export styling" under the native #print and emulate that before drawing the blocks onto the canvas, without affecting what gets rendered in the browser, but I'm not sure if this is possible.
I know these don't answer your specific question, but perhaps these are viable alternatives to the problem.
It sounds like you're trying to make something printable. I assume this is triggered by a user interaction of some kind so...
This means you have a few interface options. For example, you could "hide" the screen by placing a modal over the entire thing with a message that says "processing just a moment". Then the body (or another element) class solution works.
You could copy the elements as you suggested. If you go that route I would move the copies off the screen while you change them.
.element {
position: fixed;
left: -100vw;
}
Without knowing how many duplicates you need to make it's hard to recommend this option.
Alternately, could you offload the effort to a service worker? This would require a copy into memory BUT its completely detached from the DOM and runs in a different thread.
It's a really interesting problem though!
I think you can use node.cloneNode(true) to make a deep clone for all these blocks, put them in a classname scoped common root that's hide away from user's view, then you mod their style secretly.
Since you mod the cloned version of nodes, the original remains untouched. Plus, using the classname scope, your css can target these clones accurately.

Detect "Node redraw completed" event after adding node to DOM

I have a single-page application (SPA) that dynamically shows different parts of DOM by adding and removing DOM subtrees (nodes with their children).
They act like a "pages", switched by the menus and app logic, and may contain a lot of child elements, like controls, text, tables etc.
The problem is, that when the new node added, it takes a long for browser to draw it, and that leads to the flickering. I tried to add a node with the opacity=0 and to change the opacity to 1 then, but how could I understand the timeout required?
Is it possible to detect when redraw is completed, and to make new node visible only after that?
I tried to use MutationObserver but it just calls my callback immediately after node was added, not when it is actually drawn. Now I use "setTimeout" but it is not possible to find out the timeout value to use.
I don't want to make app too laggy, and at the other hand, short timeouts for complex nodes with a lot of children ain't preventing this redraw flickering.
Please help.

Render all possible elements or render on request

So I have an app that has a right sidebar whose visibility is toggled via a button. In that sidebar there can be one of several things [at a time] - chat, help, search. I was looking at some plain HTML from apps which have a similar feature and noticed that they have all nodes rendered, but are just hidden via CSS.
Since I need to do the same thing, I was thinking whether this would be a good idea to do with React. But then I realized that React elements have a state which when updated calls the render method. So I can use the state to store both whether the sidebar is opened, and what is inside the sidebar.
Is that the React way of doing things? Is it better to have all nodes rendered even if they are not visible, or is it better to have the nodes rendered on request via state changes?
My feeling is that only rendering what is visible would be the more standard React way, but in this case, this is mainly a performance decision. If you render everything and just toggle visibility with CSS, the first render will take longer (but the time difference may not be relevant or even noticeable). If you render only the part that's visible, React needs to do a small rerender every time the sidebar content changes. (This may also not be noticeable time.)
My recommendation would be to try both, if you want to test the performance. But I think you won't go too wrong either way.

Avoiding re-rendering of a flash object from scratch when view is reactivated

I have a question about div caching in ember js for views.
I am rendering a really heavy flash application as a part of a view and i want to switch between views but not necessarily have to reload the flash app from scratch. I would preferably want it to be "hidden".
Is there a way of doing this in ember
Currently i am implementing this using https://github.com/ghempton/ember-routemanager and one of the flash apps stay on /#media and the other on /#publishing
So when user goes to /#media the media.swf gets loaded and /#publishing the publishing.swf gets loaded into the container div. Each of these routes have a corresponding view class associated to them that renders the flash object tag to be rendered.
In the past, I have used jquery to hide the container div but i am searching for a cleaner solution.
It sounds like the feature you'd like is to be able to reuse a view instance and it's DOM across states. I have some ideas for how that could be done, unfortunately it's not possible right now without some nasty hacks.
Also, unfortunately with flash objects, they seem to get rerendered if you move them in the DOM or if you change their visibility. From what I can tell, to "hide" a flash object without causing a rerender, you can only move it off screen using CSS.
Update:
Here's a working jsFiddle example: http://jsfiddle.net/EE3B8/1
Unfortunately, that technique won't work for Flash objects, since moving them in the DOM will cause them to be reloaded. This would be a good way of eliminating expensive DOM creation/view instantiation.

Categories

Resources