OK, for what it’s worth I have this working now…needed to encode and decode “dangerous characters”. For anyone using web forms who might be interested:
<!-- search box with a linkbutton that calls the function -->
<label for="searchbox">Search Schedule</label><input type="search" id="searchbox" placeholder="search..."><asp:LinkButton ID="lnkBtn_search" runat="server" Text="search" OnClientClick="searchEvents();return false;" class="buttonLocal3" />
//02-27-2026: functions to simulate html encode and decode functions.
//IMPORTANT: You have to use the 'HTML Name' values and not the 'HTML Number' values
//otherwise you still get the "dangerous characters" error.
function htmlEncode(s) {
return s.replace(/&/g, '&')
.replace(/{/g, '{')
.replace(/}/g, '}')
.replace(/\[/g, '[')
.replace(/\]/g, ']')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/:/g, ':')
}
function htmlDecode(s) {
return s.replace(/&/g, '&')
.replace(/{/g, '{')
.replace(/}/g, '}')
.replace(/[/g, '[')
.replace(/]/g, ']')
.replace(/:/g, ':')
.replace(/</g, '<')
.replace(/>/g, '>')
}
function searchEvents() {
if (!document.getElementById("searchbox").value == "") {
const query = document.getElementById("searchbox").value;
//get the full events.list and conver tto a text string.
const allEvents = JSON.stringify(dp_month.events.list);
console.log(htmlEncode(allEvents)); //comment out when debugging is complete
//get the current events list and write to a hidden field
document.getElementById("<%= hiddenFieldEventList.ClientID %>").value = htmlEncode(allEvents);
//I'm using bubbleHTML since I populated it with all of the searchable data
//note that both bubbleHtml and the query need to be forced toUpperCase to work properly.
let filteredEventsData = dp_month.events.list.filter(data => data.bubbleHtml.toUpperCase().includes(query.toUpperCase()));
//overwrite the events.list with the search and update
dp_month.events.list = filteredEventsData;
dp_month.update();
} else {
//do nothing....
}
At the bottom of the .aspx page you’ll need another <script></script> block for clearing the search. I tried doing it with a deferred external script, but results were inconsistent:
<script>
//reset for the search field
const input = document.getElementById('searchbox');
const resetButton = document.getElementById("btn_resetFromSearch");
input.addEventListener('input', (event) => {
// This code runs when the search box is manually cleared OR the 'x' is clicked
if (event.currentTarget.value === "") {
//retrieve the hidden field value
const hiddenEventsList = document.getElementById("<%= hiddenFieldEventList.ClientID %>").value;
//decode the encoded html
const hiddenEventsListDecoded = htmlDecode(hiddenEventsList);
//use json.parse() on the data so the calendar can read it.
const eventsListArray = JSON.parse(hiddenEventsListDecoded);
//assign the array to the events.list and update the calendar.
dp_month.events.list = eventsListArray;
dp_month.update();
} else {
//do nothing
}
});
</script>
End result is that upon clicking the search button the calendar immediately removes any records that do come back with at least a partial match to the searched value. Upon clearing the search box, either by back typing or by clicking the “x”, the stored events list is restored to the calendar.
My original thought that I was violating the page view state turned out to be incorrect so all context functions, etc. work as expected. The searched view does not currently persist when performing a right-click function, etc. but only because I haven’t built the persistence part into it as of yet.
Thanks again to Dan for the tidbits…went a long way towards getting this working.