I have a nested component, what is the Polymer way to travel up the DOM or component tree in this case.
<parent-component>
<some-component>
<component-i-am-starting-from></<component-i-am-starting-from>
</some-component>
<some-other-component>
</some-other-component>
</parent-component>
I'd like to be at a deep nested component and reference any of the parent components and their models or trigger an event inside one of them. Bonus if I can access sibling components, etc.
Traveling down was easy enough with
this.$.idOfChildComponent.event()
I have tried dispatchEvent, domHost, shadowRoot, can't seem to get any further up the component tree then the direct parent or get an error back that something is undefined, is not a function, etc.
Is there a way like React to pass a reference down as a property. The docs do not seem to be helpful nor scouring the internet.
Thanks!
update
So I am not sure if this is the correct way but it works ok calling a parent function from a child function.
<parent-component id="parentComponent">
<some-component>
<component-i-am-starting-from></<component-i-am-starting-from>
</some-component>
<some-other-component>
</some-other-component>
</parent-component>
componentIAmStartingFromFunc(){
document.getElementById('parentElement').parentElementFunc()
}
However does not seem to work for siblings?
** Update **
I essentially did the same the to call the sibling event by calling the parent from one of its children, and then sent out a trigger to the sibling which is also a child component.
Calling a parent function from child ;
child-component.html (polymer 2.x)
this.dispatchEvent(new CustomEvent('upway-func', {detail: {op:"Optionally I can send some data"}}));
child-component.html (polymer 1.x)
this.fire('upway-func', {detail: {op:"Optionally I can send some data"}});
parent-component.html
...
<child-component on-upway-func='_someFunction'></child-component>
...
_someFunction(d){
console.log(d.detail.op); // "Optionally I can send some data"
}
Here this link for more detail
Have you tried using this.parentElement?
Ask yourself: if I were a span in a div, how would I get to the div?
If you want to find a particular element in the ancestor chain by selector, you can use .closest() in good browsers or https://github.com/jonathantneal/closest
The message system mentioned in another answer can work but doesn't help you with positional relationship traversing which I assume your question was requiring. Passing ids and/or objects down can be used with messages in some cases.
Related
New to Stack Overflow and Lit.
I'm building something using Lit and wanted to know how do I render element/s only if a parent element is present. I am trying to add a login element dependency which will let user to use these elements only if the login element is present.
Example of what should be allowed.
<login-element>
<child-element-button> </child-element-button>
</login-element>
Example of what should not be allowed.
<child-element-button> </child-element-button>
Another problem that I have is a way for the child elements to share data, it can be to and from sibling elements, children elements, grandchildren element and so on. I do not have a solution for data sharing currently and would like to know the possible ways to achieve this.
Is there a way to achieve all of this without making <login-element> the parent element? something like this?
<login-element> </login-element>
<div> ... </div>
<my-custom-button> </my-custom-button>
<p> ... </p>
<my-colors> </my-colors>
<my-custom-footer> </my-custom-footer>
In short, I need users to be able to use custom elements only if <login-element> if present anywhere in the document and the custom elements that are present should be able to communicate between each other. For instance, a <my-colors> element should be able to send active color data to <display-image> element which will render an image with a specific background color received from `.
Currently, I read the child elements of <login-element>, copy the nodes, run loop, delete original nodes and append with those copied nodes. Additionally, in every child elements, I check if <login-element> is present in DOM or not, if present, render, else render a error element. As for passing and receiving data to and from other components, I have not tried anything.
Than you for your time.
I have a callback function which receives an argument from child component(here CardTiles) and it is processed and passed as props to another child component. The output is displayed correctly but I have to move my page to that particular section(the second child component-OutputWindow). How can i trigger an anchor tag from my 1st child component? or would refs work here?
Child component 1:
<CardTiles parentCallback={handleCallback}/>
Child component 2:
<OutputWindow name={place}/>
or would refs work here
Yes. Have a ref in the parent, put it on the child (ref={theRef}), have the child forward that ref to the outermost (probably) HTML element it renders, and then in the callback function have the code use theRef.current?.scrollIntoView()¹ to scroll that element into view.
More
Refs
Forwarding refs
scrollIntoView
¹ That's using optional chaining, which is fairly new. If your project isn't set up for it, you can use if (theRef.current) { theRef.current.scrollIntoView(); } instead.
I have a container who have inside many elements like h1, p etc.
This container have a background, and I want create method to move him by mouse coordinates. I have a problem with access to this element, because e.target show me elements inside container, not container who is binded element.
Alive any solution to share all functions between main component and child components? Because when i want get this method in anyone place now i must add :moveHero="moveHero" to every component and get this in prop array, so i want create this more globally in one place and share this to all childs. Now i think one solution for this is create .js file and import that to Vue.
You can add $ref to the container element like this: <div ref="container-ref">.
Then to access the container element in vue methods, just do this.$refs["container-ref"].
Explanation:
You can add ref attribute to any tag, even child components. It is parsed by vue only, browser ignores it.
If the ref is attached to a HTML tag, this.$refs[key] will return the corresponding DOM element.
If the ref is attached to a child component, this.$refs[key] will return the corresponding vue instance.
I have a parent component which has multiple child components
<grid>
<cell></cell>
<cell></cell>
<cell></cell>
</grid>
My cell components emit an event with payload saying it is being edited
this.$emit('editing',cellId)
I know I can capture the event like
<cell #editing="do something"></cell> or capture using EventBus.$on('editing'), I do not want to use root listener as well this.$root.$on('editing')
But because its the parent component, how can i listen to event of 'editing' when the parent component is mounted
mounted: function(){
this.$on('editing',dosomething)
}
why am I not able to add listen when the parent component is mounted?
The main difference that you are missing is described in the Custom Events section:
In addition, a parent component can listen to the events emitted from a child component using v-on directly in the template where the child component is used.
You cannot use $on to listen to events emitted by children. You must use v-on directly in the template, as in the example below.
What this means is that child-parent communication is done through a directive, using the v-on (or #edit) way.
Your example here
mounted: function(){
this.$on('editing',dosomething)
}
Won't actually work. In the emit documentation it's said that:
Trigger an event on the current instance.
Which means that inside the same component, you can actually use this.$on and it will work. But if you want to use it in parent, then you should use the inline directive to have it bind, otherwise it won't work.
Also keep in mind that emits works only for a single step, meaning that the the parent can catch it. If you need to emit subchild -> child -> parent, then you should catch the event (using inline binding) from subchild in child, and re-emit it again so it goes to parent.
If it is outside of children-parent scope, then you should use what is called a global bus. Basically it narrows down everything to a single instance, which emits and listens for all events. So then they are no longer child-parent or whatever kind of connection, they are all on the very same instance, and therefore you can always use them in every component of yours.
Bottom line is - your approach to listen on mounted won't work. Hope that helps :)
The difference between listening to each child and listening to the EventBus is this:
when you emit an event like this.$emit('event') the event will be fired only for the parent component.
when you do a EventBus like EventBus.$emit('event') then your event will be sent to all the components
There are pros and cons for each one; EventBus can send events to components which will never use that event (can become an event polution), and the parent event emitter can be not that elegant to use as EventBus.
So you decide which approach is good for you.
TL;DR
Stumbled across this issue my self. Like the other said, when you want to bind an event listener from a parent, you need to use v-on because, well ... , you are binding something tot he child. So the actual callback is ran by the child, when that child detects that the event ocured.
In the child use this.$parent.$emit('event-name');
In the parent use
mounted: function() {
this.$on('event-name', function() {console.log('test')});
}
The above will let you trigger the event in the parent so you can use $on in the parent to lsiten to that event that was triggered by the child.
I’ve hit an interesting issue that doesn’t fit with Ember’s data down, actions up principle.
I have a code editor component (code-editor) sat inside a parent component (request-editor). There's a method on the editor component to insert a string at the current cursor position. The parent component includes some buttons to insert things into the editor (e.g. the current date).
I think I'm right in separating the buttons from the editor because the editor is used elsewhere without these buttons.
It obviously doesn't make sense to use a bound variable for this use-case because it's not really data, it's wanting to perform an action. I.e. {{code-editor insertText=insertText}} makes no sense.
How is it possible to effectively call codeEditorChildComponent.insert() from the parent component? I appreciate it will probably involve coupling them together but they have to be coupled for it to work anyway. The parent component is composed of the child components already.
All communications should be done using actions.
I think below is a good way. And you have code_editor property in request-editor component then could send action to code-editor component.
request-editor.hbs
{{code-editor owner=this}}
request-editor.js
actions:{
setChild(child){
this.set('code_editor', child);
}
}
code-editor.js
didInsertElement(){
this._super(...arguments);
this.get('owner').send('setChild', this);
}