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

Proposal: Element.assign() #477

Open
jonathantneal opened this issue Jul 18, 2017 · 4 comments
Open

Proposal: Element.assign() #477

jonathantneal opened this issue Jul 18, 2017 · 4 comments
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest

Comments

@jonathantneal
Copy link

jonathantneal commented Jul 18, 2017

Element.assign

^ or something like this name borrowed from Object.assign.

I would prefer an easier way to create and manipulate elements.

Element.assign(
  (Element or DOMString) element,
  optional (Object) properties,
  optional (Node or DOMString)... nodes
)

The Element.assign() method would assign attributes and children to Elements.

  1. Let node be null.
  2. If element is an DOMString, then:
    1. Set node to the result of invoking createElement using element as localName.
  3. Otherwise, set node to element.
  4. For each name and value in properties:
    1. If name is a specified property in node or its prototype chain:
      1. Set node’s name property to value.
    2. Otherwise, if value is null:
      1. Invoke removeAttribute using name as qualifiedName .
    3. Otherwise, invoke setAttribute using name as qualifiedName and value as value.
  5. Let child be the result of converting nodes into a node given nodes and context object’s node document.
  6. Append child to node.
  7. Return node.

Creating an Element when the first argument is a DOMString:

// these functions are equivalent
img = Element.assign('img');
img = document.createElement('img');
img = new Image();

Assigning properties when the second argument is an Object:

// set the `classList` property on <body>
Element.assign(document.body, { classList: 'js' });
// set the `onclick` property on <body>
Element.assign('button', { onclick() {} });

Assigning attributes when the second argument is an Object:

// set the `class="js"` attribute on <body>
Element.assign(document.body, { class: 'js' });
// create `<header role="banner">`
Element.assign('header', { role: 'banner' });

Creating an element, assigning a property, and appending text:

// create `<button type="submit">Submit</button>`
Element.assign('button', { type: 'submit' }, 'Submit');
// create `<a href="https://google.com/'">Google Search</a>`
Element.assign('a', { href: 'https://google.com/' }, 'Google Search');

Speculative Polyfill

function assign (element) {
  const [, properties, ...nodes] = arguments;
  const node = typeof element === 'string' ? document.createElement(element) : element;

  for (const name in properties) {
    if (name in node) {
      node[name] = properties[name];
    } else if (attrs[name] === null) {
      node.removeAttribute(name);
    } else {
      node.setAttribute(name, properties[name]);
    }
  }

  node.append(...nodes);

  return node;
}

This is not an original idea. Prior art includes libraries like the minimal Bliss.js by @LeaVerou, or Facebook’s React, and a handful of other popular libraries which all include very similar methods for creating new elements. This functionality has existed in other forms of older libraries as well, going back to at least jQuery’s innerHTML to Collection sugar ($('<div></div>')).

@annevk
Copy link
Member

annevk commented Jul 18, 2017

This seems like a duplicate of #150.

@annevk annevk marked this as a duplicate of #150 Jul 18, 2017
@jonathantneal
Copy link
Author

They are at least similar, @annevk, and I'm happy to move the discussion wherever. Thank you for tracking these things.

What may be unique is that I've made specific proposals using much of the same prior art originally provided in #150, and that this discussion hasn't (yet) moved to template strings.

On its own merits, I hope this proposal can be endorsed, rejected, discussed, or otherwise ignored.

I am also happy to produce a speculative polyfill with the desired semantics.

@victornpb
Copy link

I like the Idea, I just don't like it being too polymorphic specially the part:

Sub-Proposal 2: Appending nodes with the second argument onward:

Element.assign(element, ...nodes);

Sub-Proposal 3: Setting attributes from properties with the second argument onward:

Element.assign(element, { role: 'button' });

I would rather have , than the "sub-proposal 3" colide with the other examples.

Element.assign(element, {}, ...nodes);

@annevk annevk added the needs implementer interest Moving the issue forward requires implementers to express interest label Feb 20, 2018
@annevk annevk added the addition/proposal New features or enhancements label Apr 11, 2019
@jonathantneal
Copy link
Author

I have updated the proposal to match the suggestion of @victornpb, which is also the cowpath used by most React/JSX compatible libraries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest
Development

No branches or pull requests

3 participants