If a dom-if with restamp="true" (which should delete its children while false) is used to guard elements from receiving data they can't or shouldn't be seeing, it works for the initial pass, but if the data is updated such that a dom-if that evaluated to true (and already created its child elements) now evaluates to false, the new data is still passed to its children just before they are deleted. This results in an error condition if one is depending on the dom-if as a guard. This jsbin demonstrates the issue - if the dom-if deleted its children as soon as it evaluated to false, before they received any update, neither Larry nor Moe should ever sneeze:
http://jsbin.com/kesexa/3/edit?html,console,output
<!DOCTYPE html>
<html>
<head>
<title>polymer</title>
<script src="https://rawgit.com/webcomponents/webcomponentsjs/master/webcomponents-lite.js"></script>
<base href="http://polygit.org/polymer/components/">
<link href="polymer/polymer.html" rel="import">
</head>
<body>
<dom-module id="x-test">
<template>
<template is="dom-if" if="{{isLily(flower)}}" restamp="true">
<x-larry flower="{{flower}}"></x-larry>
</template>
<template is="dom-if" if="{{isDaisy(flower)}}" restamp="true">
<x-moe flower="{{flower}}"></x-moe>
</template>
</template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-larry',
properties: {
flower: {
type: String,
observer: 'sniff'
}
},
sniff: function (flower) {
if (flower === 'daisy') {
console.log('Achoo!') // Larry is allergic to daisies
}
}
});
Polymer({
is: 'x-moe',
properties: {
flower: {
type: String,
observer: 'sniff'
}
},
sniff: function (flower) {
if (flower === 'lily') {
console.log('Achoo!') // Moe is allergic to lilies
}
}
});
Polymer({
is: 'x-test',
properties: {
flower: {
type: String,
value: 'daisy'
}
},
ready: function () {
var that = this
setTimeout(function () {
that.flower = 'lily'
}, 1000);
},
isLily: function (flower) {
return flower === 'lily'
},
isDaisy: function (flower) {
return flower === 'daisy'
}
});
});
</script>
<x-test></x-test>
</body>
</html>
I'm not sure if this can be considered a bug. It appears that un-stamping is placed at the end of the microtask queue which I feel is correct behaviour. For me, I wouldn't use dom-if to guard against data propagation if I can help it because I want to avoid creating race conditions, one like your example demonstrates.
If not, I'll have to manually handle race conditions like this:
<dom-module id="x-test">
<template>
<template is="dom-if" if="{{_attachLarry}}" restamp>
<x-larry flower="{{flower}}"></x-larry>
</template>
<template is="dom-if" if="{{_attachMoe}}" restamp>
<x-moe flower="{{flower}}"></x-moe>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'x-test',
properties: {
flower: { type: String, value: 'daisy' },
_attachMoe: { type: Boolean, value: true },
_attachLarry: { type: Boolean, value: false }
},
ready: function () {
console.log("working");
var that = this;
setTimeout(function () {
that._attachMoe = false;
that.async(function () {
that.flower = "lily";
that._attachLarry = true;
});
}, 1000);
}
});
</script>
http://jsbin.com/sadeceyeso/edit?html,console
(BTW, with restamp='true', you are actually passing in the string literal? Which in this case is "truthy" so it works.)
Isn't that race condition exactly the issue though? I understand the argument that dom-if should not be used for application logic and everything should be purely declarative, but the fact is there are uses for elements that incur side effects based on data (such as iron-ajax, which in this case would be sending out a useless request if it had auto on, before it is removed), and it doesn't seem intuitive that a dom-if that's about to remove an element should allow the data to propagate to it first. How else would you handle this use case, without manually attaching and unattaching elements in Javascript, or adding an extra layer of indirection via an async task like in your example? Both of those options seem janky.
For me, race conditions are one's own making. For instance, looking at the example in your first post, it is not immediately clear (nor is it intuitive) to me what the outcome you're expecting is. It is much better if you bind dom-if and your template elements to separate properties, so that it's clear how you're expecting this code to behave.
I wouldn't want the framework to handle all edge cases and incur the per instance costs.
I'm not sure I fully understand the use case you mentioned in your previous post - but once again, dom-if restamp is probably not intended to act as a "guard" against data propagation; there are better, clearer, and more performant ways to do this.
@jrajav, just have exact the same problem. Did you find a workaround?
@zerodevx, you said that "there are better, clearer, and more performant ways to do this."
What are the ways?
the following construction is not efficient because if you have allot of dom-ifs with restamp that will cause delay issues.
that._attachMoe = false;
that.async(function () {
that.flower = "lily";
that._attachLarry = true;
});
that code is similar to what I now do:
this._setParts([]);
this.async(() => {
this._setParts(parts);
});
where parts is an array to feed my dom-repeater which contains a list of dom-ifs inside it. It is veeery slow.
@Qvatra yes I think there are... How about taking your question to Stackoverflow? I (and others) will definitely try to help over there. Be sure to include your exact use-case, expected output, and a repro.
Let's keep Github issues for bugs and feature requests so as not to overload the project owners..
This issue is fairly old and there hasn't been much activity on it. Closing, but please re-open if it still occurs.
@azakus To clarify, the issue is still occurring as described. I guess it's a no-fix according to @zerodevx, though personally I feel that it's ridiculous to pass data changes down to elements that have been marked for unstamping (regardless of the whole race condition issue).
Reopening; to be addressed in Polymer 2.0.
Most helpful comment
@azakus To clarify, the issue is still occurring as described. I guess it's a no-fix according to @zerodevx, though personally I feel that it's ridiculous to pass data changes down to elements that have been marked for unstamping (regardless of the whole race condition issue).