如何更新聚合物元素绑定,它从DOM中删除并再次插入 [英] How to update polymer element bindings after it was removed from DOM and inserted again

查看:97
本文介绍了如何更新聚合物元素绑定,它从DOM中删除并再次插入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们具有容器聚合物元件和另一个假聚合物元件。容器聚合物元素具有插入其他聚合物的div块。



container_polymer.html

 < polymer-element name ='container-polymer'> 
< template>
< div id =container>
< / div>
< button on-click ={{first}}>显示第一个< / button>
< button on-click ={{firstPrepared}}>显示首先准备的< / button>
< button on-click ={{second}}>显示第二个< / button>
< / template>
< script type =application / dartsrc =container_polymer.dart>
< / script>
< / polymer-element>

有三个按钮用于插入假聚合物:


  1. 第一个按钮将第一个虚拟聚合物插入容器。

  2. 第二个按钮还插入第一个虚拟聚合物,并在此聚合物上调用
    prepareElement()

  3. 第三个按钮将第二个虚拟聚合物插入到容器中

container_polymer.dart

  import'package:polymer / polymer.dart'; 
import'dart:html';
import'dummy_polymer.dart';

@CustomTag('container-polymer')
类ContainerPolymer扩展PolymerElement {
PolymerElement firstPolymer,secondPolymer,currentPolymer;
元素容器;

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}}< / span>
< / div>
< input type =text/>
< div class =external>父样式块:背景应为白色< / div>
< / div>

< / template>

< script type =application / dartsrc =dummy_polymer.dart>
< / script>

< / polymer-element>

dummy_polymer.dart

  import'package:polymer / polymer.dart'; 
import'dart:html';

@CustomTag('dummy-polymer')
类DummyPolymer extends PolymerElement {
@observable String color =red;
@observable String title;
@observable num clicks = 0;
元素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. 单击第一个聚合物内部。

绑定到可见属性``````````````````不再工作了。但点击处理程序工作,你可以看到它的顶部区域的背景颜色改变。它是通过直接改变元素的 backgroundColor 属性来实现的:

  titleElement.style.backgroundColor = color; 

因此,我的问题是如何在现有聚合物插入后正确更新绑定机制DOM吗?



有一种方法可以使用show first prepared按钮。在插入容器之前,它在第一个元素上调用 prepareElement()。因此,请执行以下操作:


  1. 点击显示第一按钮。

  2. 在输入字段中输入内容

  3. 点击显示秒

  4. 点击显示第一准备。您可以看到输入元素为空,但计数器和背景颜色是最新的。 (如果您在dartium中运行此演示也会使用白色块阻止其背景颜色更改为父级,因为不应用父级样式)

  5. 单击第一个聚合物。现在它改变背景颜色和计数器。绑定工作正常,但我们在输入字段中丢失文本。

注意:在第一个元素插入show first prepared按钮,绑定工作良好,即使第一个元素插入与显示第一按钮。



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

解决方案

我没有尝试过,似乎合理。
我希望作者不介意处理他的答案从重新使用元素时分离的observable



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



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

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

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

  bool get preventDispose =>真正; 


Assume we have container polymer element and another dummy polymer element. Container polymer element has div block for inserting another polymers.

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>

There are three buttons for inserting dummy polymers:

  1. First button inserts first dummy polymer into container.
  2. Second button also inserts first dummy polymer, and calls prepareElement() on this polymer.
  3. Third button inserts second dummy polymer into container

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);
    }
  }

}

Dummy polymer has several observable properties in order to test binding works. When you click inside this polymer it changes background color of root div, background color of title div and increases counter. Also it has input for detecting if state of polymer element was changed and block with white background for testing usage of parent style.

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;
  }

}

Test page hosted here http://dart-style-binding-test.herokuapp.com/

So, to reproduce my issue do following:

  1. Click 'show first' button. Make sure clicking inside changes background color and increases counter.
  2. Type something into input field
  3. Click 'show second'
  4. Click 'show first'. Make sure first polymer has the same state as before: background color, counter and input field text.
  5. Click inside first polymer. Now it doesn't change background color and counter, but it changes background color of area at the top.

Binding to observable properties doesn't work anymore. But on-click handler works, you can see it when background color of top area changing. It's implemented by changing element's backgroundColor property directly:

titleElement.style.backgroundColor = color;

So, my question is: how to update binding mechanism properly after existing polymer was inserted into DOM again?

There is one way to do it dirty using 'show first prepared' button. It calls prepareElement() on first element before inserting into container. So, do following:

  1. Click 'show first' button. Make sure clicking inside changes background color and increases counter.
  2. Type something into input field
  3. Click 'show second'
  4. Click 'show first prepared'. You can see input element is empty, but counter and background color are up to date. (If you run this demo in dartium also block with white color will change its background color to parent's because parent style isn't applied)
  5. Click inside first polymer. Now it changes background color and counter. Bindings work properly, but we lose text inside input field.

Note: after first element had been inserted with 'show first prepared' button, bindings works well even after first element was inserted with 'show first' button.

Code here https://github.com/petalvlad/dart-style-binding-test

解决方案

I have not tried it myself but it seems reasonable. I hope the author doesn't mind coping his answer from Detached observables when re-using element.

Having looked into the polymer.js information bit I have found that there is a cancelUnbindAll function which must be called when the element is created or a preventDispose property set to true.

For anyone that might need to do the same, in the Dart implementation you must call cancelUnbindAll in the detached function after the super call, as follows:

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

Alternatively, you can simply override the preventDispose property in your custom element:

bool get preventDispose => true;

这篇关于如何更新聚合物元素绑定,它从DOM中删除并再次插入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆