事件触发时,本地DOM元素上的Polymer 2 TypeError

时间:2018-05-09 20:20:56

标签: javascript events javascript-events polymer polymer-2.x

我有一个搜索输入字段来接收用户输入和一个响应用户输入的变量状态按钮。注意搜索输入上的on-input事件。

<dom-module id="app-search">
    <template>

        <input type="search" id="searchInput" on-input="_onInput" />

        <!-- NOTE: button is set to 'disabled' when there is no value of search field -->
        <paper-button disabled>Done</paper-button>

    </template>
</dom-module>

在Polymer ready()定义中,我获得了paper-button元素的句柄(ready()函数在所有内容之后被调用,包括在元素及其属性被初始化之后,所以它是是查询本地DOM的好时机。

ready() {
    super.ready(); // must call this for Polymer to work

    // get handle to paper-button element
    this._doneBtn = Polymer.dom(this.root).querySelector('paper-button');
}

顺便说一下,我知道使用this.$可以用作Polymer.dom(this.root).querySelector()的语法快捷方式,但该语法似乎只适用于具有id的本地DOM,例如:this.$.searchInput将返回带有id="searchInput"元素的句柄。是否有人知道定位非id,常规元素的简写必须输入Polymer.dom(this.root)... ?)

我有一个功能可以检测搜索字段上的input个事件。如果搜索字段中有值,请启用该按钮。

_onInput() {
    // if search input has value
    if (Boolean(this.$.searchInput.value)) {
        // remove disabled attr from button
        this._doneBtn.removeAttribute('disabled');
    } else {
        this._disableBtn();
    }
}

_disableBtn() {
    this._doneBtn.setAttribute('disabled', true);
}

到目前为止,这样做是为了当用户开始输入时,按钮变为启用状态;当没有值时,该按钮被禁用。

但是,按照惯例,用户还可以通过单击搜索输入右侧显示的小“x”来删除输入值。开发人员可以通过将search事件附加到input元素来检测该事件:

ready() {
    super.ready(); // must call this for Polymer to work

    // get handle to paper-button element
    this._doneBtn = Polymer.dom(this.root).querySelector('paper-button');

    // attach 'search' event listener to search input field
    // call the element's '_disableBtn' function
    this.$.searchInput.addEventListener('search', this._disableBtn);
}

问题当我通过点击搜索字段有值时显示的“x”来触发事件时,this._disableBtn函数会触发,但this._doneBtn内部会出现_doneBtn函数返回undefined Uncaught TypeError: Cannot read property 'setAttribute' of undefined

假设这可能与不正确的类型定义有关,我尝试在Polymer属性getter中声明static get properties() { return { _doneBtn: Object // also tried 'String' } } 属性:

_disabledBtn

我还尝试再次从_disableBtn() { if (!this._doneBtn) { this._doneBtn = Polymer.dom(this.root).querySelector('paper-button'); } this._doneBtn.setAttribute('disabled', true); } 函数内部查询DOM并尝试重新声明属性,但我仍然得到同样的错误:

ready()

有谁能理解这里发生了什么?这似乎与事件监听器有关。虽然在this调用中切换声明的顺序没有区别,但DOM在解析之前可能没有完全呈现?它也可能与console.log(this)有关。

有趣的是,当我在_disableBtnthis时,控制台会返回两个不同的<app-search>实例,一个用于主机元素(this),另一个用于目标元素解雇了这个事件:two elements point to 'this'。另外值得注意的是打印@Override protected void onCreate(Bundle _savedInstanceState) { super.onCreate(_savedInstanceState); setContentView(R.layout.main); MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713"); mAdView = findViewById(R.id.adView); mAdView.loadAd(new AdRequest.Builder().build()); mInterstitialAd = new InterstitialAd(this); mInterstitialAd.setAdUnitId("ca-app-pub-3940256099942544/1033173712"); mInterstitialAd.loadAd(new AdRequest.Builder().build()); mInterstitialAd.setAdListener(new AdListener() { @Override public void onAdLoaded() { SketchwareUtil.showMessage(getApplicationContext(), "Tap to start"); } }); initialize(); } private void initialize() { imageview1 = (ImageView) findViewById(R.id.imageview1); imageview1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { i.setClass(getApplicationContext(), PlaylistActivity.class); startActivity(i); if (mInterstitialAd.isLoaded()) { mInterstitialAd.show(); } else { showMessage("Error"); Log.d("AD", "The interstitial wasn't loaded yet."); } } }); } 的顺序。

我希望比我更聪明的人可以帮助解决这里发生的事情。感谢。

2 个答案:

答案 0 :(得分:1)

我的直觉是你没有正确使用“这个”。 “this”表达是违反直觉的,因为我们倾向于自动将其与词法范围或使用“this”的位置相关联。唉,情况并非如此,因为“this”绑定不是在JIT“编译时”或“运行时”确定,而是在“通话时间”确定。

这表示调用它的上下文。因此,只需将一行代码从一个函数移动到另一个函数,“this”就可以引用其他内容。而其他东西可能没有附加“setAttribute”函数,因此“未定义”错误消息。

解决这个问题的一种方法(没有双关语意)现实是用.bind配置被调用的函数([调用该函数时我们想要“这个”的值])。

例如,而不是编写以下代码段:

} else {
    this._disableBtn();
}

你会写的

} else {
    this._disableBtn().bind(this);
}

你可能已经确定你在_disableBtn()函数中使用的“this”指向与“this”在“else”块中所做的目标相同的目标。

基本上,“this”值取决于原始调用站点上下文所使用的函数被调用(我不确定这是否清楚......但如果它没有意义,请重新读取它第一次飞行)。要在被调用函数中对“this”的值进行硬编码,可以在调用函数时添加.bind(要传递给被调用函数的“this”值),如:

function aFunction() {
   myfunction(parameter).bind("required value of 'this' in myFunction").
}

希望这有帮助。

杰克

答案 1 :(得分:1)

在阅读@ softjake的回复后,我能够解决问题。

首先,让我们重新审视addEventListener()函数中添加的ready()设置:

ready() {
    super.ready();

    // handle to toggle button element
    this._doneBtn = Polymer.dom(this.root).querySelector('paper-button');

    // previous method === no worky
    //this.$.searchInput.addEventListener('search', this._disableBtn);

    // changed it to:
    this.$.searchInput.addEventListener('search', this._disableBtn.bind(this._doneBtn));
}

这里的关键是我使用.bind(this._doneBtn)确保this_disableBtn函数范围内的this._doneBtn而不是其他this _disableBtn 1}}(与父元素或文档/窗口一样)。

最后,稍微调整_disableBtn() { // previous (also no worky) //this._doneBtn.setAttribute('disabled', true); // changed to: this.setAttribute('disabled', true); } 功能:

this

由于this._doneBtn已引用this.setAttribute(...),我们只需使用// GET: api/Categories [HttpGet] public IEnumerable<Category> GetCategories() { return _context.Categories; }