Is this right way to write / execute ES6 Classes?

UI Output:
files

Html :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="overview"></div>
    <script src="/jsProject/save-text-as-file.js"></script>
</body> 
</html>

Js Script:

class SaveWrapper{
    constructor(){
        //Html wrapper
        this.html = document.getElementById('overview');
        this.parent = document.createElement('div');
        this.parent.style.cssText = 'background: #cfcfcf; padding: 20px; width: 350px; margin: 0 auto;';
        this.html.appendChild(this.parent);
        this.wrapper = document.createElement('div');
        this.parent.appendChild(this.wrapper);

        // Ui wrapper
        this.contectArea = document.createElement('div');
        this.contectArea.style.cssText = 'border: 1px solid #fff; padding: 20px; border-radius: 3px; margin-bottom: 25px';
        // Ui Textarea
        this.contectAreaInput = document.createElement('textarea');
        this.contectAreaInput.style.cssText = 'width: calc(100% - 38px); height:150px; padding: 20px; border:none; outline: none; resize: none';
        this.contectArea.appendChild(this.contectAreaInput);
        this.wrapper.appendChild(this.contectArea);
        this.contectAreaInput.addEventListener("input", ()=>{
            this.carCount.innerText = this.contectAreaInput.value.length;
        });
        // textarea word count
        this.carCount = document.createElement('span');
        this.contectArea.appendChild(this.carCount);

        // UI elements file name and select save options
        this.clientWeapper = document.createElement('div');
        this.clientWeapper.style.cssText = 'display: flex; margin-top:10px; margin-bottom:30px; align-items:center; justify-content:center';
        // File name
        this.nameWeapper = document.createElement('div');
        this.nameWeapper.style.cssText = 'width: calc(100% / 2 - 8px); margin-right: 40px;';
        this.nameLabel = document.createElement('label');
        this.nameLabel.innerText = 'File Name';
        this.nameWeapper.appendChild(this.nameLabel);
        // File name input
        this.nameInput = document.createElement('input');
        this.nameInput.style.cssText = 'display: block; width: 100%; padding: 10px';
        this.nameInput.type = 'text';
        this.nameInput.placeholder = 'Enter file name';
        this.nameWeapper.appendChild(this.nameInput);
        this.clientWeapper.appendChild(this.nameWeapper);

        // File save options
        this.saveWrapper = document.createElement('div');
        this.saveWrapper.style.cssText = 'width: calc(100% / 2 - 12px';
        this.saveLable = document.createElement('label');
        this.saveLable.innerText = 'Save as';
        this.saveWrapper.appendChild(this.saveLable);
        this.saveInputValues = [
            {id:'text/plain', name:'TEXT File (.txt)'}, 
            {id:'text/javascript', name:'JS File (.js)'}, 
            {id:'text/html', name:'HTML File (.html)'}, 
            {id:'application/xml', name:'XML File (.xml)'}, 
            {id:'application/json', name:'JSON File (.json)'}, 
            {id:'application/msword', name:'DOC File (.doc)'}
        ];
        this.saveInput = document.createElement('select');

        // dynamic option selection data
        for(let i = 0; i < this.saveInputValues.length; i++){
            this.saveInputOption = document.createElement('option');
            this.saveInputOptionTxt = document.createTextNode(this.saveInputValues[i].name);
            this.saveInputOption.appendChild(this.saveInputOptionTxt);
            this.idNames = this.saveInputValues[i].name;
            this.ids = this.idNames.split(' ');
            this.ids.pop();
            this.ikd = this.ids.join('-');
            this.saveInputOption.setAttribute('id', this.ikd);
            this.saveInputOption.setAttribute('value', this.saveInputValues[i].id);
            this.saveInput.style.cssText = 'display: block; width: 100%; padding: 10px';
            this.saveInput.setAttribute('title', 'File selection');
            this.saveInput.appendChild(this.saveInputOption);
        };
        this.saveInput.addEventListener('change', () => {
            this.selectValue = this.saveInput.options[this.saveInput.selectedIndex].text;  
            this.selectText = this.selectValue.split(' ');
            this.selectText.pop(' ');
            this.text = this.selectText.join(' ');
            this.saveBtn.innerText = `Save as ${this.text}`;
        });
        this.saveWrapper.appendChild(this.saveInput);
        this.clientWeapper.appendChild(this.saveWrapper);
        this.parent.appendChild(this.clientWeapper);

        // Save wrapper
        this.saveBtn = document.createElement("button");
        this.saveBtn.setAttribute("type", "submit");
        this.saveBtn.setAttribute("id", "saveBtn");
        this.saveBtn.innerText = `Save`;
        this.saveBtn.style.cssText = "display: block; width: 100%; padding: 10px; font-size: 20px; cursor: pointer; background-color: green;";
        this.parent.appendChild(this.saveBtn);

        // File name required 
        this.errorText= document.createElement('label');
        this.errorText.innerText = ' **Please enter a name';
        this.errorText.style.color = ' red';
        
        // Save Btn clicked
        this.saveBtn.addEventListener("click", () => {
            if(!this.nameInput.value) {
                this.nameLabel.append(this.errorText);
            } else {
                this.errorText.remove();
                this.blob = new Blob([this.contectAreaInput.value], {type: this.saveInput.value});
                this.fileUrl = URL.createObjectURL(this.blob);
                this.link = document.createElement('a');
                this.link.href = this.fileUrl;
                this.link.download = this.nameInput.value;
                this.link.click( );
                this.nameInput.value = null;
            };
        });
    } 
}
const wrapper = new SaveWrapper();

According to MDN, classes are a template for building objects. This seems more like one big function rather than a template for building objects, so why not just use a function?

1 Like

In writing code, thoughted if i use eS6class then my object property will not accessible/mutation in global/window, no hassle for hoisting, also give flexibility to create/convert as module. I can use constructor function instead eS6class but both are produce object :neutral_face:

Hello.

JS is not my best expertise but I would probably go with functions too.

As @eelsholz mention, this looks like a big function which makes it difficult to read.

Make small, digest functions.

What I would also do is rename overview as parent. Then build from there.
The reason behind that is you intend to generate a content into a div but you seem to create a div that will hold the said content.

So it looks like that in my mind :slight_smile:

<div id="overview">
	<div id="parent">
		// further content ...
	</div>
</div>

Unless you foresee to have sibling elements in the same level, I would just go like this.

<div id="parent">
	// further content ...
</div>

I also find naming that overview as html pretty misleading. This is what I would name the actual <html> element.

Now if you still want to go with classes, I’d suggest you refactor it and just remain minimal with declaring/initializing your different fields in the constructor. This is their actual function. Then use methods to do the rest.

I guess you do it for sports, so it’s OK but it is better to think about CSS classes ahead and work with that.

That’s pretty much what I could say.

You’d probably do a similar thing with jQuery or with a front-end framework at all later.
Regards.

1 Like