你如何正确地清除复杂物体的Aurelia绑定?

时间:2016-12-06 02:59:19

标签: aurelia aurelia-binding

背景: 我尝试使用Aurelia创建表单。我有一个人对象,我希望能够填写数据。如果用户知道关于该家庭的一些识别信息,则他们可以在输入中输入该信息,并且将显示选择框以允许用户从该家庭中选择该特定表格的个人。然后,表单将填写它所知道的关于该个人的任何信息到输入字段中,允许用户在必要时覆盖任何信息。如果他们想要选择另一个人,表单还允许他们清除所选人员。

大多数功能似乎都按预期工作,但当我尝试允许用户清除所选人员时,我发现了一些我不会预料到的行为。

我创建了一个GistRun。底部窗格正如我所料,在用户获取数据后,选择一个人然后清除他们的选择,他们再次提供select元素。如果取消注释输入元素,您将看到用户现在 必须再次单击清除操作 才能再次看到select元素。的 为什么?

如何更新应用程序,以便用户只需要清除该人一次,再次出现选择框以允许用户进行其他选择?

如果您有Aurelia应用程序,则应该可以通过将app.html替换为以下内容来重现此问题:

<template>
  <select value.bind="val2" if.bind="opts2 && !val2">
    <option repeat.for="opt of opts2" model.bind="opt">${opt.firstName}</option>
  </select>
  <div if.bind="!opts2 || val2">
    <span>${val2.firstName}</span>
    <button click.delegate="clearVal2()" if.bind="val2">Clear</button>
  </div>
  <button click.delegate="getOpts2()">Get</button>
  <div>${val2.blah}</div>
  <!--<input type="text" value.bind="val2.blah"/>-->
</template>

app.js与此:

export class App {
  opts2;
  val2;

  getOpts2(){
    this.opts2 = [
      undefined,
      {
        blah: 1,
        firstName: 'foo',
        address: {
          line1: '123 Main St.'
        }
      },
      {
        blah: 2,
        firstName: 'bar',
        address: {
          line1: '456 Other Wy.'
        }
      }
    ];
  }

  clearVal2(){
    this.val2 = null;
  }
}

非常感谢任何帮助。谢谢!

更新 如果我将输入放在自定义元素中并绑定到该元素,事情似乎按预期工作。我在表单中添加的值虽然不在一个可以使用自定义元素的位置。 I have updated the Gist with an example

如何在不需要自定义元素的情况下实现相同的功能?

3 个答案:

答案 0 :(得分:2)

说实话,我不确定原因,但是如果在输入元素上添加if.bind =&#34; val2&#34;它会清除该值并返回选择按钮。

<input type="text" if.bind="val2" value.bind="val2.blah"/>

希望这(稍微)帮助

答案 1 :(得分:0)

假设您允许用户从列表中选择一个值或创建一个全新的条目,我倾向于将列表中选择的值和备份文本框的数据分开。每当select的值发生更改时,我都会将支持文本框的对象的值设置为select的值。我在示例代码中选择执行此操作的方法是在observable绑定的值上使用select装饰器。

以下是一个例子:https://gist.run?id=e4b594eaa452b47d9b3984e7f9b04109

<强> app.html

<template>
  <div>
    <select value.bind="val" if.bind="opts && !val">
      <option repeat.for="opt of opts" model.bind="opt">${opt.firstName}</option>
    </select>
    <button click.delegate="getOpts()">Get</button>
  </div>
  <div if.bind="!opts || person">
    <span>First Name: ${person.firstName}</span>
    <button click.delegate="resetForm()" if.bind="val">Clear Selection</button>
  </div>
  Address: <input type="text" value.bind="person.address.line1" />

  <hr />
  val
  <pre><code>
    ${toJSON(val)}
  </code></pre>
  person
  <pre><code>
    ${toJSON(person)}
  </code></pre>
</template> 

<强> app.js

import {observable} from 'aurelia-framework';

export class App {

  @observable val = null;
  person = {};

  getOpts(){
    this.opts = [
      null,
      {
        blah: 1,
        firstName: 'foo',
        address: {
          line1: '123 Main St.'
        }
      },
      {
        blah: 2,
        firstName: 'bar',
        address: {
          line1: '456 Other Wy.'
        }
      }
    ];
  }

  valChanged() {
    this.person = this.val;
    console.log("set person");
  }

  resetForm(){
    this.val = null;
    console.log("reset val");
  }

  toJSON(value) {
    if(!(value === false) && !value) {
      return '';
    }

    return JSON.stringify(value);
  }
}

重置表单时,您可以看到有趣的事情发生。当我们设置person时,Aurelia正在创建绑定到person.address.line1所需的属性(即person = null。但它不会创建firstName属性,b / c在person停止虚假之前,财产不受约束。

答案 2 :(得分:0)

此处的另一个选择是简单地使用with属性来确定输入范围。

https://gist.run/?id=7b9d230f7d3c6dc8c13cefdd7be50c7f

<template>
  <template with.bind="val.address">
    <input value.bind="line1" />
  </template>
</template>

虽然我同意混合选择和输入的逻辑可能不是最好的主意:)