Introduction to SPA and Router
I am currently delving into the workings of single page applications, specifically focusing on routers, state management, routes, and more. I have successfully implemented a basic hash router that can display content on a fragment element. Now, I am attempting to introduce a custom component similar to React components, but I've encountered an issue with placeholder replacement using {{ }}. Despite finding a workaround for the error I faced after days of struggling, I still lack a full understanding of the problem. It seems that when returned from within a class constructor, I cannot use methods like [...].join("") or access elements in an array using [...][1] without them being interpreted as [object Object]
Code snippet & Issue Description
To prevent interference with nested components, I opted for a Depth-First Search (DFS) through child nodes of my component and delegated the parsing task to a subclass. The specific condition causing trouble was:
if (current && current?.getAttribute) {
current.innerHTML = new _Fo_Component_PlaceholderParser({ node: current, content: current.innerHTML })
}
In the _Fo_Component_PlaceholderParser class:
class _Fo_Component_PlaceholderParser {
constructor({ node, content }) {
this.node = node;
return this.placeholderParser(content);
}
placeholderParser(value) {
if(value.trim === "") {
return value
}
const parts = value.split(/(<\/?\w+[^>]*>)/g);
const stack = [];
let output = [];
for (let part of parts) {
const trimmedPart = part.trim();
if (/^<\w+[^>]*>$/.test(trimmedPart)) {
stack.push(trimmedPart);
const processedTag =
stack.length === 1
? trimmedPart.replace(/\{\{.*?\}\}/g, "testing")
: trimmedPart;
output.push(String(processedTag));
if (this.isSelfClosing(trimmedPart)) {
stack.pop();
}
} else if (/^<\/\w+>$/.test(trimmedPart)) {
stack.pop();
output.push(String(trimmedPart));
} else if (/\{\{.*?\}\}/.test(trimmedPart) && stack.length === 0) {
output.push(String(trimmedPart.replace(/\{\{.*?\}\}/g, "testing")));
} else if (trimmedPart.length > 0) {
output.push(String(trimmedPart));
}
}
return output.join("");
}
//rest of the method ...
}
The issue arises in the _Fo_Component_PlaceholderParser
where the class directly returns
this.placeholderParser()
, which in turn returns output.join("")
.
However, when displayed on the DOM, output.join("")
shows as [object Object]
even though it contains the parsed data when logged during the process.
Interestingly, returning just output
displays perfectly as an array in the DOM, comma-separated.
Hence, using output.join("")
shouldn't be problematic, right?
Moreover, it's not just the .join
method.
Even trying output[0]
results in [object Object]
, making manual string concatenation of output
futile as it simply displays
[object Object] [object Object] [object Object]...
.
Surprisingly, removing my logic and replacing output
with ["test", "it works"]
leads to the same outcome. The values were hardcoded and directly returned, yet the behavior remained consistent. Why?
What is the underlying issue here?
The only successful approach so far has been returning output
directly from the class and then performing the joining operation within the DFS condition as:
if (current && current?.getAttribute) {
current.innerHTML = new _Fo_Component_PlaceholderParser({ node: current, content: current.innerHTML }).join("")
}
Seeking Assistance With
- Why does
output.join("")
return [object Object] on the DOM when returned from the class? - Could this be related to how JavaScript handles return values from a class constructor?
- What would be the correct way to resolve this perplexing issue?