I'm trying to add web animation to my app.
I want to avoid using neon-animation as it is now deprecated.
I read this instructions : https://medium.com/collaborne-engineering/polymer-2-0-replace-neon-animation-with-web-animations-api-e82d7bd82e6 but I can't figure out how to use it in my case :
I have a page with two custom elements that are displayed if the route matches :
<app-route route="{{route}}" pattern="/list" active="{{listActive}}"></app-route>
<app-route route="{{route}}" pattern="/product/:id" active="{{productsActive}}" data="{{productsData}}"></app-route>
<catalog-product-page hidden$={{!productsActive}}></catalog-product-page>
<catalog-list-page id="productPage" hidden$={{!listActive}} item-route="{{route.prefix}}/product"></catalog-list-page>
The catalog-list-page contains a dom-repeat that loads a list of items pointing to a catalog-product-page.
How can I make catalog-product-page to get animated when an item is selected ?
Even though neon-animation is already deprecated but it's still a good example of using Web Animations. I recommend you to look its source code especially neon-animated-pages and neon-animatable.
How can I make catalog-product-page to get animated when an item is selected?
It has a lot of ways to do.
One of the simplest things I come up is this. In that plunker it has 2 components are my-app and my-page. Switch to first version (versions on the sidebar) is just a simple toggle display block to none and so on. Then switch to second version you will see simple transition and the added code is
if (selected === this.selected) return
this.animate({
opacity: [0, 1],
transform: ['translateY(16px)', 'translateY(0)']
}, {
duration: 250,
easing: 'ease-in-out'
})
This mean for entry page (switch to selected) it will play animation as the code shown. For exit page (switch to not selected) it will do nothing because its display is none. For other pages just return.
More examples of using Web Animations see here and W3C specification see here. I hope this help.
Note: In my experience of using Web Animations. It works very well in supported browsers but others it's not that good (you can find some issue on their repo).
Lots of new functions released with React 16. One of them is the ReactDOM.createPortal(child, container) API, which is handy for visually breaking out of its container.
However, it seems like that it not only breaks out its container but also breaks the basic html rules which I learned from the first day of web development. The createPortal API let you render your component out of its parent, and break the html structure convention we expected.
In the other hand, we do retrieve more flexibility and now can render DOM in the sibling or else components.
IMO, I don't think this is a good deal to gain more flexibility by trading html convention in. Also the example supplied by official does not convince me.
What I am curious about is:
Is there anyone who face any condition that createPortal API is a must?
thanks
The examples in the docs are some of the cases where createPortal is really useful - specifically dialogs, hovercards, and tooltips.
The docs also specifically state:
Note:
It is important to remember, when working with portals, you’ll need to make sure to follow the proper accessibility guidelines.
As an example, the docs show how a modal could be built using createPortal(). You'll notice the modal is created in the #modal-root element, which is a root element alongside the #app-root element. This is a great example of how createPortal() can be used without violating any HTML rules.
<div id="app-root"></div>
<div id="modal-root"></div>
I ran into another use case a few months ago. Because React 16 portals were not available, I had to use a home-baked portal implementation.
I was creating SVG graphs. All of the lines, paths, and so forth needed to be rendered inside an <svg> element. But I wanted to use HTML to render text labels (for a number of reasons). This meant that an object on the graph and its label would necessarily be in separate parts of the DOM. But with portals, I could still keep all of a graph component's logic together. Here's a fictitious example:
const LabeledPoint = ({ x, y, r, labelText }) => [
<circle cx={x} cy={y} r={r} />,
<GraphLabel x={x + 5} y={y}>{labelText}</GraphLabel>,
];
You would use this component inside an <svg> element. The GraphLabel component would use a portal to render labelText in an HTML div element at the same coordinates as that <svg>, using absolute positioning to place it at the correct coordinates.
This way, all of the logic for a single component could be in one place even if I needed to render the actual DOM elements in different places for technical reasons.
Portals is very useful feature when you need to render your component outside the DOM hierarchy of the parent component.
You define a portal using the following syntax:
ReactDOM.createPortal(child, container)
The first argument (child) is any renderable React child, such as an
element, string, or fragment. The second argument (container) is a DOM
element.
See the following tutorial to see how and why to use portals:
https://www.youtube.com/watch?v=lOMU9BeIrO4
Before going into my answer, I'll just note that I interpret the question as "in which cases is there no alternative to using a portal, or a portal would be a demonstrably much better solution?"
There are very few cases where portals are the only solution. A lot of the time there's a way to structure your app so that you don't need to use them. There's some niche use cases, but even there it's usually not the only solution.
For example in the SVG use case, you could instead create a Labels component that takes an SVG React element as argument, and then loops recursively over the children to construct an HTML element with matching labels in the right position. That would as a bonus also make the SVG code a lot simpler. If the SVG is user editable, you'd have to store its state as a whole anyway on each change, allowing you to easily pass the state back into both SVG and label elements. That said, here the portal solution seems at least on par with the alternatives, and could be the simplest in some circumstances.
Dispatching plugin components
Portals can be useful for library/framework authors. It allows plugins to render multiple components in the same element, each of which the framework then portals to a different position in the UI (e.g. editor area, sidebar).
WordPress's block editor uses this for a few things, they call it SlotFill. For example if you're coding a new block in a plugin. You always provide an edit component for each block, which is rendered to the WYSIWYG editor. If it includes an InspectorControls component, everything inside it will go into the sidebar.
The Block Toolbar works in the same way. Content of the <BlockControls/> element is moved to the toolbar that is displayed right above the block content.
This is implemented as a portal to a registered slot.
The advantage of a portal here is that it allows a block's code to reuse the state and hooks in all components, even though they are not rendered in the same place. This makes the process of adding sidebar code very easy and with minimal repetition. If plugins instead needed to provide each of these components as a standalone React component, managing their state would be much more complex.
Example
You won't find ReactDOM.createPortal in the example itself. It's rather an example of how a plugin can benefit from a framework that uses it. See WordPress's source code if you're interested in the implementation details.
I added a simple useState hook to the mentioned InspectorControls example and removed some irrelevant parts.
edit: ( { attributes, setAttributes } ) => {
const [myColor, setMyColor] = useState('#fff');
return (
<div>
<InspectorControls key="setting">
// Simplified HTML, real world blocks use more complex HTML here.
<ColorPalette
value={myColor}
onChange={ setMyColor}
/>
</InspectorControls>
<TextControl
value={ attributes.message }
onChange={ ( val ) => setAttributes( { message: val } ) }
style={ {
backgroundColor: myColor,
color: attributes.text_color,
} }
/>
</div>
);
},
What is the correct way to implement internal linking in Polymer 2.0 (linking within the same page)? I cannot seem to get access to my components that are buried within ShadowDoms, so the traditional way of using link to top and <a name="my_section"></a> and <a id="my_section"></a> does not work.
I have also tried the solutions here to no avail:
How to query elements within shadow DOM from outside in Dart?
Is it possible to access Shadow DOM elements through the parent document?
Using querySelector to find nested elements inside a Polymer template returns null
The following code that I've tried all return null, even when I add an id to my component:
document.querySelector('#my_section'); //null
this.$.my_section; //null
this.root.querySelector('#my_section'); //null
this.shadowRoot.querySelector('#my_section'); //null
Perhaps there is a way to accomplish this using <app-route>?
I'm quite new to Polymer so any advice would be appreciated. Thanks in advance.
Please share more detailed code that which elements you want to access and manuplate. Here at this document
https://www.polymer-project.org/2.0/docs/devguide/dom-template
under the Static node map head shows shortly :
The this.$ hash is created when the shadow DOM is initialized. In the
ready callback, you must call super.ready() before accessing this.$.
Update: here are the docs for this situation: Conditional templates use the if attribute to conditionally create a template instance.
this app, plnkr.co, should do the following:
use core-ajax component to get project_location from DB(JSON in this example)
use google-map component to display the map with marker
when user drags the market, use core-ajax to save the new location to DB
Q: How to make google-map component to wait with it's rendering until AJAX request is finished?
Currently this error is appearing:
"Exception caught during observer callback: TypeError: latitude must be a number", and I assume that is because google-map is rendered before {{project_location}} is initiated.
<core-ajax id="ajax_get_location"
auto
url="project_location.json"
params='{"idProject":"{{idProject}}"}'
on-core-response="{{locationLoaded}}"
handleAs="json"
response = "{{project_location}}"></core-ajax>
<google-map id="project_location_map"
zoom="{{project_location.location_map_zoom}}"
fitToMarkers>
<google-map-marker
latitude ="{{project_location.location_map_marker_latitude | toFixed(2)}}"
longitude ="{{project_location.location_map_marker_longitude | toFixed(2)}}"
title ="{{project_title}}"
draggable ="true"
>
{{project_title}}
</google-map-marker></google-map>
I think the cleanest approach is not to think about this as a timing issue with <core-ajax>. Fundamentally, the problem is that you don't want to include the <google-map> element on your page until there's a value for project_location. In your snippet, the project_location value comes from <core-ajax>, but you could easily imagine a different implementation in which project_location is populated via some other means.
So, if you think about it that way, what would make sense is to wrap the <google-map> in a conditional template that checks for a value of project_location:
<template if="{{project_location}}">
<google-map>
...
</google-map>
<template>
You can change a value on the model when core-axax has finished and wrap the other elements with a <template if="{{ajaxHasFinished}}">...</templ<te>
Besides what others have said, an another way is demonstrated in the tutorial https://www.polymer-project.org/docs/start/tutorial/step-3.html, in which you create another element to do the ajax thing, and use it in your original element. The data transfer is achieved through attributes and data binding.
I think it's a better way because you separate the data display with data fetching, making it look better in software engineering.
P.S. I've tried what other answers said, but I found out it didn't matter whether you use if condition or not.
Currently I am using Form.Validator from Mootools 1.2.5 and Mootools-More 1.2.5, but i am having a hard time validating an Element's input when dynamically injected into the DOM after ondomready. I was wonder if there's a way to attach Form.Validator's functionalities to the newly inject Elements?
UPDATE:
Using what #Dimitar suggested i was able to fix the issue. I use the build in function getFields to repopulate/attach events to the dynamic Elements. formValidatorObj.watchFields(formValidatorObj.getFields()); Hope this will help some Mootooler's in the future!
i am not a big -more users but looking at the source code on github, this seems like a good guess:
https://github.com/mootools/mootools-more/blob/master/Source/Forms/Form.Validator.js#L161
i guess you can pass any element - dynamically created or otherwise.
formValidatorObj.watchFields([someElsCollection]); // or from form.getElements or whatever.
// dynamically add a new field...
formValidatorObj.watchFields([new Element("input.required[value=John]").inject(formValidatorObj.element, "top")]);