diff --git a/packages/mdc-auto-init/README.md b/packages/mdc-auto-init/README.md
index 5283d964c47..ac51e9c4506 100644
--- a/packages/mdc-auto-init/README.md
+++ b/packages/mdc-auto-init/README.md
@@ -66,6 +66,16 @@ property on that element.
document.querySelector('.mdc-text-field').MDCTextField.disabled = true;
```
+#### Calling subsequent `mdc.autoInit()`
+
+If you decide to add new components into the DOM after the initial `mdc.autoInit()`, you can make subsequent calls to `mdc.autoInit()`. This will not reinitialize existing components. This works since mdc-auto-init will add the `data-mdc-auto-init-state="initialized"` attribute, which tracks if the component has already been initialized. After calling `mdc.autoInit()` your component will then look like:
+
+```html
+
+ ...
+
+```
+
### Using as a standalone module
#### Registering Components
diff --git a/packages/mdc-auto-init/constants.ts b/packages/mdc-auto-init/constants.ts
new file mode 100644
index 00000000000..7147addc1a4
--- /dev/null
+++ b/packages/mdc-auto-init/constants.ts
@@ -0,0 +1,28 @@
+/**
+ * @license
+ * Copyright 2019 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+export const strings = {
+ AUTO_INIT_ATTR: 'data-mdc-auto-init',
+ AUTO_INIT_STATE_ATTR: 'data-mdc-auto-init-state',
+ INITIALIZED_STATE: 'initialized',
+};
diff --git a/packages/mdc-auto-init/index.ts b/packages/mdc-auto-init/index.ts
index 8494af562e8..deb9e866ae1 100644
--- a/packages/mdc-auto-init/index.ts
+++ b/packages/mdc-auto-init/index.ts
@@ -26,6 +26,10 @@
import {MDCComponent} from '@material/base/component';
import {MDCFoundation} from '@material/base/foundation';
+import {strings} from './constants';
+
+const {AUTO_INIT_ATTR, AUTO_INIT_STATE_ATTR, INITIALIZED_STATE} = strings;
+
export interface MDCAttachable {
new(root: Element, foundation?: F, ...args: Array): MDCComponent;
@@ -60,12 +64,13 @@ function emit(evtType: string, evtData: T, shouldBubble = fals
/**
* Auto-initializes all MDC components on a page.
*/
-export function mdcAutoInit(root = document, warn = CONSOLE_WARN) {
+export function mdcAutoInit(root = document) {
const components = [];
- const nodes: Element[] = [].slice.call(root.querySelectorAll('[data-mdc-auto-init]'));
+ let nodes: Element[] = [].slice.call(root.querySelectorAll(`[${AUTO_INIT_ATTR}]`));
+ nodes = nodes.filter((node) => node.getAttribute(AUTO_INIT_STATE_ATTR) !== INITIALIZED_STATE);
for (const node of nodes) {
- const ctorName = node.getAttribute('data-mdc-auto-init');
+ const ctorName = node.getAttribute(AUTO_INIT_ATTR);
if (!ctorName) {
throw new Error('(mdc-auto-init) Constructor name must be given.');
}
@@ -76,11 +81,6 @@ export function mdcAutoInit(root = document, warn = CONSOLE_WARN) {
`(mdc-auto-init) Could not find constructor in registry for ${ctorName}`);
}
- if (Object.getOwnPropertyDescriptor(node, ctorName)) {
- warn(`(mdc-auto-init) Component already initialized for ${node}. Skipping...`);
- continue;
- }
-
// TODO: Should we make an eslint rule for an attachTo() static method?
// See https://github.com/Microsoft/TypeScript/issues/14600 for discussion of static interface support in TS
const component = Constructor.attachTo(node);
@@ -91,6 +91,7 @@ export function mdcAutoInit(root = document, warn = CONSOLE_WARN) {
writable: false,
});
components.push(component);
+ node.setAttribute(AUTO_INIT_STATE_ATTR, INITIALIZED_STATE);
}
emit('MDCAutoInit:End', {});
diff --git a/test/unit/mdc-auto-init/mdc-auto-init.test.js b/test/unit/mdc-auto-init/mdc-auto-init.test.js
index 9347f078a4b..e8b45ccbb3d 100644
--- a/test/unit/mdc-auto-init/mdc-auto-init.test.js
+++ b/test/unit/mdc-auto-init/mdc-auto-init.test.js
@@ -96,17 +96,6 @@ test('throws when constructor is not registered', () => {
assert.throws(() => mdcAutoInit(root));
});
-test('warns when autoInit called multiple times on a node', () => {
- const root = setupTest();
- const warn = td.func('warn');
- const {contains} = td.matchers;
-
- mdcAutoInit(root, warn);
- mdcAutoInit(root, warn);
-
- td.verify(warn(contains('(mdc-auto-init) Component already initialized')));
-});
-
test('#register throws when Ctor is not a function', () => {
assert.throws(() => mdcAutoInit.register('not-a-function', 'Not a function'));
});
@@ -170,3 +159,20 @@ test('#returns the initialized components', () => {
assert.equal(components.length, 1);
assert.isOk(components[0] instanceof FakeComponent);
});
+
+test('does not register any components if element has data-mdc-auto-init-state="initialized"', () => {
+ const root = setupTest();
+ root.querySelector('[data-mdc-auto-init]').setAttribute('data-mdc-auto-init-state', 'initialized');
+ mdcAutoInit(root);
+
+ assert.isFalse(root.querySelector('.mdc-fake').FakeComponent instanceof FakeComponent);
+});
+
+test('does not return any new components after calling autoInit a second time', () => {
+ const root = setupTest();
+
+ let components = mdcAutoInit(root);
+ assert.equal(components.length, 1);
+ components = mdcAutoInit(root);
+ assert.equal(components.length, 0);
+});