如何在从DOM中删除并再次插入后更新聚合物元素绑定

时间:2013-12-27 17:49:24

标签: dart dart-polymer

假设我们有容器聚合物元件和另一个虚设聚合物元件。容器聚合物元件具有用于插入另一种聚合物的div块。

container_polymer.html

<polymer-element name='container-polymer'>
  <template>
    <div id="container">
    </div>
    <button on-click="{{first}}">show first</button>
    <button on-click="{{firstPrepared}}">show first prepared</button>
    <button on-click="{{second}}">show second</button>
  </template>
  <script type="application/dart" src="container_polymer.dart">
  </script>
</polymer-element>

有三个用于插入虚拟聚合物的按钮:

  1. 第一个按钮将第一个虚设聚合物插入容器中。
  2. 第二个按钮还插入第一个虚拟聚合物,然后调用 prepareElement()对这种聚合物。
  3. 第三个按钮将第二个虚设聚合物插入容器
  4. container_polymer.dart

    import 'package:polymer/polymer.dart';
    import 'dart:html';
    import 'dummy_polymer.dart';
    
    @CustomTag('container-polymer')
    class ContainerPolymer extends PolymerElement {
      PolymerElement firstPolymer, secondPolymer, currentPolymer;
      Element container;
    
      ContainerPolymer.created() : super.created();
    
      void enteredView() {
        super.enteredView();
        container = $['container'];
      }
    
      void first(Event e, var detail, Node target) {
        showFirst(false);
      }
    
      void firstPrepared(Event e, var detail, Node target) {
        showFirst(true);
      }
    
      void showFirst(bool prepare) {
        if (firstPolymer == null) {
          DummyPolymer dummyPolymer = new Element.tag("dummy-polymer");
          dummyPolymer.title = "first";
          firstPolymer = dummyPolymer;
        }
    
        if (currentPolymer != firstPolymer) {
          if (secondPolymer != null) {
            secondPolymer.remove();
          }
    
          if (prepare) {
            firstPolymer.prepareElement();  
          }
          currentPolymer = firstPolymer;
          container.children.add(firstPolymer); 
        }
      }
    
      void second(Event e, var detail, Node target){
        if (currentPolymer != secondPolymer) {
          DummyPolymer dummyPolymer = new Element.tag("dummy-polymer");
          dummyPolymer.title = "second";
          secondPolymer = dummyPolymer;
          if (firstPolymer != null) {
            firstPolymer.remove();
          }
    
          currentPolymer = secondPolymer;
          container.children.add(secondPolymer);
        }
      }
    
    }
    

    虚拟聚合物具有多种可观察的性质,以测试结合作用。当您在此聚合物内部单击时,它会更改根div的背景颜色,标题div的背景颜色并增加计数器。此外,它还有用于检测聚合物元素状态是否发生变化的输入和用白色背景阻挡以测试父母风格的用法。

    dummy_polymer.html

    <polymer-element name='dummy-polymer'>
      <template>
        <div style="width: 500px; height: 300px; background-color: {{color}}" on-click="{{changeColor}}">
          <div id="title">
            <h1>{{title}}</h1>
            <span>Clicks: {{clicks}}</span>
          </div>
          <input type="text" />
          <div class="external">Parent style block: background should be white</div>
        </div>
    
      </template>
    
      <script type="application/dart" src="dummy_polymer.dart">
      </script>
    
    </polymer-element>
    

    dummy_polymer.dart

    import 'package:polymer/polymer.dart';
    import 'dart:html';
    
    @CustomTag('dummy-polymer')
    class DummyPolymer extends PolymerElement {
      @observable String color = "red";
      @observable String title;
      @observable num clicks = 0;
      Element titleElement;
    
      DummyPolymer.created() : super.created() {
        var root = getShadowRoot('dummy-polymer');
        root.applyAuthorStyles = true;
      }
    
      void enteredView() {
        super.enteredView();
        titleElement = $['title'];
      }
    
      void changeColor(Event e, var detail, Node target){
        clicks++;
    
        if (color == "red") {
          color = "green";
        } 
        else if (color == "green") {
          color = "blue";
        }
        else {
          color = "red";
        }
        titleElement.style.backgroundColor = color;
      }
    
    }
    

    此处托管的测试页http://dart-style-binding-test.herokuapp.com/

    因此,要重现我的问题,请执行以下操作:

    1. 点击“先显示”按钮。确保单击内部更改背景颜色并增加计数器。
    2. 在输入字段中输入内容
    3. 点击“显示第二个”
    4. 点击“先显示”。确保第一个聚合物具有与以前相同的状态:背景颜色,计数器和输入字段文本。
    5. 点击第一聚合物内部。现在它不会改变背景颜色和计数器,但会改变顶部区域的背景颜色。
    6. 绑定到可观察属性不再起作用。但on-click处理程序有效,当顶部区域的背景颜色发生变化时,您可以看到它。它是通过直接更改元素的backgroundColor属性来实现的:

      titleElement.style.backgroundColor = color;
      

      所以,我的问题是:如何在现有聚合物再次插入DOM后如何正确更新绑定机制?

      有一种方法可以使用“show first prepared”按钮进行弄脏。在插入容器之前,它会在第一个元素上调用prepareElement()。所以,请做以下事情:

      1. 点击“先显示”按钮。确保单击内部更改背景颜色并增加计数器。
      2. 在输入字段中输入内容
      3. 点击“显示第二个”
      4. 点击“先显示准备”。您可以看到输入元素为空,但计数器和背景颜色是最新的。 (如果你在dartium中运行这个演示,那么使用白色的块会将其背景颜色更改为父级,因为不应用父级样式)
      5. 点击第一聚合物内部。现在它改变了背景颜色和计数器。绑定正常工作,但我们丢失输入字段内的文本。
      6. 注意:在使用“show first prepared”按钮插入第一个元素后,即使在使用“show first”按钮插入第一个元素之后,绑定也能正常工作。

        此处代码https://github.com/petalvlad/dart-style-binding-test

1 个答案:

答案 0 :(得分:4)

我自己没试过,但看起来很合理。 我希望作者不介意从Detached observables when re-using element.

中回答他的答案

查看了polymer.js信息位后,我发现有一个cancelUnbindAll函数,必须在创建元素或将preventDispose属性设置为true时调用。

对于可能需要执行相同操作的任何人,在Dart实现中,您必须在超级调用之后在分离函数中调用cancelUnbindAll,如下所示:

void detached()
{
    super.detached();
    this.cancelUnbindAll(preventCascade: true);
}

或者,您可以简单地覆盖自定义元素中的preventDispose属性:

bool get preventDispose => true;