Alternative to Polymer's dom-if that progressively compares two properties rather than just binding to a single boolean property

Published on webcomponents.org

<if-diff>

<if-diff> is an alternative to Polymer's dom-if element that allows comparison between two operands, as well as progressive enhancement. See if-else for another data-centric alternative.

if-diff allows the server to display content that should be initially displayed, then adjusts what is displayed as conditions in the browser change.

For example, suppose today is Monday. The server could generate the syntax below:

<!-- Polymer notation -->
<if-diff if lhs="[[dayOfWeek]]" equals rhs="Monday" tag="manicMonday" m="1"></if-diff>
...
<if-diff if lhs="[[dayOfWeek]]" equals rhs="Tuesday" tag="rubyTuesday"></if-diff>
...
<div data-manic-monday="1">
  <div>I wish it was Sunday</div>
</div>
<div data-ruby-tuesday="0">
  <template>
    <div>Who could hang a name on you</div>
  </template>
</div>
...

Generally, as will see, a data-* value of "1" should be interpreted as "matches", so assuming your css is consistent with that interpretation, the user will immediately see the desired text "I wish it was Sunday" before a single byte of JS is downloaded. Since the text for Tuesday is not yet applicable, embedding the content inside a template tag will allow the browser to ignore whatever is inside until needed. Only if the day changes would we need to display Tuesday. At that point, the template needs to be cloned (and discarded). So to fill in the details:

Rules:

  1. The "tag" attribute refers to a data-* attribute / dataset.* property. The case is based on the property name.
  2. Only downstream sibling elements are checked for the data-* attribute. This is to encourage unidirectional data flow, and keeping related things physically close.
  3. Speaking of which, the optional m attribute indicates the maximum number of elements that are getting affected by the if-diff tag. Placing the if-diff element right above the elements it affects, and specifying "m" accurately, will improve performance and help reduce greenhouse emissions.
  4. if-diff sets the data-* attribute to "1" when the condition is true, "-1" if not. It is up to the application's css styling to interpret how this should display.
  5. If if-diff encounters a data-* value of "0", this signifies there's exactly one template inside the DOM element, which needs cloning before changing to "1". It will leave the template untouched if the condition is not satisfied.
  6. The "if" attribute / property is actually an active participant in the logical evaluation. If that attribute / property is false, then the evaluation will be false no matter what. And as the demo below indicates, not_equals is also supported.
  <!-- Polyfills Needed for retro browsers -->
  <script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
  <!-- End Polyfills -->
  <script type="module" src="https://cdn.jsdelivr.net/npm/if-diff@0.0.5/if-diff.iife.js"></script>
  <script type="module" src="https://cdn.jsdelivr.net/npm/p-d.p-u@0.0.82/dist/p-d.iife.js"></script>
</div>
``` -->

Syntax

Commonality with p-d.p-u (a kind of dom-bind alternative)

Not only does if-diff share the same fetish for unidirectional data flow as p-d.p-u, they share a number of common modules. As a result, while if-diff weighs around 1.6kb and p-d weighs around 1.9kb, combine them together, and due to the magic of code reuse, the combined size is ~2.5kb minified and gzipped.

Go to sleep mode

It is quite common to have a user interface with multiple tabs, each tab depending on some common filters / inputs. if-diff can be used in this scenario, and to help improve performance, it can toggle the disabled attribute on the target elements. If the elements themselves know how to "go to sleep" when disabled, and then sync up with the new filters / inputs when disabled is removed, that could provide the most optimal performance.

Install the Polymer-CLI

First, make sure you have the Polymer CLI installed. Then run polymer serve to serve your element locally.

Installation

$ npm install if-diff 

Viewing Your Element

$ polymer serve
Open http://127.0.0.1:8081/

Running Tests

npm test

Install

Link to this version
ImportedReleased 26 November 2017MIT License
Framework Support
Polymer 2.0+
Browser Compatibility
Install with
npm install if-diff"@0.0.3"
Run the above npm command in your project folder. If you have any issues installing, please contact the author.
Release notes - Version 0.0.3

Dependencies

  • @bower_components/accessibility-developer-tools#GoogleChrome/accessibility-developer-tools#^2.10.0
  • @bower_components/async#caolan/async#^1.5.0
  • @bower_components/chai#chaijs/chai#^3.2.0
  • @bower_components/font-roboto#PolymerElements/font-roboto#^1
  • @bower_components/iron-demo-helpers#PolymerElements/iron-demo-helpers#^2.0.0
  • @bower_components/iron-flex-layout#polymerelements/iron-flex-layout#1 - 2
  • @bower_components/iron-location#PolymerElements/iron-location#1 - 2
  • @bower_components/lodash#lodash/lodash#^3.7.0
  • @bower_components/marked#chjj/marked#~0.3.6
  • @bower_components/marked-element#polymerelements/marked-element#1 - 2
  • @bower_components/mocha#mochajs/mocha#^3.1.2
  • @bower_components/polymer#Polymer/polymer#^2.0.0
  • @bower_components/prism#LeaVerou/prism#*
  • @bower_components/prism-element#PolymerElements/prism-element#1 - 2
  • @bower_components/shadycss#webcomponents/shadycss#^v1.0.0
  • @bower_components/sinon-chai#domenic/sinon-chai#^2.7.0
  • @bower_components/sinonjs#blittle/sinon.js#^1.14.1
  • @bower_components/stacky#PolymerLabs/stacky#^1.3.0
  • @bower_components/test-fixture#polymerelements/test-fixture#^3.0.0-rc.1
  • @bower_components/web-component-tester#Polymer/web-component-tester#^6.0.0
  • @bower_components/webcomponentsjs#webcomponents/webcomponentsjs#^1.0.0