I was somewhat bummed to discover that Polymer's
<polymer-ajax>
does not support JSON HTTP request bodies—at least in the Dart version. But after a bit of digging, it seems that there is a <polymer-xhr>
that seems to support arbitrary body data (in both Dart and JavaScript). So tonight, I explore this element in the hopes that I can use it to get the higher-level <polymer-ajax>
to also support arbitrary HTTP payload content.So I import the
<polymer-xhr>
tag definition: <!-- Load component(s) -->
<link rel="import" href="/packages/change_history/change-sink.html">
<link rel="import" href="/packages/change_history/store-changes.html">
<link rel="import" href="/packages/polymer_elements/polymer_localstorage/polymer_localstorage.html">
<link rel="import" href="/packages/polymer_elements/polymer_ajax/polymer_ajax.html">
<link rel="import" href="/packages/polymer_elements/polymer_ajax/polymer_xhr.html">
Then, in the body of the page, I add <polymer-xhr>
as a child to the <store-changes>
element that I am trying to get working over Ajax: <store-changes>
<!-- <polymer-localstorage name="store-changes" value="{{value}}"></polymer-localstorage> -->
<!-- <polymer-ajax url="http://localhost:31337/widgets/change-history" -->
<!-- handleAs="json"> -->
<!-- </polymer-ajax> -->
<polymer-xhr></polymer-xhr>
<!-- changes will originate from elements here ... -->
</store-changes>
With that, I am ready to make my changes to the class that is backing <store-changes>
. Instead of setting <polymer-ajax>
parameters and then invoking go()
, I just need to invoke request()
on <polymer-xhr>
with the necessary options. And, since this is a low-level call, there are a lot of options:@CustomTag('store-changes') class StoreChangesElement extends PolymerElement { StoreChangesElement.created(): super.created(); // ... get store => children. firstWhere((el) => el.localName == 'polymer-xhr'); storeChange(e) { // Convert the change event into an "update" record, then... store. request({ 'url': 'http://localhost:31337/widgets', 'method': 'POST', 'callback': (__res, __xhr){}, 'headers': {}, 'body': JSON.encode(update) }); // ... } }And that turns out to just work™. When I make changes to the the contained
<div contenteditable>
element, change events propagate to the custom Polymer, <store-changes>
which sends JSON encoded HTTP requests to the server:{"id":"change-history","current":"\n <h1> Change #1</h1> \n ","history":["\n <h1> Change #1</h1> \n "]}And the server is happy to respond with:
HTTP/1.1 201 Created server: Dart/1.0 (dart:io) access-control-allow-origin: * access-control-allow-headers: Content-Type, X-Requested-With access-control-allow-methods: GET,DELETE,PUT content-type: application/json; charset=utf-8 transfer-encoding: chunked content-encoding: gzipYay!
So the question then becomes, can I get
<polymer-ajax>
to support arbitrary HTTP bodies? To answer that question, I fork the polymer elements (Dart), and clone it locally. Then I point my application to this local copy of my fork by making the necessary change in pubspec.yaml
:name: change_history dependencies: polymer: any polymer_elements: path: /home/chris/repos/polymer_elementsA quick
pub get
In my new copy of polymer_elements, I add an xhrArgs
public attribute to <polymer-ajax>
(mimicking the property of the same name in the JavaScript version of the element):@CustomTag('polymer-ajax') class PolymerAjax extends PolymerElement { // ... @published Map xhrArgs; // ... go() { var args = xhrArgs != null ? xhrArgs : {}; // ... } }If present, this Map will serve as the default values for the arguments sent to the underlying
<polymer-xhr>
. I already know that, if there is body
key in that xhrArgs
then I can POST whatever I want via <polymer-xhr>
, so I supply just that in my <store-changes>
element:@CustomTag('store-changes') class StoreChangesElement extends PolymerElement { StoreChangesElement.created(): super.created(); // ... get store => children. firstWhere((el) => el.localName == 'polymer-ajax'); storeChange(e) { // Convert the change event into an "update" record, then... store ..method = 'POST' ..xhrArgs = {'body': JSON.encode(update)} ..go(); // .. } }After switching back to the higher level
<polymer-ajax>
in my web page:<store-changes> <!-- <polymer-localstorage name="store-changes" value="{{value}}"></polymer-localstorage> --> <polymer-ajax url="http://localhost:31337/widgets/change-history" handleAs="json"> </polymer-ajax> <!-- <polymer-xhr></polymer-xhr> --> <!-- changes will originate from elements here ... --> </store-changes>It works! When I make changes in the wrapped
<div contenteditable>
, my <store-changes>
Polymer sees the change and saves a history record over XHR. Only this time, it does it with <polymer-ajax>
and mercifully fewer arguments. There are a few other benefits to be reaped in
<polymer-ajax>
. I will likely try to reap them tomorrow.Day #955
No comments:
Post a Comment