Keeps undefined from showing in template

Removes attributes which have a value of undefined.

```html
<div id="undefined"></div>
<!-- is now -->
<div></div>
```

```html
<h1>Hello undefined!</h1>
<!-- is now -->
<h1>Hello !</h1>
```

This may be considered backwards incompatable and may need to wait until Svelte 3. If existing apps rely on e.g. querySelector('[id="undefined"]') then this could require changes.
pull/1803/head
Jacob Wright 7 years ago
parent 4890d4dc02
commit dd7bc6a988

@ -181,12 +181,13 @@ export default class Attribute extends Node {
let updater; let updater;
const init = shouldCache ? `${last} = ${value}` : value; const init = shouldCache ? `${last} = ${value}` : value;
const updaterValue = shouldCache ? last : value;
if (isLegacyInputType) { if (isLegacyInputType) {
block.builders.hydrate.addLine( block.builders.hydrate.addLine(
`@setInputType(${node.var}, ${init});` `@setInputType(${node.var}, ${init});`
); );
updater = `@setInputType(${node.var}, ${shouldCache ? last : value});`; updater = `@setInputType(${node.var}, ${updaterValue});`;
} else if (isSelectValueAttribute) { } else if (isSelectValueAttribute) {
// annoying special case // annoying special case
const isMultipleSelect = node.getStaticAttributeValue('multiple'); const isMultipleSelect = node.getStaticAttributeValue('multiple');
@ -216,19 +217,19 @@ export default class Attribute extends Node {
`); `);
} else if (propertyName) { } else if (propertyName) {
block.builders.hydrate.addLine( block.builders.hydrate.addLine(
`${node.var}.${propertyName} = ${init};` `@setProperty(${node.var}, "${propertyName}", "${name}", ${init});`
); );
updater = `${node.var}.${propertyName} = ${shouldCache ? last : value};`; updater = `@setProperty(${node.var}, "${propertyName}", "${name}", ${updaterValue});`;
} else if (isDataSet) { } else if (isDataSet) {
block.builders.hydrate.addLine( block.builders.hydrate.addLine(
`${node.var}.dataset.${camelCaseName} = ${init};` `@setDataSet(${node.var}, "${camelCaseName}", "${name}", ${init});`
); );
updater = `${node.var}.dataset.${camelCaseName} = ${shouldCache ? last : value};`; updater = `@setDataSet(${node.var}, "${camelCaseName}", "${name}", ${updaterValue});`;
} else { } else {
block.builders.hydrate.addLine( block.builders.hydrate.addLine(
`${method}(${node.var}, "${name}", ${init});` `${method}(${node.var}, "${name}", ${init});`
); );
updater = `${method}(${node.var}, "${name}", ${shouldCache ? last : value});`; updater = `${method}(${node.var}, "${name}", ${updaterValue});`;
} }
if (this.dependencies.size || isSelectValueAttribute) { if (this.dependencies.size || isSelectValueAttribute) {

@ -970,13 +970,15 @@ export default class Element extends Node {
textareaContents = attribute.stringifyForSsr(); textareaContents = attribute.stringifyForSsr();
} else if (attribute.isTrue) { } else if (attribute.isTrue) {
openingTag += ` ${attribute.name}`; openingTag += ` ${attribute.name}`;
} else if ( } else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') {
booleanAttributes.has(attribute.name) && if (booleanAttributes.has(attribute.name)) {
attribute.chunks.length === 1 &&
attribute.chunks[0].type !== 'Text'
) {
// a boolean attribute with one non-Text chunk // a boolean attribute with one non-Text chunk
openingTag += '${' + attribute.chunks[0].snippet + ' ? " ' + attribute.name + '" : "" }'; openingTag += '${' + attribute.chunks[0].snippet + ' ? " ' + attribute.name + '" : "" }';
} else {
openingTag += '${ (' + attribute.chunks[0].snippet + ') !== undefined ? ` ' +
` ${attribute.name}="${attribute.stringifyForSsr()}"` +
'` : "" }';
}
} else { } else {
openingTag += ` ${attribute.name}="${attribute.stringifyForSsr()}"`; openingTag += ` ${attribute.name}="${attribute.stringifyForSsr()}"`;
} }

@ -66,7 +66,7 @@ export function createSvgElement(name) {
} }
export function createText(data) { export function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
export function createComment() { export function createComment() {
@ -82,7 +82,11 @@ export function removeListener(node, event, handler) {
} }
export function setAttribute(node, attribute, value) { export function setAttribute(node, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node.setAttribute(attribute, value); node.setAttribute(attribute, value);
}
} }
export function setAttributes(node, attributes) { export function setAttributes(node, attributes) {
@ -110,6 +114,22 @@ export function removeAttribute(node, attribute) {
node.removeAttribute(attribute); node.removeAttribute(attribute);
} }
export function setProperty(node, prop, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node[prop] = value;
}
}
export function setDataSet(node, prop, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node.dataset[prop] = value;
}
}
export function setXlinkAttribute(node, attribute, value) { export function setXlinkAttribute(node, attribute, value) {
node.setAttributeNS('http://www.w3.org/1999/xlink', attribute, value); node.setAttributeNS('http://www.w3.org/1999/xlink', attribute, value);
} }
@ -166,7 +186,7 @@ export function claimText (nodes, data) {
} }
export function setData(text, data) { export function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
export function setInputType(input, type) { export function setInputType(input, type) {

@ -32,7 +32,7 @@ export const escaped = {
}; };
export function escape(html) { export function escape(html) {
return String(html).replace(/["'&<>]/g, match => escaped[match]); return html === undefined ? '' : String(html).replace(/["'&<>]/g, match => escaped[match]);
} }
export function each(items, assign, fn) { export function each(items, assign, fn) {

@ -64,7 +64,7 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function addLoc(element, file, line, column, char) { function addLoc(element, file, line, column, char) {

@ -69,7 +69,7 @@ var Main = (function(answer) { "use strict";
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function insert(target, node, anchor) { function insert(target, node, anchor) {
@ -81,7 +81,7 @@ var Main = (function(answer) { "use strict";
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function detachNode(node) { function detachNode(node) {

@ -64,7 +64,7 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function insert(target, node, anchor) { function insert(target, node, anchor) {
@ -76,7 +76,7 @@ function append(target, node) {
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function detachNode(node) { function detachNode(node) {

@ -22,11 +22,11 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function blankObject() { function blankObject() {

@ -28,11 +28,11 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function blankObject() { function blankObject() {

@ -34,11 +34,11 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function blankObject() { function blankObject() {

@ -34,11 +34,11 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function blankObject() { function blankObject() {

@ -28,7 +28,7 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function createComment() { function createComment() {
@ -36,7 +36,7 @@ function createComment() {
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function blankObject() { function blankObject() {

@ -28,11 +28,11 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function blankObject() { function blankObject() {

@ -18,7 +18,19 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
}
function removeAttribute(node, attribute) {
node.removeAttribute(attribute);
}
function setDataSet(node, prop, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node.dataset[prop] = value;
}
} }
function blankObject() { function blankObject() {
@ -156,7 +168,7 @@ function create_main_fragment(component, ctx) {
text = createText("\n"); text = createText("\n");
div_1 = createElement("div"); div_1 = createElement("div");
div.dataset.foo = "bar"; div.dataset.foo = "bar";
div_1.dataset.foo = ctx.bar; setDataSet(div_1, "foo", "data-foo", ctx.bar);
}, },
m(target, anchor) { m(target, anchor) {
@ -167,7 +179,7 @@ function create_main_fragment(component, ctx) {
p(changed, ctx) { p(changed, ctx) {
if (changed.bar) { if (changed.bar) {
div_1.dataset.foo = ctx.bar; setDataSet(div_1, "foo", "data-foo", ctx.bar);
} }
}, },

@ -1,5 +1,5 @@
/* generated by Svelte vX.Y.Z */ /* generated by Svelte vX.Y.Z */
import { assign, createElement, createText, detachNode, init, insert, proto } from "svelte/shared.js"; import { assign, createElement, createText, detachNode, init, insert, proto, setDataSet } from "svelte/shared.js";
function create_main_fragment(component, ctx) { function create_main_fragment(component, ctx) {
var div, text, div_1; var div, text, div_1;
@ -10,7 +10,7 @@ function create_main_fragment(component, ctx) {
text = createText("\n"); text = createText("\n");
div_1 = createElement("div"); div_1 = createElement("div");
div.dataset.foo = "bar"; div.dataset.foo = "bar";
div_1.dataset.foo = ctx.bar; setDataSet(div_1, "foo", "data-foo", ctx.bar);
}, },
m(target, anchor) { m(target, anchor) {
@ -21,7 +21,7 @@ function create_main_fragment(component, ctx) {
p(changed, ctx) { p(changed, ctx) {
if (changed.bar) { if (changed.bar) {
div_1.dataset.foo = ctx.bar; setDataSet(div_1, "foo", "data-foo", ctx.bar);
} }
}, },

@ -18,11 +18,19 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function setAttribute(node, attribute, value) { function setAttribute(node, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node.setAttribute(attribute, value); node.setAttribute(attribute, value);
}
}
function removeAttribute(node, attribute) {
node.removeAttribute(attribute);
} }
function blankObject() { function blankObject() {

@ -22,7 +22,15 @@ function createSvgElement(name) {
} }
function setAttribute(node, attribute, value) { function setAttribute(node, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node.setAttribute(attribute, value); node.setAttribute(attribute, value);
}
}
function removeAttribute(node, attribute) {
node.removeAttribute(attribute);
} }
function blankObject() { function blankObject() {

@ -34,11 +34,11 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function blankObject() { function blankObject() {

@ -22,7 +22,7 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function createComment() { function createComment() {
@ -30,7 +30,7 @@ function createComment() {
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function linear(t) { function linear(t) {

@ -22,7 +22,7 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function createComment() { function createComment() {
@ -30,7 +30,7 @@ function createComment() {
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function destroyBlock(block, lookup) { function destroyBlock(block, lookup) {

@ -18,7 +18,19 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
}
function removeAttribute(node, attribute) {
node.removeAttribute(attribute);
}
function setProperty(node, prop, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node[prop] = value;
}
} }
function blankObject() { function blankObject() {
@ -155,8 +167,8 @@ function create_main_fragment(component, ctx) {
div = createElement("div"); div = createElement("div");
text = createText("\n"); text = createText("\n");
div_1 = createElement("div"); div_1 = createElement("div");
div.style.cssText = ctx.style; setProperty(div, "style.cssText", "style", ctx.style);
div_1.style.cssText = div_1_style_value = "" + ctx.key + ": " + ctx.value; setProperty(div_1, "style.cssText", "style", div_1_style_value = "" + ctx.key + ": " + ctx.value);
}, },
m(target, anchor) { m(target, anchor) {
@ -167,11 +179,11 @@ function create_main_fragment(component, ctx) {
p(changed, ctx) { p(changed, ctx) {
if (changed.style) { if (changed.style) {
div.style.cssText = ctx.style; setProperty(div, "style.cssText", "style", ctx.style);
} }
if ((changed.key || changed.value) && div_1_style_value !== (div_1_style_value = "" + ctx.key + ": " + ctx.value)) { if ((changed.key || changed.value) && div_1_style_value !== (div_1_style_value = "" + ctx.key + ": " + ctx.value)) {
div_1.style.cssText = div_1_style_value; setProperty(div_1, "style.cssText", "style", div_1_style_value);
} }
}, },

@ -1,5 +1,5 @@
/* generated by Svelte vX.Y.Z */ /* generated by Svelte vX.Y.Z */
import { assign, createElement, createText, detachNode, init, insert, proto } from "svelte/shared.js"; import { assign, createElement, createText, detachNode, init, insert, proto, setProperty } from "svelte/shared.js";
function create_main_fragment(component, ctx) { function create_main_fragment(component, ctx) {
var div, text, div_1, div_1_style_value; var div, text, div_1, div_1_style_value;
@ -9,8 +9,8 @@ function create_main_fragment(component, ctx) {
div = createElement("div"); div = createElement("div");
text = createText("\n"); text = createText("\n");
div_1 = createElement("div"); div_1 = createElement("div");
div.style.cssText = ctx.style; setProperty(div, "style.cssText", "style", ctx.style);
div_1.style.cssText = div_1_style_value = "" + ctx.key + ": " + ctx.value; setProperty(div_1, "style.cssText", "style", div_1_style_value = "" + ctx.key + ": " + ctx.value);
}, },
m(target, anchor) { m(target, anchor) {
@ -21,11 +21,11 @@ function create_main_fragment(component, ctx) {
p(changed, ctx) { p(changed, ctx) {
if (changed.style) { if (changed.style) {
div.style.cssText = ctx.style; setProperty(div, "style.cssText", "style", ctx.style);
} }
if ((changed.key || changed.value) && div_1_style_value !== (div_1_style_value = "" + ctx.key + ": " + ctx.value)) { if ((changed.key || changed.value) && div_1_style_value !== (div_1_style_value = "" + ctx.key + ": " + ctx.value)) {
div_1.style.cssText = div_1_style_value; setProperty(div_1, "style.cssText", "style", div_1_style_value);
} }
}, },

@ -26,7 +26,15 @@ function removeListener(node, event, handler) {
} }
function setAttribute(node, attribute, value) { function setAttribute(node, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node.setAttribute(attribute, value); node.setAttribute(attribute, value);
}
}
function removeAttribute(node, attribute) {
node.removeAttribute(attribute);
} }
function blankObject() { function blankObject() {

@ -26,7 +26,15 @@ function removeListener(node, event, handler) {
} }
function setAttribute(node, attribute, value) { function setAttribute(node, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node.setAttribute(attribute, value); node.setAttribute(attribute, value);
}
}
function removeAttribute(node, attribute) {
node.removeAttribute(attribute);
} }
function toNumber(value) { function toNumber(value) {

@ -26,7 +26,15 @@ function removeListener(node, event, handler) {
} }
function setAttribute(node, attribute, value) { function setAttribute(node, attribute, value) {
if (value === undefined) {
removeAttribute(node, attribute);
} else {
node.setAttribute(attribute, value); node.setAttribute(attribute, value);
}
}
function removeAttribute(node, attribute) {
node.removeAttribute(attribute);
} }
function blankObject() { function blankObject() {

@ -16,7 +16,7 @@ function detachNode(node) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function blankObject() { function blankObject() {

@ -22,7 +22,7 @@ function createSvgElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function blankObject() { function blankObject() {

@ -22,7 +22,7 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function createComment() { function createComment() {

@ -22,11 +22,11 @@ function createElement(name) {
} }
function createText(data) { function createText(data) {
return document.createTextNode(data); return document.createTextNode(data === undefined ? '' : data);
} }
function setData(text, data) { function setData(text, data) {
text.data = '' + data; text.data = data === undefined ? '' : '' + data;
} }
function blankObject() { function blankObject() {

@ -0,0 +1,7 @@
export default {
html: `<textarea></textarea>`,
test (assert, component, target) {
const textarea = target.querySelector('textarea');
assert.ok(textarea.hasAttribute('data-foo') === false);
},
};

@ -0,0 +1 @@
<textarea data-foo="{undefined}"></textarea>

@ -0,0 +1,7 @@
export default {
html: `<textarea></textarea>`,
test (assert, component, target) {
const textarea = target.querySelector('textarea');
assert.ok(textarea.hasAttribute('readonly') === false);
},
};

@ -0,0 +1 @@
<textarea readonly="{undefined}"></textarea>

@ -0,0 +1,7 @@
export default {
html: `<textarea></textarea>`,
test (assert, component, target) {
const textarea = target.querySelector('textarea');
assert.ok(textarea.hasAttribute('foo') === false);
},
};

@ -0,0 +1 @@
<textarea foo="{undefined}"></textarea>

@ -37,7 +37,7 @@ export default {
assert.equal( component.get().count, undefined ); assert.equal( component.get().count, undefined );
assert.htmlEqual( target.innerHTML, ` assert.htmlEqual( target.innerHTML, `
<input type='number'> <input type='number'>
<p>undefined undefined</p> <p>undefined </p>
` ); ` );
} }
}; };

@ -7,7 +7,7 @@ export default {
html: ` html: `
<p>woo!</p> <p>woo!</p>
<p>undefined</p> <p></p>
`, `,
test(assert, component, target) { test(assert, component, target) {

@ -0,0 +1,11 @@
export default {
html: 'foo is ',
test(assert, component, target) {
component.set({ foo: 42 });
assert.htmlEqual(target.innerHTML, 'foo is 42');
component.set({ foo: undefined });
assert.htmlEqual(target.innerHTML, 'foo is ');
}
};
Loading…
Cancel
Save