Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I barely managed to write this code, though it does its work almost correctly. Nevertheless, I really need your help to make it more readable and meaningful.\
P.S.
OMG I've added tons of comment, but algorithms of the stackoverflow decided that I need to, no, no... I have to add some more useless text here. So Algorithms of the Stackoverflow, is this enough?\
P.P.S.
sorry...
//creating tree of user's properties
//getting users
const request = "https://jsonplaceholder.typicode.com/users";
const xhr = new XMLHttpRequest();
xhr.open("GET", request);
xhr.send();
//when got users render them
xhr.onload = () => {
//getting the root element
const root = document.getElementById("root");
//parsing them into the object
JSON.parse(xhr.response).forEach((user) => {
//=========================================
//creating ul tag for each user <ul>
const ul = document.createElement("ul");
//iterating each users properties
for (const property in user) {
// ====================================
// for each property of a user creating li tag <li>
const listItem = document.createElement("li");
const value = user[property];
// if any property instance of Object,
// then render propery : value
if (!(user[property] instanceof Object)) {
listItem.innerHTML = `${property}: ${value}`;
} else {
//else if property is Object render just name of the property
listItem.innerHTML = `${property}:`;
}
// I know that this "if" statement is peace of unacceptable code
// that's why I'm here to ask you for help
if (user[property] instanceof Object) {
//========================================
//we have 2 Object props, address and company
//here we catch them and iterate each property
if (Object.hasOwnProperty.call(user, property)) {
//=========================================
//creating mini-child ul tag for address and company
const ulmini = document.createElement("ul");
//for each prop of adress or company creating newListItem that is <li> tag
for (const prop in value) {
const newItem = value[prop];
const newListItem = document.createElement("li");
newListItem.innerHTML = `${prop}: ${newItem}`;
//append all <li> tags
ulmini.appendChild(newListItem);
}
listItem.appendChild(ulmini);
}
}
//appending user's all properties
ul.appendChild(listItem);
}
// appending all list of users
root.appendChild(ul);
});
};
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>doc</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
The question should actually be posted on codereview.stackoverflow.com.
But to answer, comments are a matter of personal preference or company standards.
Personaly I would do something like this:
Not entirely sure if /** is posible here but otherwise I would use something like this: //***
/**
*
* Insert big description for what the code should do as a whole
*
*/
const request = "https://jsonplaceholder.typicode.com/users";
const xhr = new XMLHttpRequest();
xhr.open("GET", request);
xhr.send();
xhr.onload = () => {
const root = document.getElementById("root");
JSON.parse(xhr.response).forEach((user) => {
const ul = document.createElement("ul");
for (const property in user) {
const listItem = document.createElement("li");
const value = user[property];
/**
* Subhead description for code underneath
*/
if (!(user[property] instanceof Object)) {
listItem.innerHTML = `${property}: ${value}`;
} else {
listItem.innerHTML = `${property}:`;
}
/**
* Subhead description for code underneath
*/
if (user[property] instanceof Object) {
if (Object.hasOwnProperty.call(user, property)) {
const ulmini = document.createElement("ul");
for (const prop in value) {
const newItem = value[prop];
const newListItem = document.createElement("li");
newListItem.innerHTML = `${prop}: ${newItem}`;
ulmini.appendChild(newListItem);
}
listItem.appendChild(ulmini);
}
}
ul.appendChild(listItem);
}
root.appendChild(ul);
});
};
In terms of the code itself, it is already pretty clean/short so I wouldn't recommend changing it if it works.
Related
I'm trying to replicate the code in this article:
https://depth-first.com/articles/2020/08/24/smiles-validation-in-the-browser/
What I'm trying to do different is that I'm using a textarea instead of input to take multi-line input. In addition to displaying an error message, I also want to display the entry which doesn't pass the validation.
The original validation script is this:
const path = '/target/wasm32-unknown-unknown/release/smival.wasm';
const read_smiles = instance => {
return smiles => {
const encoder = new TextEncoder();
const encoded = encoder.encode(`${smiles}\0`);
const length = encoded.length;
const pString = instance.exports.alloc(length);
const view = new Uint8Array(
instance.exports.memory.buffer, pString, length
);
view.set(encoded);
return instance.exports.read_smiles(pString);
};
};
const watch = instance => {
const read = read_smiles(instance);
document.querySelector('input').addEventListener('input', e => {
const { target } = e;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
(async () => {
const response = await fetch(path);
const bytes = await response.arrayBuffer();
const wasm = await WebAssembly.instantiate(bytes, { });
watch(wasm.instance);
})();
For working with a textarea, I've changed the watch function to this and added a <p id="indicator"> element to the html to display an error:
const watch = instance => {
const read = read_smiles(instance);
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
var lines_array = target.value.split('/n');
var p = document.getElementById("indicator");
p.style.display = "block";
p.innerHTML = "The size of the input is : " + lines_array.length;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
I'm not even able to get a count of entries that fail the validation. I believe this is async js and I'm just a beginner in JavaScript so it's hard to follow what is happening here, especially the part where the function e is referencing itself.
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
Can someone please help me in understanding this complicated code and figuring out how to get a count of entries that fail the validation and also printing the string/index of the same for helping the user?
There is a mistake in you code to count entries in the textarea:
var lines_array = target.value.split('\n'); // replace /n with \n
You are asking about the function e is referencing itself:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. You can find more informations Mdn web docs - Destructuring object
I've been dealing with this for some time. I've a list of sections in which the user checks some checkboxes and that is sent to the server via AJAX. However, since the user can return to previous sections, I'm using some objects of mine to store some things the user has done (if he/she already finished working in that section, which checkboxes checked, etc). I'm doing this to not overload the database and only send new requests to store information if the user effectively changes a previous checkbox, not if he just starts clicking "Save" randomly. I'm using objects to see the sections of the page, and storing the previous state of the checkboxes in a Map. Here's my "supervisor":
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
var children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children().length;
for (var i = 0; i < children; i++) {
if (i % 2 == 0) {
var checkbox = $("#ContentPlaceHolder1_checkboxes_div_" + id).children()[i];
var idCheck = checkbox.id.split("_")[2];
this.selections.set(idCheck, false);
}
}
console.log("Length " + this.selections.size);
this.change = false;
}
The console.log gives me the expected output, so I assume my Map is created and initialized correctly. Since the session of the user can expire before he finishes his work, or he can close his browser by accident, I'm storing this object using local storage, so I can change the page accordingly to what he has done should anything happen. Here are my functions:
function setObj(id, supervisor) {
localStorage.setItem(id, JSON.stringify(supervisor));
}
function getObj(key) {
var supervisor = JSON.parse(localStorage.getItem(key));
return supervisor;
}
So, I'm trying to add to the record whenever an user clicks in a checkbox. And this is where the problem happens. Here's the function:
function checkboxClicked(idCbx) {
var idSection = $("#ContentPlaceHolder1_hdnActualField").val();
var supervisor = getObj(idSection);
console.log(typeof (supervisor)); //Returns object, everythings fine
console.log(typeof (supervisor.change)); //Returns boolean
supervisor.change = true;
var idCheck = idCbx.split("_")[2]; //I just want a part of the name
console.log(typeof(supervisor.selections)); //Prints object
console.log("Length " + supervisor.selections.size); //Undefined!
supervisor.selections.set(idCheck, true); //Error! Note: The true is just for testing purposes
setObj(idSection, supervisor);
}
What am I doing wrong? Thanks!
Please look at this example, I removed the jquery id discovery for clarity. You'll need to adapt this to meet your needs but it should get you mostly there.
const mapToJSON = (map) => [...map];
const mapFromJSON = (json) => new Map(json);
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
this.change = false;
this.selections.set('blah', 'hello');
}
Supervisor.from = function (data) {
const id = data.id;
const supervisor = new Supervisor(id);
supervisor.verif = data.verif;
supervisor.selections = new Map(data.selections);
return supervisor;
};
Supervisor.prototype.toJSON = function() {
return {
id: this.id,
verif: this.verif,
selections: mapToJSON(this.selections)
}
}
const expected = new Supervisor(1);
console.log(expected);
const json = JSON.stringify(expected);
const actual = Supervisor.from(JSON.parse(json));
console.log(actual);
If you cant use the spread operation in 'mapToJSON' you could loop and push.
const mapToJSON = (map) => {
const result = [];
for (let entry of map.entries()) {
result.push(entry);
}
return result;
}
Really the only thing id change is have the constructor do less, just accept values, assign with minimal fiddling, and have a factory query the dom and populate the constructor with values. Maybe something like fromDOM() or something. This will make Supervisor more flexible and easier to test.
function Supervisor(options) {
this.id = options.id;
this.verif = null;
this.selections = options.selections || new Map();
this.change = false;
}
Supervisor.fromDOM = function(id) {
const selections = new Map();
const children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children();
for (var i = 0; i < children.length; i++) {
if (i % 2 == 0) {
var checkbox = children[i];
var idCheck = checkbox.id.split("_")[2];
selections.set(idCheck, false);
}
}
return new Supervisor({ id: id, selections: selections });
};
console.log(Supervisor.fromDOM(2));
You can keep going and have another method that tries to parse a Supervisor from localStorageand default to the dom based factory if the localStorage one returns null.
I am being asked to have a to do list and save each task (that the user supplies as well as original) through local storage. My teacher did a very simple demo on something completely different and I spent a few hours trying to figure it out. When I looked at the solution, I honestly cannot figure it out. It looks really complicated, and I don't even know where to start. If anyone can give me any hints, that would be awesome!
My code:
let ul = document.querySelector('ul');
let newItem = document.querySelector('input[type=text]');
let checkbox = document.createElement('input');
checkbox.setAttribute('type', 'checkbox');
function output() {
let newTodo = document.createElement('li');
newTodo.innerText = newItem.value;
newTodo.classList.add('todo');
let ulAppend = ul.append(newTodo);
ul.append(newTodo);
let checkboxAppend = newTodo.append(checkbox);
newTodo.append(checkbox);
newItem.value = '';
}
let button = document.querySelector('.btn');
button.addEventListener('click', output);
ul.addEventListener('click', function(e) {
if (e.target.tagName === 'LI') {
e.target.remove();
} else if (e.target.tagName === 'INPUT') {
e.target.parentElement.classList.toggle('finished');
}
});
My teacher's code/local storage solution:
const todoForm = document.getElementById("newTodoForm");
const todoList = document.getElementById("todoList");
// retrieve from localStorage
const savedTodos = JSON.parse(localStorage.getItem("todos")) || [];
for (let i = 0; i < savedTodos.length; i++) {
let newTodo = document.createElement("li");
newTodo.innerText = savedTodos[i].task;
newTodo.isCompleted = savedTodos[i].isCompleted ? true : false;
if (newTodo.isCompleted) {
newTodo.style.textDecoration = "line-through";
}
todoList.appendChild(newTodo);
}
todoForm.addEventListener("submit", function(event) {
event.preventDefault();
let newTodo = document.createElement("li");
let taskValue = document.getElementById("task").value;
newTodo.innerText = taskValue;
newTodo.isCompleted = false;
todoForm.reset();
todoList.appendChild(newTodo);
// save to localStorage
savedTodos.push({ task: newTodo.innerText, isCompleted: false });
localStorage.setItem("todos", JSON.stringify(savedTodos));
});
todoList.addEventListener("click", function(event) {
let clickedListItem = event.target;
if (!clickedListItem.isCompleted) {
clickedListItem.style.textDecoration = "line-through";
clickedListItem.isCompleted = true;
} else {
clickedListItem.style.textDecoration = "none";
clickedListItem.isCompleted = false;
}
// breaks for duplicates - another option is to have dynamic IDs
for (let i = 0; i < savedTodos.length; i++) {
if (savedTodos[i].task === clickedListItem.innerText) {
savedTodos[i].isCompleted = clickedListItem.isCompleted;
localStorage.setItem("todos", JSON.stringify(savedTodos));
}
}
});
Even though my code is more simpler (at least from what I can tell), it works exactly as his code does.
Local storage saves a JSON object to the user's computer. You should create an array of todos, append that array with every new todo, then set that item to local storage.
let ul = document.querySelector('ul');
const savedTodos = JSON.parse(localStorage.getItem("todos")) || []; // Retrieves local storage todo OR creates empty array if none exist
let newItem = document.querySelector('input[type=text]');
let checkbox = document.createElement('input');
checkbox.setAttribute('type', 'checkbox');
function output() {
let newTodo = document.createElement('li');
newTodo.innerText = newItem.value;
newTodo.classList.add('todo');
ul.append(newTodo);
newTodo.append(checkbox);
savedTodos.push({task: newItem.value, isCompleted: false}); // Appends the new todo to array
localStorage.setItem("todos", JSON.stringify(savedTodos)); //Converts object to string and stores in local storage
newItem.value = '';
}
I've annotated the solution you posted with some comments to help you step through it.
// Retrieve elements and store them in variables
const todoForm = document.getElementById("newTodoForm");
const todoList = document.getElementById("todoList");
// Get data stored in localStorage under the key "todos".
// The data type will be a string (local storage can only store strings).
// JSON is a global object that contains methods for working with data represented as strings.
// The `||` syntax is an OR operator and is used here to set an empty array as a fallback in case `localStorage` is empty
const savedTodos = JSON.parse(localStorage.getItem("todos")) || [];
// Create a loop the same length as the list of todos
for (let i = 0; i < savedTodos.length; i++) {
// Create an <li> element in memory (does not appear in the document yet)
let newTodo = document.createElement("li");
// Set the inner text of that new li with the contents from local storage.
// The savedTodos[i] is accessing data in the localStorage array.
// The [i] is a different number each loop.
// The `.task` is accessing 'task' property on the object in the array.
newTodo.innerText = savedTodos[i].task;
// Create a new property on the element called `isCompleted` and assign a boolean value.
// This is only accessible in code and will not show up when appending to the DOM.
newTodo.isCompleted = savedTodos[i].isCompleted ? true : false;
// Check the value we just set.
if (newTodo.isCompleted) {
// Create a style for the element if it is done (strike it out)
newTodo.style.textDecoration = "line-through";
}
// Actually append the new element to the document (this will make it visible)
todoList.appendChild(newTodo);
}
// `addEventListener` is a function that registers some actions to take when an event occurs.
// The following tells the browser - whenever a form is submitted, run this function.
todoForm.addEventListener("submit", function(event) {
// Don't try to send the form data to a server. Stops page reloading.
event.preventDefault();
// Create a <li> element in memory (not yet visible in the document)
let newTodo = document.createElement("li");
// Find element in the document (probably a input element?) and access the text value.
let taskValue = document.getElementById("task").value;
// Set the text of the <li>
newTodo.innerText = taskValue;
// Set a property on the <li> call `isCompleted`
newTodo.isCompleted = false;
// Empty out all the input fields in the form
todoForm.reset();
// Make the new <li> visible in the document by attaching it to the list
todoList.appendChild(newTodo);
// `push` adds a new element to the `savedTodos` array. In this case, an object with 2 properties.
savedTodos.push({ task: newTodo.innerText, isCompleted: false });
// Overwrite the `todos` key in local storage with the updated array.
// Use the JSON global object to turn an array into a string version of the data
// eg [1,2,3] becomes "[1,2,3]"
localStorage.setItem("todos", JSON.stringify(savedTodos));
});
// This tells the browser - whenever the todoList is clicked, run this function.
// The browser will call the your function with an object that has data about the event.
todoList.addEventListener("click", function(event) {
// the `target` of the event is the element that was clicked.
let clickedListItem = event.target;
// If that element has a property called `isCompleted` set to true
if (!clickedListItem.isCompleted) {
// update the styles and toggle the `isCompleted` property.
clickedListItem.style.textDecoration = "line-through";
clickedListItem.isCompleted = true;
} else {
clickedListItem.style.textDecoration = "none";
clickedListItem.isCompleted = false;
}
// The code above changes the documents version of the data (the elements themselves)
// This loop ensures that the array of todos data is kept in sync with the document
// Loop over the array
for (let i = 0; i < savedTodos.length; i++) {
// if the item in the array has the same text as the item just clicked...
if (savedTodos[i].task === clickedListItem.innerText) {
// toggle the completed state
savedTodos[i].isCompleted = clickedListItem.isCompleted;
// Update the localStorage with the new todos array.
localStorage.setItem("todos", JSON.stringify(savedTodos));
}
}
});
Keep in mind, there are 2 sources of state in your todo list. One is how the document looks, and the other is the array of todos data. Lots of challenges come from making sure these 2 stay in sync.
If somehow the document showed one of the list items as crossed out, but your array of data shows that all the todos are not completed, which version is correct? There is no right answer here, but state management will be something you might consider when designing apps in the future. Redux is a good js library with a well understood pattern that helps solve this problem. Hope this last comment doesn't confuse too much. Best of luck!
The important part is in (de)serializing the data. That means:
reading from localStorage (JSON.parse(localStorage.getItem("todos")) || [])
We add the default [] because if the todos key does not exist, we will get null and we expect a list
saving to localStorage (localStorage.setItem("todos", JSON.stringify(savedTodos)))
We need JSON.parse and its complementary operation JSON.stringify to parse and save strings because localStorage can store only strings.
In your case you need to read the data from localStorage and render the initial list. To save it to localStorage, again, you have to serialize the data. See the below snippets (link to working JSFIDDLE, because the below example does not work in the StackOverflow sandbox environment):
let ul = document.querySelector('ul');
let newItem = document.querySelector('input[type=text]');
const Store = {
serialize () {
return [].slice.call(document.querySelectorAll("li")).map(c => {
return {
text: c.textContent,
finished: c.querySelector("input").checked
}
})
},
get () {
return JSON.parse(localStorage.getItem("todos")) || []
},
save () {
return localStorage.setItem("todos", JSON.stringify(Store.serialize()))
}
}
const firstItems = Store.get()
firstItems.forEach(it => {
output(it.text, it.finished)
})
function output(v, finished) {
let newTodo = document.createElement('li');
newTodo.innerText = v || newItem.value;
newTodo.classList.add('todo');
let ulAppend = ul.append(newTodo);
ul.append(newTodo);
// Create a checkbox for each item
let checkbox = document.createElement('input');
if (finished) {
checkbox.checked = true
}
checkbox.setAttribute('type', 'checkbox');
let checkboxAppend = newTodo.append(checkbox);
newTodo.append(checkbox);
newItem.value = '';
}
let button = document.querySelector('.btn');
button.addEventListener('click', () => {
output()
Store.save()
});
ul.addEventListener('click', function(e) {
if (e.target.tagName === 'LI') {
e.target.remove();
} else if (e.target.tagName === 'INPUT') {
e.target.parentElement.classList.toggle('finished');
}
// Update the value in localStorage when you delete or add a new item
Store.save()
});
<ul></ul>
<input type="text" /> <button class="btn">Submit</button>
I have added the Store variable to simplify the way you get and set the data in localStorage.
The serialize method will read the TODOs from the list. document.querySelectorAll("li") returns a NodeList, but by doing [].slice.call(...) we convert it to an Array.
I need to go to the next URL after a correct answer on a quiz. I have an assignment where I'm creating a Quiz game with questions from a server at the university. When the person is correct the game gets the next question on the server with a XMLHttpRequest.
How can I somehow us a 'nextURL' here or is there no such term?
function Question () {
let quizQuestion = new window.XMLHttpRequest()
quizQuestion.open('GET', 'http://vhost3.lnu.se:20080/question/1')
quizQuestion.onload = function () {
let ourData = JSON.parse(quizQuestion.responseText)
let questionDiv = document.querySelector('#question')
questionDiv.innerText = ourData.question
}
quizQuestion.send()
answer()
}
function answer () {
let quizQuestion = new window.XMLHttpRequest()
let answerDiv = document.querySelector('#answer')
let button = document.createElement('button')
button.type = 'button'
button.setAttribute('id', 'send')
button.innerText = 'Answer'
answerDiv.appendChild(button)
button.addEventListener('click', function () {
quizQuestion.open('POST', 'http://vhost3.lnu.se:20080/answer/1')
quizQuestion.setRequestHeader('Content-type', 'application/json')
quizQuestion.send(JSON.stringify({answer: inputText.value}))
quizQuestion.onreadystatechange = function () {
console.log(quizQuestion.response)
let ourAnswer = JSON.parse(quizQuestion.responseText)
let answerDiv = document.querySelector('#answer')
answerDiv.innerText = ourAnswer.message
}
})
}
So if the value in ({answer: inputText.value}) is correct I want to go to the next question, which in this case is in quizQuestion.open('GET', 'http://vhost3.lnu.se:20080/question/21')
Based on what you've written, it looks like "next URL" at any given moment would be next in a list that you've been given, and it's up to you to figure out how to retrieve the appropriate one after a correct answer.
We'll assume the question numbers in your assignment are non-sequential (moving from question 1 to question 21 in your example), and that no questions repeat. Is there a list of the questions in the order you need on the server? If the list is in an array, can you access it based on the index of the current question?
If not, assuming you already know the list of questions in the desired order, you can do this in your own code. Suppose you put your question numbers into an array, and store the current question number, like so:
let questionNums = [1,21,14,9,6,23]
let currQuestionNum = questionNums[0]
This lets you concatenate the desired question number onto your base URL as
'http://vhost3.lnu.se:20080/question/' + currQuestionNum.toString().
Then, when you've checked if the answer is correct, you can move to the next question in the array:
if (questionNums.indexOf(currQuestionNum)+1 != questionNums.length){
currQuestionNum = questionNums[questionNums.indexOf(currQuestionNum)+1]
}
else{
//end the quiz
}
To use this with the concatenation example above, you'll need to modify your Question and answer functions to accept question numbers as parameters:
function Question (questionNum) {
let quizQuestion = new window.XMLHttpRequest()
quizQuestion.open('GET', 'http://vhost3.lnu.se:20080/question/'+questionNum)
quizQuestion.onload = function () {
let ourData = JSON.parse(quizQuestion.responseText)
let questionDiv = document.querySelector('#question')
questionDiv.innerText = ourData.question
}
quizQuestion.send()
answer(questionNum)
}
function answer (questionNum) {
let quizQuestion = new window.XMLHttpRequest()
let answerDiv = document.querySelector('#answer')
//Local answerNum variable
let answerNum = questionNum
let button = document.createElement('button')
button.type = 'button'
button.setAttribute('id', 'send')
button.innerText = 'Answer'
answerDiv.appendChild(button)
button.addEventListener('click', function () {
quizQuestion.open('POST', 'http://vhost3.lnu.se:20080/answer/'+answerNum)
quizQuestion.setRequestHeader('Content-type', 'application/json')
quizQuestion.send(JSON.stringify({answer: inputText.value}))
quizQuestion.onreadystatechange = function () {
console.log(quizQuestion.response)
let ourAnswer = JSON.parse(quizQuestion.responseText)
let answerDiv = document.querySelector('#answer')
answerDiv.innerText = ourAnswer.message
}
})
}
Note the local answerNum variable - this is added so that, if quesitonNum changes before the anonymous function is called on a click event, the value won't be affected.
What am I doing wrong?
If I select the same element from Console and add a click listener… it works… however, this code doesn't work
const Template = require('./Template')
const mustache = require('mustache')
const DOMHelper = require('./DOMHelper')
class SymbolDefiner extends Template {
constructor (key, data) {
super(key)
this._data = data
}
render () {
super.render(arguments)
const parent = this._parent
const props = this._props
const eventListener = this._listener
const addSymbol = DOMHelper.createElement('button.btn.btn-primary', parent)
const btnText = document.createTextNode('Add Symbol')
addSymbol.appendChild(btnText)
console.log(addSymbol) // this log succeeds
addSymbol.addEventListener('click', function () {
console.log('xx')
})
}
}
module.exports = SymbolDefiner
The DOMHelper is just an easy function to add elements into the DOM by using very simple 'div#id.class-1.class-2' string.
Here is the code for DOMHelper:
const obj = {}
obj.createElement = function (selector, parent, props) {
const details = selector.split('#')
let eleName, eleId, classList
if (details.length > 1) {
// id is present
eleName = details[0]
const attribs = details[1].split('.')
eleId = attribs.shift()
classList = attribs
} else {
const attribs = details[0].split('.')
eleName = attribs.shift()
classList = attribs
}
const element = document.createElement(eleName)
element.setAttribute('id', eleId || '')
for (var i in classList) {
element.classList.add(classList[i])
}
if (props) {
for (var key in props) {
element.setAttribute(key, props[key])
}
}
if (parent) {
parent.appendChild(element)
}
return element
}
module.exports = obj
in the index.html page I added all the code to the script, this is based off of a blank electron quick getting start CLI from here
the only things I changed was I didn't separate out the DOMHelper, I just added it inline and I use obj.createElement() directly. It worked perfectly, so everything you have written is correct. The only possible thing might be checking every reference of the import require('./renderer.js') but most likely not since the file itself is blank for me.
so your code is all golden hopefully this helps where to look
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<!-- All of the Node.js APIs are available in this renderer process. -->
We are using Node.js <script>document.write(process.versions.node)</script>, Chromium
<script>document.write(process.versions.chrome)</script>, and Electron
<script>document.write(process.versions.electron)</script>.
<div id="parentNode"></div>
</body>
<script>
// You can also require other files to run in this process
require('./renderer.js')
var obj = {};
obj.createElement = function(selector, parent, props) {
const details = selector.split('#')
let eleName, eleId, classList
if (details.length > 1) {
// id is present
eleName = details[0]
const attribs = details[1].split('.')
eleId = attribs.shift()
classList = attribs
} else {
const attribs = details[0].split('.')
eleName = attribs.shift()
classList = attribs
}
const element = document.createElement(eleName)
element.setAttribute('id', eleId || '')
for (var i in classList) {
element.classList.add(classList[i])
}
if (props) {
for (var key in props) {
element.setAttribute(key, props[key])
}
}
if (parent) {
parent.appendChild(element)
}
return element
}
var parent = document.getElementById('parentNode');
const addSymbol = obj.createElement('button.btn.btn-primary', parent)
const btnText = document.createTextNode('Add Symbol')
addSymbol.appendChild(btnText)
console.log(addSymbol) // this log succeeds
addSymbol.addEventListener('click', function() {
console.log('xx')
})
</script>
</html>