按名称获取 属性 时不会反映更改
Changes do not get reflected when getting property by name
我有以下聚合物元素
import 'package:polymer/polymer.dart';
import 'dart:mirrors';
import 'dart:async';
import 'dart:math';
class Column extends Observable{
@observable String name;
@observable String displayName;
Column(this.name,this.displayName);
}
class Model extends Observable{
@observable String fname;
@observable String lname;
@observable int age;
Model(this.fname,this.lname,this.age);
operator [](String fieldName){
var im = reflect(this);
return im.getField(new Symbol(fieldName)).reflectee;
}
}
@CustomTag('main-app')
class MainApp extends PolymerElement {
@observable ObservableList<Object> data;
@observable ObservableList<Column> columns;
MainApp.created() : super.created(){
columns = new ObservableList.from([new Column("fname","First Name"), new Column("lname","Last name"),new Column("age","Age")]);
emulateDataChanging();
}
emulateDataChanging(){
var r = new Random();
var names = ["aaa","bbb","ccc","ddd","eee"];
//add some models to data first
data = new ObservableList();
for(int i=0;i<5;i++){
data.add(new Model(names[r.nextInt(4)],names[r.nextInt(4)],r.nextInt(99)));
}
//modify couple random props every second
new Timer.periodic(new Duration(seconds:1),(t){
Model m;
m=(data[r.nextInt(data.length-1)] as Model);
m.lname=names[r.nextInt(4)];
m.deliverChanges();
m=(data[r.nextInt(data.length-1)] as Model);
m.fname=names[r.nextInt(4)];
m.deliverChanges();
m=(data[r.nextInt(data.length-1)] as Model);
m.age =r.nextInt(4);
m.deliverChanges();
//add a random model
//data.add(new Model(names[r.nextInt(4)],names[r.nextInt(4)],r.nextInt(99)));
});
}
}
和 html 元素
<link rel="import" href="../../packages/polymer/polymer.html">
<polymer-element name="main-app">
<template>
<style>
:host {
display: block;
}
</style>
<!--A table -->
<table id="table" class="table table-hover table-mc-light-blue">
<thead>
<tr>
<th template repeat='{{column in columns}}'>
{{column.displayName}}
</th>
</tr>
</thead>
<tbody>
<tr template repeat='{{row in data}}'>
<td template repeat='{{ column in columns}}' data-title="{{column.displayName}}">
{{row[column.name]}}
</td>
</tr>
</tbody>
</table>
<!--A repeat by binding to the Model properties directly -->
<template repeat="{{row in data}}">
<p>{{row.fname}} {{row.lname}} {{row.age}}</p>
</template>
</template>
<script type="application/dart" src="main_app.dart"></script>
</polymer-element>
我添加了整个代码,因此可以在几秒钟内复制和过去 运行,正如您在模板中看到的那样,我有一个 table 并且使用嵌套重复添加行,并且属性 模型通过列的名称访问,并在属性直接访问的地方重复一次。
但是在更改模型 属性 时出现问题,更改不会反映到 table 但它们会反映在另一个重复中,我想如果你 运行 它你会更好地理解。
我认为你可以在这里尝试两件事:
- 使用
Observable.dirtyCheck()
- 在聚合物元素而不是模型上调用
deliverChanges()
// 编辑
我认为你的问题是你每次都创建一个新的 ObservableList() 。尝试只创建一次 ObservableList,例如在您的 created() 构造函数中,然后更改列表的元素而不是对象。
// 编辑 2 - 可能的解决方案
你好。现在我已经正确理解了您的问题,我为您提供了解决方案。我也有同样的问题。我通过围绕模型编写包装器解决了这个问题:
HTML
<link rel="import" href="../../packages/polymer/polymer.html">
<polymer-element name="model-wrapper" attributes="model property">
<template>
{{value}}
</template>
<script type="application/dart" src="model_wrapper.dart"></script>
</polymer-element>
飞镖
import 'package:polymer/polymer.dart';
import 'dart:mirrors';
@CustomTag('model-wrapper')
class ModelWrapper extends PolymerElement {
@published var model;
@published String property;
@ComputedProperty('model[property]')
get value => model[property] == null ? "" : model[property].toString();
@observable
set value(v) => model[property] = v;
ModelWrapper.created() : super.created(){
}
void ready() {
model.changes.listen((List<ChangeRecord> changes) {
changes.forEach((record) {
if(record is PropertyChangeRecord) {
if(MirrorSystem.getName(record.name) == property) {
notifyPropertyChange(#value, record.oldValue, record.newValue);
}
}
});
});
}
}
我的原始包装可以在这里找到:
https://github.com/roberthartung/webui/blob/master/lib/util/webui-property-wrapper.dart
https://github.com/roberthartung/webui/blob/master/lib/util/webui-property-wrapper.html
问题在于您如何访问模型中的数据
{{row[column.name]}}
[]
运算符访问不可观察,并且 column.name
不会更改,因此永远不会重新计算表达式。
仅仅因为字段是 @observable
也不会使用 []
运算符访问 @observable
进行引用。
我的尝试——引入一个dummy
字段:
class Model extends Observable {
@observable String fname;
@observable String lname;
@observable int age;
@observable String get dummy => '$fname$lname$age';
getValue(String colName, String dummy) {
return this[colName];
}
Model(this.fname, this.lname, this.age) {
changes.listen((List<ChangeRecord> c) {
c.forEach((PropertyChangeRecord r) {
if(r.name != #dummy) {
notifyPropertyChange(#dummy, null, dummy);
}
});
});
}
operator [](String fieldName){
var im = reflect(this);
return im.getField(new Symbol(fieldName)).reflectee;
}
}
并像
一样绑定字段值
{{row.getValue(column.name, row.dummy)}}
通过这种方式,Polymer 绑定表达式包含一个更改的字段 row.dummy
,这使得 Polymer 重新计算表达式。
我有以下聚合物元素
import 'package:polymer/polymer.dart';
import 'dart:mirrors';
import 'dart:async';
import 'dart:math';
class Column extends Observable{
@observable String name;
@observable String displayName;
Column(this.name,this.displayName);
}
class Model extends Observable{
@observable String fname;
@observable String lname;
@observable int age;
Model(this.fname,this.lname,this.age);
operator [](String fieldName){
var im = reflect(this);
return im.getField(new Symbol(fieldName)).reflectee;
}
}
@CustomTag('main-app')
class MainApp extends PolymerElement {
@observable ObservableList<Object> data;
@observable ObservableList<Column> columns;
MainApp.created() : super.created(){
columns = new ObservableList.from([new Column("fname","First Name"), new Column("lname","Last name"),new Column("age","Age")]);
emulateDataChanging();
}
emulateDataChanging(){
var r = new Random();
var names = ["aaa","bbb","ccc","ddd","eee"];
//add some models to data first
data = new ObservableList();
for(int i=0;i<5;i++){
data.add(new Model(names[r.nextInt(4)],names[r.nextInt(4)],r.nextInt(99)));
}
//modify couple random props every second
new Timer.periodic(new Duration(seconds:1),(t){
Model m;
m=(data[r.nextInt(data.length-1)] as Model);
m.lname=names[r.nextInt(4)];
m.deliverChanges();
m=(data[r.nextInt(data.length-1)] as Model);
m.fname=names[r.nextInt(4)];
m.deliverChanges();
m=(data[r.nextInt(data.length-1)] as Model);
m.age =r.nextInt(4);
m.deliverChanges();
//add a random model
//data.add(new Model(names[r.nextInt(4)],names[r.nextInt(4)],r.nextInt(99)));
});
}
}
和 html 元素
<link rel="import" href="../../packages/polymer/polymer.html">
<polymer-element name="main-app">
<template>
<style>
:host {
display: block;
}
</style>
<!--A table -->
<table id="table" class="table table-hover table-mc-light-blue">
<thead>
<tr>
<th template repeat='{{column in columns}}'>
{{column.displayName}}
</th>
</tr>
</thead>
<tbody>
<tr template repeat='{{row in data}}'>
<td template repeat='{{ column in columns}}' data-title="{{column.displayName}}">
{{row[column.name]}}
</td>
</tr>
</tbody>
</table>
<!--A repeat by binding to the Model properties directly -->
<template repeat="{{row in data}}">
<p>{{row.fname}} {{row.lname}} {{row.age}}</p>
</template>
</template>
<script type="application/dart" src="main_app.dart"></script>
</polymer-element>
我添加了整个代码,因此可以在几秒钟内复制和过去 运行,正如您在模板中看到的那样,我有一个 table 并且使用嵌套重复添加行,并且属性 模型通过列的名称访问,并在属性直接访问的地方重复一次。
但是在更改模型 属性 时出现问题,更改不会反映到 table 但它们会反映在另一个重复中,我想如果你 运行 它你会更好地理解。
我认为你可以在这里尝试两件事:
- 使用
Observable.dirtyCheck()
- 在聚合物元素而不是模型上调用
deliverChanges()
// 编辑
我认为你的问题是你每次都创建一个新的 ObservableList() 。尝试只创建一次 ObservableList,例如在您的 created() 构造函数中,然后更改列表的元素而不是对象。
// 编辑 2 - 可能的解决方案
你好。现在我已经正确理解了您的问题,我为您提供了解决方案。我也有同样的问题。我通过围绕模型编写包装器解决了这个问题:
HTML
<link rel="import" href="../../packages/polymer/polymer.html">
<polymer-element name="model-wrapper" attributes="model property">
<template>
{{value}}
</template>
<script type="application/dart" src="model_wrapper.dart"></script>
</polymer-element>
飞镖
import 'package:polymer/polymer.dart';
import 'dart:mirrors';
@CustomTag('model-wrapper')
class ModelWrapper extends PolymerElement {
@published var model;
@published String property;
@ComputedProperty('model[property]')
get value => model[property] == null ? "" : model[property].toString();
@observable
set value(v) => model[property] = v;
ModelWrapper.created() : super.created(){
}
void ready() {
model.changes.listen((List<ChangeRecord> changes) {
changes.forEach((record) {
if(record is PropertyChangeRecord) {
if(MirrorSystem.getName(record.name) == property) {
notifyPropertyChange(#value, record.oldValue, record.newValue);
}
}
});
});
}
}
我的原始包装可以在这里找到:
https://github.com/roberthartung/webui/blob/master/lib/util/webui-property-wrapper.dart https://github.com/roberthartung/webui/blob/master/lib/util/webui-property-wrapper.html
问题在于您如何访问模型中的数据
{{row[column.name]}}
[]
运算符访问不可观察,并且 column.name
不会更改,因此永远不会重新计算表达式。
仅仅因为字段是 @observable
也不会使用 []
运算符访问 @observable
进行引用。
我的尝试——引入一个dummy
字段:
class Model extends Observable {
@observable String fname;
@observable String lname;
@observable int age;
@observable String get dummy => '$fname$lname$age';
getValue(String colName, String dummy) {
return this[colName];
}
Model(this.fname, this.lname, this.age) {
changes.listen((List<ChangeRecord> c) {
c.forEach((PropertyChangeRecord r) {
if(r.name != #dummy) {
notifyPropertyChange(#dummy, null, dummy);
}
});
});
}
operator [](String fieldName){
var im = reflect(this);
return im.getField(new Symbol(fieldName)).reflectee;
}
}
并像
一样绑定字段值{{row.getValue(column.name, row.dummy)}}
通过这种方式,Polymer 绑定表达式包含一个更改的字段 row.dummy
,这使得 Polymer 重新计算表达式。