Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: API to be able to get references of children components created in a for-each loop #4869

Closed
Fygo opened this issue May 20, 2020 · 12 comments
Labels
awaiting submitter needs a reproduction, or clarification stale-bot

Comments

@Fygo
Copy link

Fygo commented May 20, 2020

Is your feature request related to a problem? Please describe.
I would like to call an exported function (method) of a child component through its parent. This method changes the DOM of the child, so it is for obvious reasons implemented in the child component. This works nicely when a reference can be obtained through <Child bind:this={cmp}/>. However, there is currently no easy way (or is there?) to obtain references to children created in a for-each loop.

Describe the solution you'd like
bind:this={arrayRef} or some similar data structure to be populated/spliced/whatever in a for-each loop. This array should always be up-to-date and contain the currently existing children.

Describe alternatives you've considered

  1. https://svelte.dev/repl/7c34201c5d844bf6a87c43a6b39b21ae?version=3.22.3
    This would kind of work. But the animations ruin it. As soon as you have an animation on your child component, this is not removed and the elements array is not up-to-date. If you delete multiple items while the previous animations are still running, the array will get more and more "out of sync".
  2. https://svelte.dev/repl/4195f5f0ecd3430d810464ec85298a99?version=3.22.3
    Similar example. Different approach with an object. Elements array still not up-to-date. The source of truth should be the list.
  3. I considered passing the references onMount and onDestroy from child to parent. But I can't, because I can't get the this reference of the child. Actually, any way to expose some API for that?

How important is this feature to you?
I hit this issue 3 times in my current project. The first 2 times I just made it work in another way but now I really wanted to look into it and solve it. (I failed, obviously)

Special thanks to the guys in the Discord channel, especially to GrygrFlzr, whose example you can see above.

@kuhlaid
Copy link

kuhlaid commented May 28, 2020

One approach may be to use the Svelte store https://svelte.dev/repl/253ddd578806497b8b54c339490f8221?version=3.23.0

@Fygo
Copy link
Author

Fygo commented May 28, 2020

@kuhlaid I appreciate you taking time to look at this but could you please be a bit more clear? Where exactly are you saving the references to the child components in an each-block?

@kuhlaid
Copy link

kuhlaid commented May 28, 2020

@Fygo Sorry my first example was not the best for your use-case. How about https://svelte.dev/repl/28996f04783542ceafed7cc6a85128b9?version=3.23.0? I prefer to handle things this way because it does not involve complex binding and exporting properties, etc. It lets you dynamically add attributes to the 'store' for use in your components.

@Fygo Fygo changed the title API to be able to get references of children components created in a for-each loop Feature request: API to be able to get references of children components created in a for-each loop May 29, 2020
@Fygo
Copy link
Author

Fygo commented May 29, 2020

@kuhlaid Thanks for the simplified example but that is not what I mean. Let me try to explain a bit more:

Let's assume this setup:

        Container
          /    \
      List      List
     / /  \         \
Item Item Item      Item

Lists are created in the Container's each block. Items are created in each List's each block.
I want to issue a command from the Container to highlight an Item (basically means attaching a class to the Item's main element and then, after a few seconds, removing that class).
I can find which List contains the highlighted Item without any problems from the store, of course.

So in Container I want to call: myLists[X].highlightItem();
List should just take it, find the Item and call: myItems[Y].highlight();

That should be it, all the rest should be handled within the Item, there is practically no reason why anything else should be involved.

Right now I cannot save the references, so I cannot use myLists[X] or myItems[Y]. Thus, I have to do it either with changing a property in the store or using props. Both of these methods create overhead because the properties set must be actually reset at some point or the store needs to be updated. That would be the case in your example as well.

@Conduitry Conduitry added the awaiting submitter needs a reproduction, or clarification label Jun 8, 2020
@intelcentre
Copy link

No idea if this is useful, but I was finding the bind:this functionality a little limited as well.
Ideally I would like an event based model for creation/destruction of components and then I could decide on what I want to do with the component reference.

bind:this would make more sense to me if the value was dynamic, but presumably its set to a component instance at creation and set to null at destruction with no reactivity in between?
Something like
<MyComponent on:create={(instance) => handleCreate(instance)} on:destroy={() => handleDestroy()} /> (but obviously this exact syntax is already taken)

As a work around, I came up with this:
https://svelte.dev/repl/b60274af24284ac2a3079ba77aeec58b?version=3.23.2

There are two parts doing the real work, and the rest is just a contrived user interface to demonstrate/test the technique.

  1. LifeCycle provides a why to be notified before and after your child component is created, thus providing an opportunity to get ready for bind:this.
  2. handleCreate creates a get/set property to provide a trigger for when bind:this provides a value.

I believe this solution could work for you, though it's a non trivial bit of boiler plate and it really is something of a trick.

(I also tried getting more fancy, but ran into limitations of the let: directive https://svelte.dev/repl/3f8a62a1a82a468eae09b2506ec806aa?version=3.23.2)

@PatrickG
Copy link
Member

I think this is a good example to use a context.

What do you think about this?
https://svelte.dev/repl/929f49fa03844812a57bfd28adba83da?version=3.22.3

@Fygo
Copy link
Author

Fygo commented Jun 20, 2020

@intelcentre Not bad, your solution actually seems to work! I will play around with it a bit if I have some spare time next week. But jeez, saving references in an each block should be much more straightforward. I would really appreciate some simpler way to do this similar to bind:this. Pretty please, svelte devs?

@PatrickG You still don't have a reference to the item, you can't call an instance method on it.

@PatrickG
Copy link
Member

PatrickG commented Jun 20, 2020

You could use get_current_component - but I don't know if it is very "safe" to do so, because it is a internal function.
https://svelte.dev/repl/468f0b8fb9b14d60b31c80d144e5b93e?version=3.22.3

Or just send a reference to the functions you want to call.
https://svelte.dev/repl/7c01e54e077c44f2afa5d4d60ace4dc6?version=3.22.3

@Fygo
Copy link
Author

Fygo commented Nov 27, 2020

Has there been any new development in this area? Any new idea?

@kindoflew
Copy link
Contributor

I solved a similar problem recently by using stores and context to populate a store in the parent with child methods to call from the parent:

https://svelte.dev/repl/cd2324bc4f134396896594f6621faadb?version=3.37.0

So, instead of a reference to the whole child, you just expose the things you need from it in onMount.

@stale
Copy link

stale bot commented Jul 7, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale-bot label Jul 7, 2021
@stale
Copy link

stale bot commented Jul 21, 2021

This issue has been closed as it was previously marked as stale and saw no subsequent activity.

@stale stale bot closed this as completed Jul 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting submitter needs a reproduction, or clarification stale-bot
Projects
None yet
Development

No branches or pull requests

6 participants