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

unpleasant side-effect of bindValue default value = '' (#130) #143

Open
2 tasks done
christophe-g opened this issue Nov 29, 2018 · 0 comments
Open
2 tasks done

unpleasant side-effect of bindValue default value = '' (#130) #143

christophe-g opened this issue Nov 29, 2018 · 0 comments

Comments

@christophe-g
Copy link

Description

While upgrading my app to Polymer 2.0, I encountered a pretty nasty side effect of #130 (bindValue having a default value = ''), where persistent data is being wiped in situation like :

<firebase-document path="/myPath" data= "{{data}}"></firebase-document>
<paper-input label="label" value="{{data.WILL_BE_DELETED}}"></paper-input>

Expected outcome

data.WILL_BE_DELETED is saved/synched between persistent layer (firebase) and paper-input.

Actual outcome

Persisted data is being wiped out because iron-input instantiate a default '' value, which is being notified to the persistent layer.

Fix

Prevent iron-input to notify upstream when the element is being attached (_initSlottedInput) and bindValue = "" (default value).

Tests are passing.

If this seems acceptable, I will propose a PR.

      _initSlottedInput: function() {
        this._isInitiatingSlottedInput = true;
        this._inputElement = this.getEffectiveChildren()[0];

        if (this.inputElement && this.inputElement.value) {
          this.bindValue = this.inputElement.value;
        }

        this._isInitiatingSlottedInput = false;
        this.fire('iron-input-ready');
      },
      
      /**
       * @suppress {checkTypes}
       */
      _bindValueChanged: function(bindValue, inputElement) {
        // The observer could have run before attached() when we have actually
        // initialized this property.
        if (!inputElement) {
          return;
        }

        if (bindValue === undefined) {
          inputElement.value = null;
        } else if (bindValue !== inputElement.value) {
          this.inputElement.value = bindValue;
        }

        if (this.autoValidate) {
          this.validate();
        }

        // Note(cg): prevent notifying the change when initiating slotted input and bindValue is default. 
        if(this._isInitiatingSlottedInput && bindValue === '') {
          return;
        }
        // manually notify because we don't want to notify until after setting value
        this.fire('bind-value-changed', {value: bindValue});
      },

Steps to reproduce

Example bellow will produce:
image

<html>
<head>

  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">

  <title>iron-input demo</title>

  <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
  <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">

  <link rel="import" href="../../paper-input/paper-input.html">
   <!-- Order of imports matters. The validator needs to be imported before the
    iron-input needs it. -->
  <link rel="import" href="../iron-input.html">
  
  <custom-style>
    <style is="custom-style" include="demo-pages-shared-styles"></style>
  </custom-style>
</head>
  
  <dom-module id="app-test">
    <template>
      <style>
        :host {
          display: block;
        }
        
      </style>
      <ul>
      <template is="dom-repeat" items="[[logs]]">
          <li >name: [[item]]</li>
      </template>
      </ul>
      <div >name: [[data.name]]</div>
    </template>
    <script>
      Polymer({
        is: 'app-test',
        
        properties: {
          
          data:  {
            type: Object,
            notify: true, 
            value: {}
          },

          logs: {
            type: Array, 
            value: []
          }
        },
  
        observers: ['_observeData(data, data.*)'],
        
        _observeData() {
          this.push('logs', JSON.stringify(this.data));
          if(this.data && this.data.name === '') {
            this.push('logs', 'EMPTY !!!');
          }
        }
      });
    </script>
  </dom-module>
</script>

<body>
  <div class="vertical-section-container centered">
    <h4>Basic inputs</h4>
    <demo-snippet class="">
      <template>
         <dom-bind id="app">
          <template>
            <app-test data="{{data}}"></app-test>
            <paper-input placeholder="name" label="my name" value="{{data.name}}"></paper-input>
          </template>
        </dom-bind>
      </template>
    </demo-snippet>
    <script>
    window.addEventListener('WebComponentsReady', function() {

      const app = document.querySelector('#app');
      app.data = {name:'cg'}

    });
    </script>
  </div>
</body>
</html>

Browsers Affected

  • Chrome
  • Firefox
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant