Skip to content
This repository has been archived by the owner on Dec 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2 from PolymerElements/form-fixes
Browse files Browse the repository at this point in the history
fix form serializing and demo
  • Loading branch information
notwaldorf committed May 25, 2015
2 parents 9d6f8bc + d1c6eec commit 0aa7bf9
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 70 deletions.
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"web-component-tester": "*",
"webcomponentsjs": "^0.7.0",
"paper-input": "PolymerElements/paper-input#^0.9.0",
"paper-button": "PolymerElements/paper-button#^0.9.0"
"paper-button": "PolymerElements/paper-button#^0.9.0",
"paper-styles": "PolymerElements/paper-styles#^0.9.0"
}
}
143 changes: 86 additions & 57 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,81 +10,110 @@
-->
<html>
<head>
<title>iron-form demo</title>

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">

<title>iron-form demo</title>
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">

<script src="../../webcomponentsjs/webcomponents-lite.js"></script>

<link rel="import" href="../../paper-input/paper-input.html">
<link rel="import" href="../../paper-button/paper-button.html">
<link rel="import" href="../../iron-flex-layout/iron-flex-layout.html">
<link rel="stylesheet" href="../../paper-styles/demo.css">
<link rel="import" href="../../paper-styles/paper-styles.html">
<link rel="import" href="../../paper-styles/demo-pages.html">
<link rel="import" href="../iron-form.html">

</head>
<style>
form {
width: 300px;
}

.divider {
margin-left: 20px;
margin-right: 20px;
border: 1px solid #ccc;
.wide {
width: 474px;
}
</style>
<body>

<div class="horizontal layout">
<form is="iron-form" id="formGet" method="get" action="/">
<h1>method="get"</h1>
<paper-input name="name" label="Name" required></paper-input>
<paper-input name="animal" label="Favourite animal" required></paper-input>
<br>
<input type="checkbox" name="donuts" value="donuts" checked="checked"> I like donuts<br>
<br><br>
<paper-button raised
onclick="clickHandler(event)">Submit</paper-button>
<button type="submit">Native Submit</button>
</form>

<div class="divider"></div>

<form is="iron-form" id="formPost" method="post" action="/">
<h1>method="post"</h1>
<paper-input name="name" label="Name" required></paper-input>
<paper-input name="animal" label="Favourite animal" required></paper-input>
<br><br>
<paper-button raised
onclick="clickHandler(event)">Submit</paper-button>
<button type="submit">Native Submit</button>
</form>

<div class="horizontal center-center layout">
<div>
<h4>method="get"</h4>
<div class="horizontal-section">
<form is="iron-form" id="formGet" method="get" action="/">
<paper-input name="name" label="Name" required></paper-input>
<paper-input name="animal" label="Favourite animal" required></paper-input>
<br>

<input type="checkbox" name="food" value="donuts" checked> I like donuts<br>
<input type="checkbox" name="food" value="pizza"> I like pizza<br>
<br>

<input type="radio" name="color" value="red" checked>Red<br>
<input type="radio" name="color" value="blue" checked>Blue<br>
<input type="radio" name="color" value="green">Green<br>

<br><br>

<paper-button raised
onclick="clickHandler(event)">Submit</paper-button>
<button type="submit">Native Submit</button>
</form>
</div>
</div>

<div>
<h4>method="post"</h4>
<div class="horizontal-section">
<form is="iron-form" id="formPost" method="post" action="/">
<paper-input name="name" label="Name" required></paper-input>
<paper-input name="name" label="Duplicate name" required></paper-input>
<paper-input name="animal" label="Favourite animal" required></paper-input>
<br>

<label>Cars</label>
<select name="cars">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="fiat">Fiat</option>
<option value="audi">Audi</option>
</select>

<br><br>
<label>Browsers</label>
<input list="browsers" name="browsers">
<datalist id="browsers">
<option value="Internet Explorer">
<option value="Firefox">
<option value="Chrome">
<option value="Opera">
<option value="Safari">
</datalist>

<br><br><br>
<paper-button raised
onclick="clickHandler(event)">Submit</paper-button>
<button type="submit">Native Submit</button>
</form>
</div>
</div>
</div>

<br><br>

<div id="output"></div>
<div class="layout vertical center-center">
<div>
<h4>Submitted form data</h4>
<div class="horizontal-section wide">
<div id="output"></div>
</div>
</div>
</div>

<script>
document.getElementById('formGet').addEventListener('iron-form-submit',
function(event){
var output = document.getElementById('output');
output.innerHTML = 'Form data: ' + JSON.stringify(event.detail);
});

document.getElementById('formPost').addEventListener('iron-form-submit',
function(event){
var output = document.getElementById('output');
output.innerHTML = 'Form data: ' + JSON.stringify(event.detail);
});

function clickHandler(e) {
Polymer.dom(e).localTarget.parentElement.submit();
document.getElementById('formGet').addEventListener('iron-form-submit', display);
document.getElementById('formPost').addEventListener('iron-form-submit', display);

function display(event) {
var output = document.getElementById('output');
output.innerHTML = JSON.stringify(event.detail);
}

function clickHandler(event) {
Polymer.dom(event).localTarget.parentElement.submit();
}
</script>
</body>
Expand Down
74 changes: 63 additions & 11 deletions iron-form.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,35 @@
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../iron-ajax/iron-ajax.html">

<!--
An `iron-form` is a form element that can validate and submit any custom
elements that have an 'iron-form-behavior`, as well as any native HTML elements.
-->

<script>
/*
``<iron-form>` is an HTML `<form>` element that can validate and submit any custom
elements that implement `Polymer.IronFormElementBehavior`, as well as any
native HTML elements.
It supports both `get` and `post` methods, and uses an `iron-ajax` element to
submit the form data to the action URL.
Example:
<form is="iron-form" id="form" method="post" action="/form/handler">
<paper-input name="name" label="name"></paper-input>
<input name="address">
...
</form>
By default, a native `<button>` element will submit this form. However, if you
want to submit it from a custom element's click handler, you need to explicitly
call the form's `submit` method.
Example:
<paper-button raised onclick="submitForm()">Submit</paper-button>
function submitForm() {
document.getElementById('form').submit();
}
*/

Polymer({

Expand Down Expand Up @@ -88,25 +111,45 @@

/**
* Returns a json object containing name/value pairs for all the registered
* custom components and native elements of the form.
* custom components and native elements of the form. If there are elements
* with duplicate names, then their values will get aggregated into an
* array of values.
*/
serialize: function() {
var json = {};

function addSerializedElement(el) {
// If the name doesn't exist, add it. Otherwise, serialize it to
// an array,
if (!json[el.name]) {
json[el.name] = el.value;
} else {
if (!Array.isArray(json[el.name])) {
json[el.name] = [json[el.name]];
}
json[el.name].push(el.value);
}
}

// Go through all of the registered custom components.
for (var el, i = 0; el = this._customElements[i], i < this._customElements.length; i++) {
if (el.name) {
json[el.name] = el.value;
addSerializedElement(el);
}
}

// Also go through the form's native elements.
for (var el, i = 0; el = this.elements[i], i < this.elements.length; i++) {
// Don't re-add custom elements that extend native elements (like an
// `<input is="fancy-input">`), since they will also show up in this list.
if (el.name && !json[el.name]) {
json[el.name] = el.value;
// Checkboxes and radio buttons should only use their value if they're checked.
// Also, custom elements that extend native elements (like an
// `<input is="fancy-input">`) will appear in both lists. Since they
// were already added as a custom element, they don't need
// to be re-added.
if (!el.name || !this._useValue(el) ||
(el.hasAttribute('is') && json[el.name])) {
continue;
}
addSerializedElement(el);
}

return json;
Expand All @@ -130,6 +173,15 @@
valid = el.validate() && valid;
}
return valid;
},

_useValue: function(el) {
// Checkboxes and radio buttons should only use their value if they're checked.
if (el.type !== 'checkbox' && el.type !== 'radio') {
return true;
} else {
return el.checked;
}
}

});
Expand Down
58 changes: 57 additions & 1 deletion test/basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,29 @@
</template>
</test-fixture>

<test-fixture id="Dupes">
<template>
<form is="iron-form">
<input name="foo" value="bar">
<input name="foo" value="barbar">
<simple-element name="zig" value="zig"></simple-element>
<simple-element name="zig" value="zag"></simple-element>
<simple-element name="zig" value="zug"></simple-element>
</form>
</template>
</test-fixture>

<test-fixture id="CheckedStates">
<template>
<form is="iron-form">
<input type="checkbox" name="foo" value="bar1" checked>
<input type="checkbox" name="foo" value="bar2">
<input type="checkbox" name="foo" value="bar3" checked>
<input type="checkbox" name="foo" value="bar4">
</form>
</template>
</test-fixture>

<test-fixture id="FormGet">
<template>
<form is="iron-form" action="/responds_with_json" method="get">
Expand Down Expand Up @@ -62,6 +85,37 @@
assert.equal(json['zig'], 'zag');
assert.equal(json['foo'], 'bar');
});

test('serializes elements with duplicate names', function() {
f = fixture('Dupes');

assert.equal(f._customElements.length, 3);
assert.equal(f.elements.length, 2);

var json = f.serialize();
assert.equal(Object.keys(json).length, 2);
assert.equal(json['foo'].length, 2);
assert.equal(json['foo'][0], 'bar');
assert.equal(json['foo'][1], 'barbar');
assert.equal(json['zig'].length, 3);
assert.equal(json['zig'][0], 'zig');
assert.equal(json['zig'][1], 'zag');
assert.equal(json['zig'][2], 'zug');
});

test('serializes elements with checked states', function() {
f = fixture('CheckedStates');

assert.equal(f._customElements.length, 0);
assert.equal(f.elements.length, 4);

var json = f.serialize();
assert.equal(Object.keys(json).length, 1);
assert.equal(json['foo'].length, 2);
assert.equal(json['foo'][0], 'bar1');
assert.equal(json['foo'][1], 'bar3');
});

});

suite('submitting', function () {
Expand Down Expand Up @@ -155,8 +209,10 @@

form.addEventListener('iron-form-error', function(event) {
var error = event.detail;

expect(error).to.be.ok;
expect(error).to.be.instanceOf(Error);
expect(error).to.be.an('object');
expect(error.error).to.be.ok;
done();
});

Expand Down

0 comments on commit 0aa7bf9

Please sign in to comment.