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

How to pass down a function? #43

Closed
andruschka opened this issue Feb 27, 2019 · 1 comment
Closed

How to pass down a function? #43

andruschka opened this issue Feb 27, 2019 · 1 comment
Labels
help render Applies to render and content properties defined as functions

Comments

@andruschka
Copy link

Hello! First of all, I love this project. Really good work. I hope it will get the traction it deserves.

But there is one thing I cannot wrap my head around. Meaybe it would be helpful to have a kind of getting started tutorial for developing a small app. Ok here is my problem:
Say we have a parent component <todo-list> which has a property with the list of todos - lets say it is an array with strings. This <todo-list> renders for every todo in the array a child component <todo-item>. Each item has a button, which - if clicked- would remove this item from the array in <todo-list>. In React or Vue, I would just pass down a function to the child components - how would I solve this in hybrids? Maybe I am just thinking too much in the react box.. Thanks in advance!

@smalluban smalluban added help render Applies to render and content properties defined as functions children 👶 labels Feb 27, 2019
@smalluban
Copy link
Contributor

smalluban commented Feb 28, 2019

It is possible to pass down function to the custom element created by the hybrids. However, I would recommend to stick to the platform and use DOM events instead.

First of all, there are two ways to structure related components - you can render children inside of the parent component - in render property, like this:

const TodoList = {
  render: () => html`
    <todo-item></todo-item>
    <todo-item></todo-item>
  `,
};

Then in your other part of the app you are using <todo-list> where <todo-item> is used behind the scene.

The second way allows composing parent and children using the distribution:

const AppWrapper = {
  render: () => html`
    <todo-list>
      <todo-item></todo-item>
      <todo-item></todo-item>
    </todo-list>
  `,
}

The question is here, where do you want to have logic, which is resposible for processing input items for the list. In the first way, the <todo-item> is just for convience - it could be a <div> with styling, so then you don't have communication between different custom elements. In the second example <todo-list> is rather a UI wrapper with some styling etc, for <todo-item>s.

How you can then use DOM events? If your <todo-item> has delete button - you can attach event listener to click action, and dispatch another custom event for it:

import { dispatch, html } from 'hybrids';

function delete(host) {
  dispatch(host, 'todo-item-delete', { detail: host.data.id });
}

const TodoItem = {
   data: null,
   render: ({ data }) => html`
      <div>${data.msg}</div>
      <button onclick=${delete}>delete item</button>
   `,
};

In above example <todo-item> element dispatches todo-item-delete event when a user clicks delete item button.

You can then listen to that event in your parent component and remove item from your list:

function deleteItem(host, event) {
  const itemId = event.detail;
  host.items = ...
}

const AppWrapper = {
  render: () => html`
    <todo-list>
      <todo-item ontodo-item-delete=${deleteItem}></todo-item>
      <todo-item></todo-item>
    </todo-list>
  `,
}

If you are using the first method you can still use events and add one to your <todo-item> element.

At last, if you really want to pass function you can define your property as a undefined (omit transforming value of the property) and use it on some event:

const TodoItem = {
   deleteCallback: undefined,
   render: ({ data, deleteCallback }) => html`
      <div>${data.msg}</div>
      <button onclick=${deleteCallback}>delete item</button>
   `,
};

And then:

function deleteItem() {...}

const AppWrapper = {
  render: () => html`
    <todo-list>
      <todo-item deleteCallback=${deleteItem}></todo-item>
      <todo-item></todo-item>
    </todo-list>
  `,
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help render Applies to render and content properties defined as functions
Development

No branches or pull requests

2 participants