polymerpolymer-2.xdom-repeatiron-ajaxiron-form

How to addEventListener to Polymer 2.0 iron-forms loaded with iron-ajax within dom-repeat template


I have been using the following syntax to edit iron-form requests before submitting in Polymer 2.0:

connectedCallback() {
    super.connectedCallback();
    someForm.addEventListener('iron-form-presubmit, function() {...})
}

Now I want to load multiple iron-forms within a dom-repeat, each with the same iron-form-presubmit function. The number and content of the forms are loaded from the server using iron-ajax. I intended to loop through all the forms and add the event listener but it seems when I call the following, the forms have not yet loaded so allForms is empty.

HTML:

<iron-ajax auto
    id="requestSchedules"
    url="/api/v2/schedules"
    handle-as="json"
    on-response="handleApiResponse"
    last-response="{{schedules}}">
</iron-ajax>

<dom-repeat items="[[schedules]]">
    <template>
      <paper-card heading="Schedule">       
        <div class="card-content">
          <iron-form id="scheduleForm[[item.id]]">
              ...

Javascript:

connectedCallback() {
    super.connectedCallback();
    var allForms = this.shadowRoot.querySelectorAll("iron-form");
    // here allForms = []
    ...
}

Inspecting the shadow DOM with a break-point at this point shows the dom-repeat template has not loaded. Is there a way I can wait until the page has completed loading or possibly another way to accomplish the same thing?


Solution

  • You could listen to <dom-repeat>'s dom-change event, which occurs when the template contents change. The event handler could then use querySelectorAll to get a reference to the <iron-form>s:

    template:

    <dom-repeat on-dom-change="_onDomRepeatChange">
    

    script:

    _onDomRepeatChange(e) {
      const forms = this.shadowRoot.querySelectorAll('iron-form');
      Array.from(forms).forEach(form => {
        form.addEventListener('iron-form-presubmit', function() {
          this.request.method = 'post';
          this.request.params['foo'] = true;
        });
      });
    }
    

    window.addEventListener('WebComponentsReady', () => {
      class XFoo extends Polymer.Element {
        static get is() { return 'x-foo'; }
    
        _onDomRepeatChange(e) {
          const forms = this.shadowRoot.querySelectorAll('iron-form');
          Array.from(forms).forEach(form => {
            form.addEventListener('iron-form-presubmit', function() {
              this.request.method = 'post';
              this.request.params['foo'] = true;
            });
            
            form.addEventListener('iron-form-response', e => {
              const response = e.detail.response;
              this.formResponse = JSON.stringify(response, null, 2);
            });
          });
        }
      }
      customElements.define(XFoo.is, XFoo);
    });
    <head>
      <base href="https://cdn.rawgit.com/download/polymer-cdn/2.6.0.2/lib/">
      <script src="webcomponentsjs/webcomponents-loader.js"></script>
      <link rel="import" href="polymer/polymer.html">
      <link rel="import" href="iron-ajax/iron-ajax.html">
      <link rel="import" href="iron-form/iron-form.html">
      <link rel="import" href="paper-card/paper-card.html">
    </head>
    <body>
      <x-foo></x-foo>
    
      <dom-module id="x-foo">
        <template>
          <iron-ajax auto
                     id="requestSchedules"
                     url="https://httpbin.org/anything"
                     method="POST"
                     handle-as="json"
                     content-type="application/json"
                     body='[{"id":1, "x":1},{"id":2, "x":2}]'
                     last-response="{{schedules}}">
          </iron-ajax>
    
          <template is="dom-repeat" items="[[schedules.json]]" on-dom-change="_onDomRepeatChange">
            <paper-card heading="Schedule">
              <div class="card-content">
                <iron-form id="scheduleForm[[item.id]]">
                  <form action="https://httpbin.org/post">
                    <input name="name" type="text" placeholder="Name">
                    <button>Submit</button>
                  </form>
                </iron-form>
              </div>
            </paper-card>
          </template>
          
          <pre>[[formResponse]]</pre>
        </template>
      </dom-module>
    </body>

    Alternatively, you could use an annotated event listener on <iron-form>:

    template:

    <iron-form on-iron-form-presubmit="_onIronFormPresubmit">
    

    script:

    _onIronFormPreSubmit(e) {
      const ironForm = e.composedPath()[0];
      ironForm.request.method = 'post';
      ironForm.request.params['foo'] = true;
    }
    

    window.addEventListener('WebComponentsReady', () => {
      class XFoo extends Polymer.Element {
        static get is() { return 'x-foo'; }
    
        _onIronFormPreSubmit(e) {
          const ironForm = e.composedPath()[0];
          ironForm.request.method = 'post';
          ironForm.request.params['foo'] = true;
        }
    
        _onIronFormResponse(e) {
          const response = e.detail.response;
          this.formResponse = JSON.stringify(response, null, 2);
        }
      }
      customElements.define(XFoo.is, XFoo);
    });
    <head>
      <base href="https://cdn.rawgit.com/download/polymer-cdn/2.6.0.2/lib/">
      <script src="webcomponentsjs/webcomponents-loader.js"></script>
      <link rel="import" href="polymer/polymer.html">
      <link rel="import" href="iron-ajax/iron-ajax.html">
      <link rel="import" href="iron-form/iron-form.html">
      <link rel="import" href="paper-card/paper-card.html">
    </head>
    <body>
      <x-foo></x-foo>
    
      <dom-module id="x-foo">
        <template>
          <iron-ajax auto
                     id="requestSchedules"
                     url="https://httpbin.org/anything"
                     method="POST"
                     handle-as="json"
                     content-type="application/json"
                     body='[{"id":1, "x":1},{"id":2, "x":2}]'
                     last-response="{{schedules}}">
          </iron-ajax>
    
          <template is="dom-repeat" items="[[schedules.json]]">
            <paper-card heading="Schedule">
              <div class="card-content">
                <iron-form id="scheduleForm[[item.id]]"
                           on-iron-form-presubmit="_onIronFormPreSubmit"
                           on-iron-form-response="_onIronFormResponse">
                  <form action="https://httpbin.org/post">
                    <input name="name" type="text" placeholder="Name">
                    <button>Submit</button>
                  </form>
                </iron-form>
              </div>
            </paper-card>
          </template>
          
          <pre>[[formResponse]]</pre>
        </template>
      </dom-module>
    </body>