ionic-team / stencil

A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
https://stenciljs.com
Other
12.5k stars 783 forks source link

Input's value attribute missing in the DOM #2946

Open coconnorco opened 3 years ago

coconnorco commented 3 years ago

Stencil version:

 @stencil/core@2.6.0

I'm submitting a:

[x] bug report [ ] feature request [ ] support request => Please do not submit support requests here, use one of these channels: https://stencil-worldwide.herokuapp.com/ or https://forum.ionicframework.com/

Current behavior: When setting a value attribute on an <input> element, that input is missing the value attribute. The property value gets set though.

Expected behavior: I expect that the value attribute gets rendered to the dom

Related code:

import {Component, h} from '@stencil/core';

@Component({
  tag: 'c-test',
})
export class Test {
  render() {
    return (
        <input value="30" min="0" max="100" type="text" />
    )
  }
}

as <c-test></c-test> renders as

Screenshot_565

Screenshot_566

Other Information I use stencil build --watch --docs to build the components

splitinfinities commented 3 years ago

Hey! Thanks for submitting this. While investigating this issue, we bumped into a couple things.

First, this line that may or may not be running, suggests that when setting value, you may need to set value after the min and max props. https://github.com/ionic-team/stencil/blob/master/src/runtime/vdom/h.ts#L172 Based on the next item I wrote below I may think that this doesn't matter.

Second, I wanted to check to see if the input element would reflect the value of value on the input element. From my preliminary tests, I can't see cases where the value prop is reflected, so I think this is intended behavior.

I went to a new index.html page, added an input element, opened the dev tools and set value and did not see the value reflected to the element. I think this may be by design for layout recalculation related reasons - value would be an attribute that changes often, so the DOM library may prevent the value prop from propagating to the attribute.

Could you add a reproduction repo with this updated code?

adoumas commented 2 years ago

Hello,

I have the same issue. I'm trying to build a material web components wrapper with stencil and the input fields loosing the value and I cant bind on them.

import { Component, Prop, Event, EventEmitter, h } from '@stencil/core';
import { MDCSlider } from '@material/slider';

@Component({
  tag: 'mdc-slider',
  styleUrl: 'mdc-slider.scss',
  // shadow: true,
})

export class MdcSlider {

  @Prop({reflect:true}) value: string = '0';

  @Prop({reflect:true}) disabled: boolean = false;

  @Event() change: EventEmitter;

  @Event() inputChange: EventEmitter;

  mdcSlider: any;
  mdcSliderComponent: any;
  mdcSliderInput: any;

  componentDidLoad(){
    this.mdcSliderComponent = MDCSlider.attachTo(this.mdcSlider);
    // this.mdcSliderComponent.listen('MDCSlider:change', () => {
    //   // this.change.emit(this.mdcSliderInput.value);
    // });
    // this.mdcSliderComponent.listen('MDCSlider:input', () => {
    //   // this.inputChange.emit(this.mdcSliderInput.value);
    // });
  }

  disconnectedCallback(){
    this.mdcSliderComponent.destroy();
  }

  render() {
    return (
      <div
        class={{
          'mdc-slider': true,
          'mdc-slider--disabled': this.disabled,
        }}
        ref={(mdcSlider) => { this.mdcSlider = mdcSlider; }}
      >
        <input
          class="mdc-slider__input"
          type="range"
          min="0"
          max="100"
          value={this.value}
          name="volume"
          disabled={this.disabled}
          ref={(mdcSliderInput) => {  this.mdcSliderInput  = mdcSliderInput }}
        />
        <div class="mdc-slider__track">
          <div class="mdc-slider__track--inactive" />
          <div class="mdc-slider__track--active">
            <div class="mdc-slider__track--active_fill" />
          </div>
        </div>
        <div class="mdc-slider__thumb">
          <div class="mdc-slider__thumb-knob" />
        </div>
      </div>
    );
  }
}

BR

adoumas commented 2 years ago

I found a solution and you need to add defaultValue={this.value} to access the value attribute

rwaskiewicz commented 2 years ago

Hey all,

I dug into this this morning and was able to reproduce the issue. Both in plain HTML and a 'vanilla' web component, we should expect to see value, which I don't in Stencil. Gonna tag this to get it ingested into the backlog for the team to look further into it