Daveman
Daveman

Reputation: 1096

How to wrap an input field in a custom element?

I am trying to wrap an input field inside a custom element.

The custom element DOM looks like this:

<custom-element>
  <div class="fancy-wrapper">
     <input value="4">
  </div>
<custom-element>

While the element should work like this:

<custom-input id="test"></custom-input>

<script>
let test = document.getElementById('test')
console.log(test.value); //  should return 4 (value of inner input)

test.onkeydown = function(e){
    console.log(e.target.value); // should the new value of the inner input
};
</script>

Is there any way to get the <custom-input> attributes redirected to the <input> attributes inside it, without connecting everything by hand?

Upvotes: 1

Views: 1085

Answers (4)

ellipsis
ellipsis

Reputation: 12152

You can append to the innerHTML of the custom element tag

var string="<input type='text' ";
document.getElementById('test').onclick = function(e){
var attr=[...document.querySelector('#test').attributes].map(attr => attr.nodeName);
attr.forEach((e)=>{
var val=document.getElementById('test').getAttribute(e);
string+=e+"="+val + " ";
})
document.getElementById("test").innerHTML+=string + '//>' ;
console.log(document.getElementById("test").outerHTML)
};
<custom-input id="test">dd</custom-input>

Upvotes: 0

No, it is no different than having one DIV and another child DIV

You have to make the connection between the CustomElement and content yourself.

One way is to define a Get/Set function on your Custom-Element that fetches the value of a child input

Instead of manually declaring Get/Set You can ofcourse loop any child element and assign on the CustomElement with defineProperty or Proxies

Example below creates 2 INPUT fields and a this.input array:

    <number-and-range>
       <input type="number"> // this.input[0]
       <input type="range">  // this.input[1]
    </number-and-range>

And connects (GET/SET) <number-and.range>.value to this.input[0]

customElements.define('number-and-range', class extends HTMLElement {
  get value() {
    return this.input[0].value;
  }

  set value(val) {
    //input validation should go here
    this.input[0].value = val;
    console.clear();
    console.log('new value:',val);
  }
  connectedCallback() {
    this.input = ['number', 'range'] //create [0] and [1] values in array
      .map((type, idx) => Object.assign(
        this.appendChild(document.createElement('input')), {
          type,
          min: 20,
          max: 50,
          oninput: _ => this.value = this.input[~~!idx].value = this.input[idx].value //toggle [0] and [1]
        }));
    this.value = 42;//default value
  }
});

let el=document.querySelector('number-and-range');
console.log(el.value);
el.value=99;
<body>
<h3>Custom Element : Connected INPUT and Range slider</h3>
Please enter a number between 20 and 50, or use the range slider
<p>
<number-and-range></number-and-range>
</p>
</body>

Upvotes: 2

Ankit Sinha
Ankit Sinha

Reputation: 1680

HTML:

<custom-element id="test">
  <div><input value="43" /></div>
</custom-element> 

JavaScript:

class CustomElement extends HTMLElement {
  constructor() {
    super();
    const currentDocument = document.currentScript.ownerDocument;
    this.template = currentDocument.querySelector('input');
  }
  get value() {
    return this.template.getAttribute('value');
  }
  set onkeydown(cb) {
    return this.template.addEventListener('keydown', cb);
  }
}

window.customElements.define('custom-element', CustomElement);

let test = document.getElementById('test');
console.log(test.value);
test.onkeydown = function(e) {
  console.log(e.target.value);
};

Can take a look at demo

Upvotes: 0

Jayendra Sharan
Jayendra Sharan

Reputation: 1018

If I understood your question, you want to copy all the attributes of the custom-element to the input tag.

What you can do is,

//get all attributes of custom element
var el = document.getElementById ('test');

// get all attributes
var attrs = el.getAttributeNames(); // returns an array

// loop over attrs array and append the attribute and value in the input,
// I am assuming, you will not add copy id attribute here.

var input = el.getElementsByTagName ('input')[0];
for (var index = 0; index < attrs.length; index++) {
  if (attrs[index] !== 'id') {

    // set attribute of input with attribute name from the array,
    // and get the value from from input.

    input.setAttribute (attrs[index], el.getAttribute (attrs[index]));
  }
}

It's an idea, you can do something else.

Upvotes: 0

Related Questions