I’m creating a dynamic sidebar in a Document with a Google Apps Scripts sidebar served by HTMLService.
In the client-side sidebar template script, I can find my container via a jQuery selector and dynamically append DOM buttons to it, but I cannot remove any button elements from the same container (which is best practice since each holds an event handler which, as I understand it, would not be deleted from memory).
The function within the sidebar.html responsible for these actions:
function fillContainerWithWords(arrayOfWords, container, wordClass) {
while (container.first()) { // empty word container
container.remove(container.first());
}
arrayOfWords.forEach(word => { // fill word container
let wordButton = `<div><button class="${wordClass}" onclick=getNewWords("${word}")>${word}</button></div>`;
container.append(wordButton);
})
}
CAN append to the container correctly, but DOES NOT remove any children from the container (so it ends up stacking DOM elements onto the container)
I’ve tried deviations of the same intent, such as:
- container.firstChild, (typical javascript way)
- $(container).firstChild, (the jQuery way)
- container.removeChild(container.first())
and nothing seems to work.
The "firstChild" approach produces an "undefined" (clearly not a property of the container.)
The code above is the closest I’ve managed, but produces an error deep in the jQuery implementation (or perhaps with Caja?):
jquery.min.js:4 Uncaught TypeError: t.replace is not a function
at st.matchesSelector (**jquery.min.js:4:10383**)
at Function.filter (**jquery.min.js:4:23300**)
at init.remove (**jquery.min.js:4:26762**)
at **fillContainerWithWords** (userCodeAppPanel:73:17)
at userCodeAppPanel:55:17
at Of (2515706220-mae_html_user_bin_i18n_mae_html_user.js:94:266)
at 2515706220-mae_html_user_bin_i18n_mae_html_user.js:25:132
at Ug.U (2515706220-mae_html_user_bin_i18n_mae_html_user.js:123:380)
at Bd (2515706220-mae_html_user_bin_i18n_mae_html_user.js:54:477)
at a (2515706220-mae_html_user_bin_i18n_mae_html_user.js:52:52)
Any info on restrictions or possible options is greatly appreciated…
Stripped down minimum example:
Code.gs
/**
* @OnlyCurrentDoc
*/
function onOpen(e) {
DocumentApp.getUi().createAddonMenu()
.addItem('Start', 'showSidebar')
.addToUi();
}
function onInstall(e) {
onOpen(e);
}
function showSidebar() {
const ui = HtmlService.createHtmlOutputFromFile('basic').setTitle('stackoverflow').setSandboxMode(HtmlService.SandboxMode.EMULATED);;
DocumentApp.getUi().showSidebar(ui);
}
basic.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<style>
.col-contain {
overflow: hidden;
}
.col-one {
float: left;
width: 50%;
}
.blue {
color: blue;
}
.red {
color: red;
}
</style>
<body>
<button class="blue" id="change-button">Change List</button>
<div class="block col-contain">
<div class="col-one" id="list"></div>
</div>
</body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(function() {
$('#change-button').click(() => fillContainerWithWords(['five', 'six', 'seven'], $("#list"), 'blue'));
});
function fillContainerWithWords(arrayOfWords, container, wordClass) {
// while (container.first()) { // empty word container
// container.remove(container.first());
// }
arrayOfWords.forEach(word => { // fill word container
let wordButton = `<div><button class="${wordClass}">${word}</button></div>`;
container.append(wordButton);
})
}
fillContainerWithWords(['one', 'two', 'three', 'four'], $("#list"), 'red');
</script>
</html>
2
Answers
Thanks Ruben - that put me on the right track.
For anyone curious for the full set of modifications required to get the function to work successfully to both remove and replace the list:
Remove
.setSandboxMode(HtmlService.SandboxMode.EMULATED);
Remove
by
and replace
by
It looks that the references that you used to write your code are obsolete as it includes
Document.querySelector
andDocument.querySelectorAll
could be used with CSS-selectors to select DOM elements in a similar way that jQuery used them.HtmlService.SandboxMode.EMULATED
.From https://developers.google.com/apps-script/reference/html/sandbox-mode
jQuery is not bad per se but, IMHO, nowadays it’s better to avoid it’s use in very small web apps like usually are Google editors custom dialogs and sidebars as the tecnhologies that support them have evolved a lot making jQuery not as "indispensable" as it was several years ago.