2
votes

I'm have a polymer element whose model may be one of two classes (technically one of two subclasses of a common superclass). I'm looking for my element template to be slightly different depending on which of the two classes the model is. Something like this:

<polymer-element name="my-element">
<template>
    {{model.runtimeType}} <!-- sanity check -->
    {{model.commonProperty}}
    <template if="{{model is Foo}}">
      {{model.fooSpecificProperty}}
    </template>
    <template if="{{model is Bar}}">
      {{model.barSpecificProperty}}
    </template>
</template>
<script type="application/dart" src="my-element.dart"></script>
</polymer-element>

What I'm finding is that both of the if templates are displaying, as though both model is Foo and model is Bar are returning true. For each type of model, I see that the {{model.runtimeType}} is printing Foo and Bar as appropriate.

I've also tried changing the if conditions to other things such as {{model.runtimeType.toString() == 'Foo'}}, but I can't seem to find the right condition to properly sort out my model types.

In a Dart Polymer element, what is the correct way to detect and filter based on the type of an object?

EDIT: Also noticing that both {{model is Foo}} and {{model is! Foo}} seem to return true as a conditional when used in Polymer, but work as expected inside a .dart file.

3

3 Answers

3
votes

It's important not to use toString() here, since it will not work when using dart2js with minification. Similar to the other suggestions, here are two ideas that should work even with obfuscation/minification.

<polymer-element name="x-tag">
<template>
    <!-- idea #1 -->
    <template if="{{model.runtimeType == fooType}}"> ...

    <!-- idea #2 -->
    <template if="{{isFoo}}"> ...

and

@CustomTag(x-tag)
class XTag extends PolymerElement {
  // idea #1
  Type get fooType => Foo;

  // idea #2
  @observable bool isFoo;
  @ObserveProperty('model')
  updateIsFoo() { isFoo = model is Foo; }

}
1
votes

The problem is that Foo/Bar (of type Type is not recognized/available in Polymer expressions therefore is or is! cannot work.

model.runtimeType.toString() == 'Bar'

should work though. I'll investigate.

What I got working is:

on my-element

String asString(value) {
  return value.runtimeType.toString();
} 
  <template if="{{asString(model) == 'Foo')}}">
    {{model.fooSpecificProperty}}
  </template>
  <template if="{{asString(model) == 'Bar'}}">
    {{model.barSpecificProperty}}
  </template>

also working

class Base {
  String commonProperty = 'common';

  @override
  String toString() => runtimeType.toString();
}
  <template if="{{model.toString() == 'Foo')}}">
    <div style="border: solid 1px red;">{{model.fooSpecificProperty}}</div>
  </template>
  <template if="{{model.toString() == 'Bar'}}">
    <div style="border: solid 1px green;">{{model.barSpecificProperty}}</div>
  </template>
0
votes

In light of the Polymer bug https://code.google.com/p/dart/issues/detail?id=20980, it seems that right now the best way to do this is a workaround. The cleanest workaround I've been able to find is

my-element.html

<polymer-element name="my-element">
<template>
    {{model.runtimeType}} <!-- sanity check -->
    {{model.commonProperty}}
    <template if="{{model.type == 'Foo'}}">
      {{model.fooSpecificProperty}}
    </template>
    <template if="{{model.type == 'Bar'}}">
      {{model.barSpecificProperty}}
    </template>
</template>
<script type="application/dart" src="my-element.dart"></script>
</polymer-element>

model_superclass.dart

abstract class ModelSuperclass {
  var commonProperty;
  String get type => this.runtimeType.toString();
}

In the future, once the bug is resolved, the best way to accomplish this will be to use

<template if="{{model.runtimeType.toString() == 'Foo'}}">