【问题标题】:Data binding on JavaScript HTMLElement property in PolymerPolymer 中 JavaScript HTMLElement 属性的数据绑定
【发布时间】:2016-04-28 12:17:20
【问题描述】:

使用 Polymer 制作 SPA,我需要我的自定义组件都使用一个通用的自定义组件,该组件代表我的后端 API,并负责从 API 获取/发布数据。它还用作“缓存”并保存要显示的数据。这样,所有有权访问该单个元素的组件都将共享相同的数据。

所以我想做的是这个......:

<my-api
  users="{{users}}"
  products="{{products}}">
</my-api>

...但是以编程方式,因为&lt;my-api&gt; 没有在我的所有组件中声明,而是在顶部声明一次,然后通过 JavaScript 传递到层次结构:

Polymer({
  is: 'my-component',
  properties: {
    api: {
      observer: '_onApiChanged',
      type: HTMLElement
    },
    products: {
       type: Array
    },
    users: {
       type: Array
    }
  },
  _onApiChanged: function(newVal, oldVal) {
    if (oldVal)
      oldVal.removeEventListener('users-changed', this._onDataChanged);

    // Listen for data changes
    newVal.addEventListener('users-changed', this._onDataChanged);

    // Forward API object to children
    this.$.child1.api = newVal;
    this.$.child2.api = newVal;
    ...
  },
  _onDataChanged: function() {
    this.users = this.api.users; // DOESN'T WORK as 'this' === <my-api>
    this.products = this.api.products; // Plus I'd have to repeat for every array
  }
});

Polymer 是否提供了内置方法来执行此操作?我可以通过编程方式创建 双花括号 绑定吗?

【问题讨论】:

  • 为什么需要向下传递 API 元素,而不仅仅是从中传递值?
  • @zacharytamas 因为例如假设component1 只需要监听产品而不是用户,但它的一个子组件subcomponent1 需要两者,那么我仍然需要声明一个@ component1 中的 987654326@ 属性,以便能够将其传递给 subcomponent1。这意味着我必须在几乎每个组件中声明所有数据数组,这使得每当我添加新数据类型时维护非常复杂,而且非常冗长。

标签: javascript data-binding polymer


【解决方案1】:

我可能会以稍微不同的方式构建它:以声明方式传递 products/users 数组,以利用 Polymer 的绑定系统。或者,您可以编写 my-api 元素,使它们都共享状态,并且第一个声明的状态是主状态,而未来声明的状态是副本。这将使您可以在需要它们的任何地方声明它们并通过 Polymer 的常规方式绑定到值。

但要回答您的问题,目前无法在不使用私有 Polymer API 的情况下以编程方式轻松设置相同类型的绑定。

为避免重复次数过多以及遇到的绑定问题,您可以使用 Polymer 的内置 listenunlisten 方法:

Polymer({
  is: 'my-component',
  properties: {
    api: {
      observer: '_onApiChanged',
      type: HTMLElement
    },
    products: {
       type: Array
    },
    users: {
       type: Array
    }
  },
  _onApiChanged: function(newVal, oldVal) {
    var apiProperties = ['users', 'products'];

    if (oldVal) {
      apiProperties.forEach(function(prop) {
        this.unlisten(oldVal, prop + '-changed', '_onDataChanged');
      });
    }

    // Listen for data changes
    apiProperties.forEach(function(prop) {
      this.listen(newVal, prop + '-changed', '_onDataChanged');
    });

    // Forward API object to children
    this.$.child1.api = newVal;
    this.$.child2.api = newVal;
    ...
  },
  _onDataChanged: function() {
    this.users = this.api.users; // `this` should be the element now
    this.products = this.api.products;
  }
});

鉴于这是您正在执行的常见模式,您可能会从将其中一些内容提取到抽象出绑定/解除绑定和 API 元素转发的 Behavior 中获得很多好处。

您可以进行的另一个优化是查看传递给_onDataChanged 的事件,看看您是否可以推断出哪个值发生了变化并更新相应的属性。这可以防止您需要为每个属性添加一行。

【讨论】:

    【解决方案2】:

    我最终使用了其他解决方案。无需手动将顶部 &lt;my-api&gt; 元素向下传递到层次结构中,任何需要访问此共享数据的元素都声明了自己的 &lt;my-api&gt;

    然后在&lt;my-api&gt; 元素的声明中,我声明所有实例都使用相同的数组引用。因此,每当我更新一个时,它们都会得到更新,而且我不必将任何东西传递到 HTML 层次结构中,这让事情变得简单了很多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多