FastComments.com

With FastComments, we can have as many comment widgets on the same page as we want. We can set them all to the same thread, and they will be kept in sync, or we can have them all be different threads at the same time. We can add, remove, and change the comment threads on-demand.

Dynamically Add and Swap Comment Threads Internal Link

This is all done by configuring the urlId and related parameters and calling update() on the widget instances to swap them out with a different thread.

The below is an interactive example (hit run in the top left) which allows you to add and swap comment threads on demand. We could remove them as well by calling instance.destroy instead of update.

Add and Swap Comment Threads
Copy CopyRun External Link
1
2 <script src="https://cdn.fastcomments.com/js/embed-v2.min.js"></script>
3
4 <div id="fastcomments-widgets"></div>
5 <div class="demo-form">
6 <section>
7 <h3>Add or Swap a Product/Comment Thread</h3>
8 <label>
9 Product Name
10 <input type="text" name="name" />
11 </label>
12 <label>
13 Product ID
14 <input type="text" name="id" />
15 </label>
16 <label>
17 Product URL
18 <input type="url" name="url" />
19 </label>
20 <label>
21 Replaces Product (id)
22 <input type="text" name="replaces_id" />
23 </label>
24 <button type="button">Add/Swap</button>
25 </section>
26 </div>
27 <script>
28 (function () {
29 const target = document.getElementById('fastcomments-widgets');
30 const tenantId = "demo"; // PUT YOUR TENANT ID HERE
31
32 function setHeading(heading, {name, productID}) {
33 heading.innerHTML = `${name} (${productID})`;
34 }
35
36 function addWidget({name, productID, productURL}) {
37 const outer = document.createElement('div');
38 const heading = document.createElement('h5');
39 setHeading(heading, {name, productID});
40 const inner = document.createElement('div');
41 inner.append(heading);
42 outer.append(inner);
43 const widgetTarget = document.createElement('div');
44 outer.append(widgetTarget);
45 target.append(outer);
46 window.FastCommentsUI(widgetTarget, {
47 "tenantId": tenantId,
48 "pageTitle": name, // for notification emails and moderation dashboard
49 "url": productURL, // for notification emails and moderation dashboard
50 "urlId": productID,
51 "showLiveRightAway": true
52 });
53 }
54
55 function switchProduct(oldId, {name, productID, productURL}) {
56 for (const instanceWrapped of fcUIInstances) {
57 if (instanceWrapped.targetElement) {
58 const config = instanceWrapped.config;
59 if (config.urlId === oldId) {
60 const heading = instanceWrapped.targetElement.parentNode.querySelector('h5');
61 setHeading(heading, {name, productID});
62 config.pageTitle = name;
63 config.urlId = productID;
64 config.url = productURL;
65 instanceWrapped.instance.update(config);
66 return;
67 }
68 }
69 }
70 alert(`Product ${oldId} not found to replace!`);
71 }
72
73 // add some widgets
74 addWidget({name: "Product A", productID: 'product-id-a', productURL: 'https://example.com/a'});
75 addWidget({name: "Product B", productID: 'product-id-b', productURL: 'https://example.com/b'});
76
77 const form = document.querySelector('.demo-form');
78 form.querySelector('button').addEventListener('click', function() {
79 const name = form.querySelector('input[name=name]').value;
80 const productID = form.querySelector('input[name=id]').value;
81 const productURL = form.querySelector('input[name=url]').value;
82 const replaces_id = form.querySelector('input[name=replaces_id]').value;
83
84 if (replaces_id) {
85 switchProduct(replaces_id, {
86 name,
87 productID,
88 productURL,
89 });
90 } else {
91 addWidget({name, productID, productURL});
92 }
93 });
94 })();
95 </script>
96 <style>
97 #fastcomments-widgets {
98 display: flex;
99 }
100 #fastcomments-widgets > div {
101 width: 100%;
102 }
103
104 .demo-form section label {
105 display: block;
106 margin-bottom: 20px;
107 }
108 </style>
109

This is similar to how pagination works.

With the React and related libraries we can simply update the configuration and the library (React, Angular, Vue) will handle refreshing the widget for us. With VanillaJS we have to manage it ourselves as shown.

Feel free to ask any questions below and we'll do our best to help!