问题
I've got an array that I'd like to display the top N elements from. This array is mutated and kept sorted by another component in my app.
I'm seeing a bug though such that if I display all of the array elements everything is fine. If I respond to my array changing by taking a copy of the array with .slice()
and putting that in another field and displaying that field filtered for the top N elements, then everything if fine. But if I just display the original array filtered through for the top N elements then the DOM is never updated to changes.
Here's a codepen reduction of the bug that shows off the problem: http://codepen.io/rictic/pen/ienJK?editors=101
Full code:
<script src="http://www.polymer-project.org/platform.js"></script><script src="http://www.polymer-project.org/components/web-animations-js/web-animations.js"></script><link rel="import" href="http://www.polymer-project.org/components/polymer/polymer.html">
<my-app></my-app>
<script>console.clear()</script>
<polymer-element name='my-app'>
<template>
<template if='{{results}}'>
r in results
<ul>
<template repeat='{{ r in results }}'>
<li>{{r.value}} - {{r.name}}</li>
</template>
</ul>
r in processedResults | first(5)
<ul>
<template repeat='{{ r in processedResults | first(5) }}'>
<li>{{r.value}} - {{r.name}}</li>
</template>
</ul>
r in results | first(5)
<ul>
<template repeat='{{ r in results | first(5) }}'>
<li>{{r.value}} - {{r.name}}</li>
</template>
</ul>
</template>
</template>
<script>
</script>
</polymer-element>
<script>
'use strict';
var names = ['Alice', 'Bob', 'Charline', 'Daryl', 'Elise', 'Franz', 'Geraldine', 'Happsburg', 'Irene', 'Jerome'];
Polymer('my-app', {
results: [{value: 10, name: 'root'}],
first: function(a, k) {
// A filterer to display the first k elements of an array.
if (!a) {
return a;
}
return a.slice(0, k);
},
domReady: function() {
// Populate the results array.
for (var i = 0; i < 10; i++) {
this.results.push({value: i, name: names[i]});
}
// Once a second, mutate and sort the array
setInterval(function() {
var randomChoice = Math.round(Math.random() * (this.results.length - 1));
this.results[randomChoice].value *= 2;
this.results.sort(function(a, b) {
if (a.value != b.value) {
return b.value - a.value;
}
return a.name.localeCompare(b.name);
});
}.bind(this), 1000);
},
resultsChanged: function() {
// Copy this.results into this.processedResults.
this.processedResults = this.results.slice();
}
});
</script>
回答1:
I believe you can setup results in the created
callback and everything will work. Here's an example CodePen. The created
callback is part of native custom elements and executes before ready
(which is added by Polymer to know when various features like data binding are setup and ready to rock). I'm still fuzzy as to why you have to do it this way so I've asked a member of the team to explain it to me and I'll leave another comment when I know more :)
edit
After speaking with one of the authors of polymer-expressions, it sounds like your original code should have worked but filters are not currently rerunning if the object model.results
points to is mutated. Instead they only rerun if the path to the object that model.results
points to changes. This seems like a shortcoming of filters and we're looking into changing the behavior so it works as you would expect.
来源:https://stackoverflow.com/questions/23706775/polymer-changes-not-always-flowing-through-a-filter