Hacker News new | ask | show | jobs
by tjallingt 3575 days ago
I've never seen this before:

    children(el => [
      el.email = input(props({ type: 'email' })),
      el.pass = input(props({ type: 'pass' })),
      el.submit = button(text('Sign in'))
    ])
Can someone explains what this does and why it is used here? As i understand it this function both modifies the `el` object (whatever that is) and returns an array containing the input elements, but why would you want to do both those things at the same time?
5 comments

Here’s what I believe will be an accurate translation of that example to the normal DOM API (without having actually looked at the RE:DOM source code):

    const login = document.createElement('form');
    
    login.email = document.createElement('input');
    login.email.type = 'email';
    
    login.pass = document.createElement('input');
    login.pass.type = 'pass';
    
    login.submit = document.createElement('button');
    login.submit.textContent = 'Sign in';
    
    login.appendChild(login.email);
    login.appendChild(login.pass);
    login.appendChild(login.submit);
    
    login.onsubmit = function(event) {
        event.preventDefault();
        console.log(this.email.value, this.pass.value);
    };
    
    document.body.appendChild(login);
The children call produces an array of objects that are appended to the element, but the callback also takes the wrapping element (in this case `login`), and so to be conveniently able to access it later (`login.email.value`) it also assigns them there. A more conventional JavaScript approach would be to assign email, pass and submit as local variables rather than stuffing them inside the form object.

As for the other example:

    const app = document.createElement('table');
    const tbody = document.createElement('tbody');

    app.appendChild(tbody);

    app.update = function(data) {
        tbody.innerHTML = '';
        for (let row in data.tbody) {
            let tr = document.createElement('tr');
            for (let cell in row) {
                let td = document.createElement('td');
                td.textContent = cell;
                tr.appendChild(td);
            }
            tbody.appendChild(tr);
        }
    }

    document.body.appendChild(app);

    app.update({
        tbody: [
            [1, 2, 3],
        ],
    });
This is rather simpler, frankly. I prefer plain DOM for myself at this level.
That is a great explanation and after looking at the source code and reading the example more closely that is indeed what appears to happen. I do think that, albeit very clever, it's a confusing pattern though...
And too tricky - assigning to arbitrary properties on a DOM object can have arbitrary side effects if ever you happen to overload a predefined property (on any browser).
That is an arrow function.

children() is supposed to take a function as argument and that function is supposed to return the list of children.

So basically:

children( function(el) {

  return [

    el.email = input(props({ type: 'email' })),

    el.pass = input(props({ type: 'pass' })),

    el.submit = button(text('Sign in'))

  ]
} )

Also,

[

   el.email = input(props({ type: 'email' }))

   ,

   ...
]

is a neat idea. In one (expressive) line he is assigning the value to the array and also giving the child (in this case, email) a name and reference in its parent, so later he can just call el.email (in the onsubmit function).

Yeah, I'm using similar technique with FRZR as well (https://frzr.js.org), but with RE:DOM I wanted to experiment with ES2015 and also break the API to smaller parts, which you can replace with your own if you like..
At first I was gonna say, this could be expressed with an object expression, but actually if you think about it object expressions don't grantee ordering of it's elements, that and you could probably don't need a reference to all children of a component.

    children(function(el) {
      var a, b, c;
      a = input(props({ type: 'email' }));
      el.email = a;
      // etc
      return [a, b, c];
    })
Entirely guesswork but: El is the form element you're defining children on. You need to provide references to the elements you're creating so that you can use them later (el.email and friends) but you also need to return them to the children function in an ordered manner so that it can actually attach them into the DOM.
Aah of course; By reading the source code of the children function I figured the array of elements returned was appended to the parent element. The strange thing was that it was also adding them to `el` object but indeed it appears this is done to maintain a reference to the children so they can be modified later (which I would have seen had i read the example a bit more carefully :S )

I'm still not sure how I feel about that bit of code though but it sure is clever...

Yeah, check out my another library FRZR too: https://frzr.js.org

Point is to be able to design: 1) how you create component 2) how you update it Both 1) and 2) are just simple functions.

I explain a similar case in my presentation about my another library FRZR: https://youtu.be/0nh2EK1xveg
I'd assume it's argument chaining, e.g.:

> find('elements').clear('contents').add('border')

somehow that reminds me of delete('facebook').lawyer('up').hit('thegym') ;)