-->

Can't find element on iron ajax event methods

2019-08-31 06:25发布

问题:

For below given code this.$.createButton or document.querySelector('createButton') works inside the ready method. But same code fails inside handleRequestSent or handleResponseReceived. The error message I get is

Uncaught TypeError: Cannot read property 'createButton' of undefined

I tried to debug, it appears that inside handleRequestSent and handleResponseReceived the this actually pointing to iron-ajax, but not the element dom root. Any suggestion is welcome. Thanks in advance.

<dom-module id="bortini-tv-create">
    <template>
        <form>
            <paper-input label="Name" value="{{tv.name}}"></paper-input>
            <paper-input label="Logo" value="{{tv.logo}}"></paper-input>
            <paper-input label="Address" value="{{tv.address}}"></paper-input>
            <paper-input label="Web site" value="{{tv.webSite}}"></paper-input>
            <paper-input label="Registration number" value="{{tv.regNumber}}"></paper-input>
            <br/>
            <br/>
            <paper-button id="createButton" raised on-tap="handleTvCreate">
                <iron-icon icon="redeem"></iron-icon>
                Add
            </paper-button>
            <paper-button id="cancelButton" raised on-tap="handleCancelTvCreate">
                <iron-icon icon="cancel"></iron-icon>
                Cancel
            </paper-button>
        </form>

        <iron-ajax
                id="ironAjax"
                url="/api/tv"
                content-type="application/json"
                handle-as="json"
                method="POST">
        </iron-ajax>

        <paper-toast id="toast"
                     duration="3000"
                     text="TV {{tv.name}} has been created">
        </paper-toast>
    </template>
</dom-module>
<script>

    function initModel() {
        return {"name": "", "logo": "", "address": "", "webSite": "", "regNumber": ""};
    }


    Polymer({
        is: "bortini-tv-create",
        properties: {
            tv: {
                type: Object,
                value: initModel(),
                notify: true
            }
        },
        ready: function() {
            this.$.ironAjax.addEventListener('error', this.handleError);
            this.$.ironAjax.addEventListener('request', this.handleRequestSent);
            this.$.ironAjax.addEventListener('response', this.handleResponseReceived);
        },
        handleTvCreate: function (event) {
            var ironAjax=document.querySelector("#ironAjax");
            ironAjax.body = JSON.stringify(this.tv);
            ironAjax.generateRequest();
        },
        handleCancelTvCreate: function (event) {
            MoreRouting.navigateTo('tv-list');
        },
        handleError: function(event) {
            this.$.createButton.disabled=false;
            this.$.cancelButton.disabled=false;

            var request=event.detail.request;
            var error=event.detail.error;
            var toast=document.querySelector("#toast");
            toast.text="Error: "+error;
            toast.show();
        },
        handleRequestSent: function (request) {
            console.log("boooooo");
            this.$.createButton.disabled=true;
            this.$.cancelButton.disabled=true;

        },
        handleResponseReceived: function (response) {
            document.querySelector('createButton').disabled=false;
            document.querySelector('cancelButton').disabled=false;

            console.log("Received response: " + JSON.stringify(response.detail.response));
            document.querySelector('#toast').show();
            MoreRouting.navigateTo('tv-list');
        }
    });
</script>

回答1:

Because you set your event handlers imperatively the scope (i.e this) the handler is called with, isn't your element instance.

Two ways to solve this:

  1. Bind the event handler to your element instance:

    this.$.ironAjax.addEventListener('error', this.handleError.bind(this));

    This will make sure that this inside of the event handler is actually the this you want.

  2. Define the event handlers declaratively, then Polymer will take care of the proper binding:

    <iron-ajax ... on-error="handleError" ...></iron-ajax>



回答2:

this is because the responseHandler method is fired from an iron-request-element inside. So the this-context moves to the iron-ajax element. If you want to return to your "original" firing element from there, simply use the this.parentElement try something like this:

[...]
handleResponseReceived: function( request ) 
{
  var that = this.parentElement;
  that.$.createButton.disabled=true;
}

This should do the trick. Sorry for answering that late. ;)