diff --git a/packages/ui/render.js b/packages/ui/render.js index 35bef5703a..09c656b94a 100644 --- a/packages/ui/render.js +++ b/packages/ui/render.js @@ -132,11 +132,13 @@ makeRenderBuffer = function (component, options) { throw new Error("Expected 'type' to be Component or function"); } } else if (arg.attrs) { + // `{attrs: { name1: string, array, or function, ... }}` // attrs object inserts zero or more `name="value"` items // into the HTML, and can reactively update them later. // You can have multiple attrs objects in a tag, but they // can't specify any of the same attributes (i.e. the right // thing won't happen). + var elemId = null; for (var attrName in arg.attrs) { if (! ATTRIBUTE_NAME_REGEX.test(attrName)) throw new Error("Illegal HTML attribute name: " + attrName); @@ -155,22 +157,29 @@ makeRenderBuffer = function (component, options) { initialValue = attrValue(); }); - var elemId = elementUid++; - strs.push('data-meteorui-id', curDataAttrNumber, - '="', elemId, '" '); - if (curDataAttrNumber > maxDataAttrNumber) { - dataAttrs[curDataAttrNumber-1] = - 'data-meteorui-id' + curDataAttrNumber; - maxDataAttrNumber = curDataAttrNumber; + if (! elemId) { + elemId = elementUid++; + // don't call the `push` helper, go around it + strs.push('data-meteorui-id', curDataAttrNumber, + '="', elemId, '" '); + if (curDataAttrNumber > maxDataAttrNumber) { + dataAttrs[curDataAttrNumber-1] = + 'data-meteorui-id' + curDataAttrNumber; + maxDataAttrNumber = curDataAttrNumber; + } + curDataAttrNumber++; + greaterThanEndsTag = true; } - curDataAttrNumber++; - greaterThanEndsTag = true; - elementsToWire[elemId] = { + var info = (elementsToWire[elemId] || + (elementsToWire[elemId] = {})); + + info[attrName] = { attrName: attrName, attrValueFunc: attrValue, initialValue: initialValue }; + } else { initialValue = attrValue; } @@ -232,7 +241,7 @@ makeRenderBuffer = function (component, options) { if (elemId) { var info = elementsToWire[elemId]; if (info) - info.element = n; + info._element = n; n.removeAttribute(attrName); } } @@ -261,47 +270,53 @@ makeRenderBuffer = function (component, options) { component._onNextBuilt(function () { for (var k in elementsToWire) { var infoObj = elementsToWire[k]; - if (infoObj.element) { + if (infoObj._element) { // element found during DOM traversal - component.autorun(function (c) { - // bring infoObj into our closure as `info`. - // `infoObj` is not safe to close over because - // it's in a for loop, but it is safe during - // the first autorun which is inline. - if (c.firstRun) { - c.info = infoObj; - c.curValue = infoObj.initialValue; - } - var info = c.info; - if (component.stage !== Component.BUILT || - ! component.containsElement(info.element)) { - c.stop(); - return; - } - // capture dependencies of this line: - var newValue = info.attrValueFunc(); + for (var attrName in infoObj) { + // XXXX putting _element on the dictionary is not right + if (attrName === '_element') + continue; + component.autorun(function (c) { + // note: it's not safe to access `attrName` + // and `infoObj` from this closure, except + // during firstRun when they have their original + // values. + if (c.firstRun) { + c.element = infoObj._element; + c.info = infoObj[attrName]; + c.curValue = c.info.initialValue; + } + var info = c.info; + if (component.stage !== Component.BUILT || + ! component.containsElement(c.element)) { + c.stop(); + return; + } + // capture dependencies of this line: + var newValue = info.attrValueFunc(); - var oldValue = c.curValue; - if (newValue == null) { - if (oldValue != null) - info.element.removeAttribute(info.attrName); - } else { - var newStringValue = stringifyAttrValue(newValue); - if (oldValue == null) { - info.element.setAttribute( - info.attrName, newStringValue); + var oldValue = c.curValue; + if (newValue == null) { + if (oldValue != null) + c.element.removeAttribute(info.attrName); } else { - var oldStringValue = - stringifyAttrValue(oldValue); - if (newStringValue !== oldStringValue) { - info.element.setAttribute( + var newStringValue = stringifyAttrValue(newValue); + if (oldValue == null) { + c.element.setAttribute( info.attrName, newStringValue); + } else { + var oldStringValue = + stringifyAttrValue(oldValue); + if (newStringValue !== oldStringValue) { + c.element.setAttribute( + info.attrName, newStringValue); + } } } - } - c.curValue = newValue; - }); + c.curValue = newValue; + }); + } } } elementsToWire = null;