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

multiple app()s / component approach / return dom #2

Closed
tunnckoCore opened this issue Jan 31, 2017 · 10 comments
Closed

multiple app()s / component approach / return dom #2

tunnckoCore opened this issue Jan 31, 2017 · 10 comments
Labels
discussion enhancement New feature or request wontfix Forget it, sorry

Comments

@tunnckoCore
Copy link

tunnckoCore commented Jan 31, 2017

So, it is just amazing lib. A was working on some idea like that, code name mitak ;d Based on events with just router, pub/sub system. For now it is 450bytes gzip. But yea, anyway.

So the problem of return nothing just bumped while I tried to make a Todo List in components way.

So lets get started. We have 3 app()s - TodoItem, TodoList and main.

  • main - main entry, place for header & footer for example
  • TodoItem - component for each todo, e.g. <li></li>
  • TodoList - component holding all TodoItems, actions and view which is just like <ul>TodoItem()</ul>

main

const { app, html } = require('hyperapp')

const main = app({
  // root: document.body,
  model: {
    title: 'Todo List Example',
    link: 'https://github.com/hyperapp/hyperapp'
  },
  view: (state) => html`<main id="HyperApp">
    <h1>${state.title}</h1>
    ${TodoList()}
    <footer>Powered by <a data-no-routing href="${state.link}">HyperApp</a></footer>
  </main>`
})

TodoList

const TodoList = () => app({
  model: {
    todos: [],
    count: 0,
    input: '',
    placeholder: 'Add new todo'
  },
  update: {
    toggle: (state, data) => ({
      todos: state.todos.map((item) => {
        return data.id === item.id
          ? Object.assign({}, item, { done: !data.done })
          : item
      })
    }),
    remove: (state, data) => ({
      todos: state.todos.map((todo) => todo.id !== data.id)
    }),
    add: (state) => ({
      todos: state.todos.concat({
        id: state.count++,
        done: false,
        text: state.input
      })
    }),
    input: (state, data) => ({ input: data.value })
  },
  view: (state, action) => html`<section>
    <ul>${state.todos.map((item) => TodoItem(item, action))}</ul>
    <p>
      <input
        class="add"
        type="text"
        onkeyup=${e => e.keyCode === 13 ? action.add() : ''}
        oninput=${e => action.input({ value: e.target.value })}
        placeholder=${state.placeholder}
      />
      <button onclick=${action.add}>add</button>
    </p>
  </section>`
})

TodoItem

const TodoItem = (state, actions) => app({
  model: state,
  update: actions,
  view: (item, action) => html`<li onclick=${e => action.toggle(item)}>${item.text}</li>`
})

All is okey, but it adds Todo to DOM body two times

2017-01-31-14 53 55_1280x1024_scrot

Passing opts.root seems to not deal with that problem.

The only thing that I changed to the core source code, is to return node from app function.

@tunnckoCore
Copy link
Author

So, it should not "auto mount". Maybe would be cool to return a function that when called to append to body, or that function can accept selector where app to be mounted

@tzellman
Copy link
Contributor

If you set the root of Todo to document.createElement("div") it won't double-render the Todo component. I am still looking into the TodoItem rendering...

@tunnckoCore
Copy link
Author

Yea, it seems it work, but not work for nested components (or i dont know how to call it). Nested component (here TodoItem) should know who is the parent. It is easy to document.createElement('div') and pass that div to opts.root of Todo, and later pass that same div to TodoItem and set it as its opts.root but it seems it not work.

@evgenykochetkov
Copy link
Contributor

evgenykochetkov commented Jan 31, 2017

I just breifly read the source code, so I might be wrong, but I don't think that app is intended for creating components. It's more like program in Elm's Html.App

Also, why not define TodoItem like this

const TodoItem = (item, action) => html`<li onclick=${e => action.toggle(item)}>${item.text}</li>`

Clarification: I just breifly read hyperapp's source code
edit2: here is an example in jsbin http://jsbin.com/tomusut/edit?js,output

@tunnckoCore
Copy link
Author

I know that. And basically it could be possible to be used for components if change some bytes here and there.

I actually don't like components way and things like that and choo are good and enough for me. Just started to think how it can be done, because a comments in reddit.

@evgenykochetkov
Copy link
Contributor

evgenykochetkov commented Jan 31, 2017

Oh, sorry, I was not aware of discussion on reddit.

edit: I think I found it. Very interesting, thank you!

@jorgebucaran
Copy link
Owner

@evgenykochetkov @tunnckoCore

I don't think that app is intended for creating components. It's more like program in Elm's Html.App

Correct.

And basically it could be possible to be used for components if change some bytes here and there.

Like I said on the Reddits, thank you for bringing this up. I think we may be onto something here.

@jorgebucaran
Copy link
Owner

@tunnckoCore @tzellman @evgenykochetkov Here's a TodoMVC implementation using HyperApp.

screen shot 2017-02-01 at 23 54 37

@jorgebucaran
Copy link
Owner

This is as far I think we can go with the current implementation of HyperApp.

It's not just a matter of implementation, it's also a goal of the project to remain close to the Elm Architecture and use a single model for the entire application kind of approach.

Docs have been updated to indicate this as well.

@jorgebucaran
Copy link
Owner

jorgebucaran commented Aug 31, 2018

Summary

The original idea here was to make the return value of the app function a valid node type and make apps composable that way. This is not supported, but that doesn't mean you can't create multiple different apps and communicate with each other using whatever means possible, usually wired actions in V1 or the upcoming subscriptions API in V2.

@jorgebucaran jorgebucaran added enhancement New feature or request wontfix Forget it, sorry labels Aug 31, 2018
Repository owner locked and limited conversation to collaborators Aug 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
discussion enhancement New feature or request wontfix Forget it, sorry
Projects
None yet
Development

No branches or pull requests

4 participants