Pre-Christmas sale Swift week
Save up to 80 % on Swift e-learning! Only this week!
Christmas are almost here! Get up to 20 % extra points for free! More info

Lesson 8 - Finishing an Object-Oriented Diary In JavaScript

In the previous lesson, Improving the Object-Oriented Diary In JavaScript, we added a few more features to our object-oriented diary in JavaScript. Today, we're going to continue in a similar way and complete the application.

Changing the done Property Of the Entries

The last button we're missing is the button to accomplish the task.

Parametrization

Because the button to make the task done will look and work very much like the delete button, we won't add duplicate code to our application unnecessarily, but we'll rather modify the existing one. Let's create a helper method to insert a task button:

_addButton(title, callback) {
    const button = document.createElement("button");
    button.onclick = callback;
    button.innerText = title;
    this.printElement.appendChild(button);
}

The _addButton() method does exactly what we did to add the delete button. However, the button's title and handler method are set from a parameter, so we can use the method to insert different buttons with different titles and handlers.

We can replace all the code for the remove button in the printEntries() method with the following one:

this._addButton("Delete", () => {
    if (confirm("Are you sure you want to remove the task?")) {
        this.entries = this.entries.filter(e => e !== entry); // Keep everything not equal to the entry variable
        this.saveEntries();
        this.printEntries();
    }
});

We created the helper method intentionally now and not before adding the first button. It was to show how to handle a situation when you need to put some very similar code to your application. You move the existing code to an auxiliary method and parameterize it. Redundant code violates the DRY principle, one of the most important rules for high-quality object design.

Private Methods

Note that the method name starts with an underscore. Auxiliary methods that no one should call on our class from the outside should be ideally hidden. Unfortunately, JavaScript currently doesn't allow to encapsulate methods easily. In the course, we'll show that it's possible, but only using hacks, which will make the code confusing. Marking private properties and methods with an underscore is a quite good habit and it's used in other languages that don't support access modifiers as well.

In order for our code to be really well written, we'll mark the _setEvents() method with an underscore as well. It's also just an auxiliary functionality that shouldn't be called from the outside.

_setEvents() {
    // ...
}

Remember to rename the method call in the constructor:

constructor(language = "en-US") {
    // ...
    this._setEvents();
}

The Button To Make the Entry Done

After a small detour, let's go back to the new button. We'll add it using the prepared _addButton() method:

this._addButton("Mark as " + (entry.done ? "done" : "not done"), () => {
    entry.done = !entry.done;
    this.saveEntries();
    this.printEntries();
});

You can try the result :)

Sanitizing User Inputs

So we have a fully-functional diary using localStorage. All we are missing is to sanitize user inputs, because if the user doesn't enter a date, it will be listed as "Invalid Date". So we'll modify the _setEvents() method and make a simple validation there. Because <input type ="date"> returns an empty string as the value if the date is not provided, it's not difficult to alert the user about this problem:

_setEvents() {
    this.confirmButton.onclick = () => { // this now stays this
        if (this.dateInput.value !== "") {
            const entry = new Entry(this.nameInput.value, this.dateInput.value);
            this.entries.push(entry);
            this.saveEntries();
            this.printEntries();
        } else
            alert("You must fill in the date!");
    };
}

So, if the date isn't entered correctly, we notify the user using the alert() function to enter it correctly, otherwise we save the new entry.

Design

Now there's just some design left, which we can go through quickly while editing the JS only a little. We'll create a css/ folder and a new style.css file in the project. It's contents will be as follows:

* {
    font-family: Segoe UI Light, "Calibri Light", sans-serif;
}

button {
    padding: 10px 16px;
    font-weight: 600;
    background: #2792e0;
    color: #fff;
    border: none;
    cursor: pointer;
    transition: .5s;
}

button:hover {
    background: #2954c2;
}

button:active {
    background: #204199;
}

input {
    min-width: 250px;
    padding: 8px;
    border: 1px solid #909090;
    height: 20px;
}

button, input {
    margin-top: 1rem;
    outline: none;
}

.task {
    width: 75%;
    padding: 2rem;
    margin: 1rem auto;
    border: 1px solid #c5c5c5;
    box-shadow: 2px 2px 4px #b1b1b1;
}

We'll link the style in index.html:

<link href="css/style.css" rel="stylesheet">

And now we can easily adjust how each entry is printed:

this.printElement.innerHTML += `<h4>${entry.name}</h4>
    <br>task ${!entry.done ? "not " : ""}done`;
    // ...
this.printElement.innerHtml = `<div class="task">` + this.printElement.innerHtml  + `</div>`;

The result:

Your page
localhost

And it's done! :) So we have a pretty looking diary that stores data and can be used in real life :) If you havd any problem with anything, you can download the complete source code below and find your error.

Next time, in the lesson Inheritance And Polymorphism In JavaScript, we'll move further and look at inheritance and polymorphism.


 

 

Activities (2)

 

 

Comments

To maintain the quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it's free.

No one has commented yet - be the first!