Hello World!, this article is a project template. More like a complete project but just Javascript (i.e no HTML or CSS).
I have not been a fan of JavaScript Objects and Classes, not that I don't understand the fundamentals but I found it not too necessary to worry about as I considered Functional Programming as a simpler approach. These have been my thoughts for long and all my projects so far were all with functional programming, but when I took the CodeCademy's JavaScript Course; I discovered my love for Object-Oriented Programming, and for me, I think it's way simpler, especially if using Getters and Setters.
So after I was done with the JavaScript Objects module of the course, there was this project they (CodeCademy) were going to build i.e Meal Maker. I couldn't access it as a free user, but I understood the purpose of making the project i.e to make use of Getters and Setters in a real-life project.
There was one problem, I had no idea of what a Meal Maker does or how it usually works, but I had a great idea to practice Getters and Setters; an Appointment Booking App. Brilliant right? Yeah, I know, so what it does is simply book appointments for people with business users.
Say I am Elon Musk (which I am not), I can create an account with this app as such other users can book appointments with me.
Now Elon Musk is not gonna be the only user with a business account, we will use Factory Functions (not Classes) to duplicate and have any amount of business account we want.
This app may be basic, but it contains all the difficult parts of making an appointment booking app. Have in mind that the purpose of this article is not to show you one of the ways you can make an appointment booking app, but to show you how Getters and Setters can be very handy in projects like this.
If you do not know JavaScript Getters and Setters or JavaScript Objects, i recommend going through CodeCademy's JS Objects Course.
Enough with the writing, let's get to coding. Scroll down to see the complete code or simply visit GitHub for the code.
// alert: am tired of using John Doe, i wanna use Elon Musk
const elonMusk = {
_hoursfree: [10, 12, 9], // currently hard-coded, but will change in time
};
The reason for the underscore (_
) before the hoursFree
property is because I intentionally do not want that to be accessed directly. A programmer should know that and keep to that. But we would need to access the hours Elon Musk is free, to do that we will use JavaScript Getters i.e
const elonMusk = {
_hoursFree: [10, 12, 9],
get hoursFree() {
return this._hoursFree; // can now be accessed legitimately
},
};
Now we want to add more properties to the elonMusk object
const elonMusk = {
_hoursFree: [10, 12, 9],
acceptedPurpose: 'any',
pendingMeetongs: [], // meetings yet to be approved by Elon Musk
declinedMeetings: [], // meetings not approved by Elon Musk
approvedMeetings: [], // meetings approved by Elon Musk
canceledMeetings: [], // meetings already approved but later canceled maybe something came up
_feedback: '', // feedback to the booking user (user making the booking)
get hoursFree() {
return this._hoursFree;
},
get feedBack() {
return this._feedback); // simply return a feedback
},
};
The acceptedPurpose
property simply represents the current purpose Elon Musk wants to accept. Let's say the design of the app has in it that the purpose of a meeting can be set weekly or daily as the case may be; by Elon Musk. Say the acceptedPurpose
options provided by the app is business, family, fun, or any
So for now we are assuming Elon Musk is available for any type of meeting be it a business meeting, fun meeting, family meeting. Currently hard-coded will change later.
Now let's begin using Setters. Say we want to book a meeting with Elon Musk, how would we do it
// still in the elonMusk object, just under the feedBack getter
set newMeeting(time) {
if (this._hoursFree.indexOf(time) !== -1) {
this.pendingMeetings.push(time);
this._feedback =
'Your meeting was sent successfully. Elon Musk can now review and approve or decline';
} else {
this._feedback = 'Time not suitable for Elon Musk';
}
},
// outside of the elonMusk object
elonMusk.newMeeting = 10
console.log(elonMusk.feedBack)
This is very basic, there is more to setting a meeting which we will get back to. But first, let's analyze this;
- We checked if the time provided by the user is suitable with Elon Musk by comparing it to his provided free hours.
- If true, we added the time to the
pendingMeetings
array. and gave a feedback. - If false, we simply return a feedback to the user making this booking.
A meeting should not just contain the time, Elon Musk of course would need more information about this meeting i.e
Creating Meetings:
// still in the elonMusk object, just under the feedBack getter
set newMeeting(meeting) {
const { name, time, purpose } = meeting;
if (
this._hoursFree.indexOf(time) !== -1 &&
this.acceptedPurpose === 'any'
) {
this.pendingMeetings.push(meeting);
this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
} else if (this.acceptedPurpose === purpose.toLowerCase()) {
this.pendingMeetings.push(meeting);
this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
} else {
this._feedback = `${name}, this meeting is not suitable for Elon Musk`;
}
},
}
// outside of the elonMusk object
const clientMeeting = {id: 10, name: 'Bill Gates', time: 10, purpose: 'fun'};
elonMusk.newMeeting = clientMeeting;
console.log(elonMusk.feedBack);
We just made it a little spicy, shouldn't be difficult to comprehend. We included id, name, and purpose to time to make up the meeting object.
The meeting will be sent successfully if;
- the
acceptedPurpose
of Elon Musk is set to any and if the time of meeting from booking user is an item in thehoursFree
array of Elon Musk. - the
acceptedPurpose
of Elon Musk is similar to the purpose provided by the booking user
Now let's start approving, declining, and canceling meetings
Approving Meetings:
// still in the elonMusk object, right under the newMeeting
set approveMeeting(id) {
const previewingMeeting = this.pendingMeetings.filter((meeting) => {
return meeting.id === id; // filter out a meeting with its id and preview
})[0];
// approve previewing meeting and mark the previewingMeeting.time as a booked hour
this.approvedMeetings.push(previewingMeeting); // note that approvedMeetings with a 'd' is the array while approveMeeting without a 'd' is the setter
this._hoursFree.splice(this._hoursFree.indexOf(previewingMeeting.time), 1);
this._feedback = `${previewingMeeting.name}, your meeting has been approved, time of meeting: ${previewingMeeting.time}`;
},
// outside the elonMusk object;
elonMusk.newMeeting = clientMeeting //clientMeeting already declared before, scroll up
elonMusk.approveMeeting = clientMeeting.id;
console.log(elonMusk.feedBack);
The approveMeeting
setter is not having any conditional statement because it is meant to go straight to the point that is; approves the meeting. So this can be attributed to a button that says 'Approve Meeting', and when clicked by Elon, the meeting is approved and sent to the approvedMeetings
array.
If a meeting is approved, then it means a particular hour of Elon Musk has been booked. For that, we should endeavor to remove that booked hour to avoid two or more meetings booked to a particular hour. So for that, we used the splice method to remove that hour. You can log the current hoursFree
in the console to see the result of that i.e console.log(elonMusk.hoursFree)
Declining Meetings:
// still in the elonMusk object, right under the approveMeeting
set declineMeeting(id) {
const previewingMeeting = this.pendingMeetings.filter((meeting) => {
return meeting.id === id; // filter out a meeting with its id and preview
})[0];
this.declinedMeetings.push(previewingMeeting); // note that declinedMeetings with a 'd' is the array while declineMeeting without a 'd' is the setter
this._feedback = `${previewingMeeting.name}, your meeting was declined for reasons best known to Elon Musk`;
},
// outside the elonMusk object;
elonMusk.newMeeting = clientMeeting //clientMeeting already declared before, scroll up
elonMusk.declineMeeting = clientMeeting.id;
console.log(elonMusk.feedBack);
Something to note is that the delineMeeting
setter is a manual declining by Elon Musk, automatic declining was never added to the pendingBookings
array. In other words, bookings that were added to the pendingBookings
array are bookings that needed the business account owner (Elon Musk now) to review.
Automatic declining were done when either the time or purpose was not suitable for Elon Musk as provided in the hoursFree
array and the acceptedPurpose
string.
Canceling Meetings:
// still in the elonMusk object, right under the declineMeeting
set cancelMeeting(id) {
// the meeting has to be approved first
const previewingMeeting = this.approvedMeetings.filter((meeting) => {
return meeting.id === id;
})[0];
this._hoursFree.push(previewingMeeting.time); // make the hour of the canceled meeting a free hour
this.canceledMeetings.push(previewingMeeting); // add canceled meeting to the array of canceled meetings
this.approvedMeetings.splice(previewingMeeting, 1); // remove canceled meeting from approved meeting array
this._feedback = `${previewingMeeting.name}, your meeting with Elon Musk scheduled at ${previewingMeeting.time} has been canceled by Elon Musk. Don't ask me why? am not Elon Musk.`;
},
// outside the elonMusk object
elonMusk.newMeeting = clientMeeting; //clientMeeting already declared above
elonMusk.approveMeeting = clientMeeting.id; // approve meeting first
elonMusk.cancelMeeting = clientMeeting.id;
console.log(elonMusk.feedBack);
Pretty straightforward. One thing you could add is a setter to remove free hours from the hoursFree
array. If a meeting got canceled, the scheduled hour is automatically regarded as a free hour; but if Elon Musk doesn't want that hour to be free anymore He can simply click a button to remove that hour from being free (manually).
Requesting Free Hour Cancelation:
// still in the elonMusk object, right under the cancelMeeting
set requestHourCancelation(hr) {
if (this._hoursFree.indexOf(hr) !== -1) {
this._hoursFree.splice(this._hoursFree.indexOf(hr), 1);
}
}
// outside of the elonMusk object
elonMusk.requestHourCancelation = 10;
console.log(elonMusk.hoursFree);
Elon Musk Booking Object:
const elonMusk = {
_hoursFree: [10, 12, 9],
acceptedPurpose: 'family',
pendingMeetings: [], // meetings yet to be approved by Elon Musk
declinedMeetings: [], // meetings not approved by Elon Musk
approvedMeetings: [], // meetings approved by Elon Musk
canceledMeetings: [], // meetings already approved but later canceled maybe something came up
_feedback: '', // feedback to the booking user (user making the booking)
get hoursFree() {
return this._hoursFree;
},
get feedBack() {
this._feedback; // simply return a feedback.
},
set newMeeting(meeting) {
const { name, time, purpose } = meeting;
if (
this._hoursFree.indexOf(time) !== -1 &&
this.acceptedPurpose === 'any'
) {
this.pendingMeetings.push(meeting);
this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
} else if (this.acceptedPurpose === purpose.toLowerCase()) {
this.pendingMeetings.push(meeting);
this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
} else {
this._feedback = `${name}, this meeting is not suitable for Elon Musk`;
}
},
set approveMeeting(id) {
const previewingMeeting = this.pendingMeetings.filter((meeting) => {
return meeting.id === id;
})[0];
// approve previewing meeting and mark the previewingMeeting.time as a booked hour
this.approvedMeetings.push(previewingMeeting); // note that approvedMeetings is the array while approveMeeting is the setter
this._hoursFree.splice(this._hoursFree.indexOf(previewingMeeting.time), 1);
this._feedback = `${previewingMeeting.name}, your meeting has been approved, time of meeting: ${previewingMeeting.time}`;
},
set declineMeeting(id) {
const previewingMeeting = this.pendingMeetings.filter((meeting) => {
return meeting.id === id;
})[0];
this.declinedMeetings.push(previewingMeeting); // note that declinedMeetings is the array while declineMeeting is the setter
this._feedback = `${previewingMeeting.name}, your meeting was declined for reasons best known to Elon Musk`;
},
set cancelMeeting(id) {
// the meeting has to be approved first
const previewingMeeting = this.approvedMeetings.filter((meeting) => {
return meeting.id === id;
})[0];
this._hoursFree.push(previewingMeeting.time); // make the hour of the canceled meeting a free hour
this.canceledMeetings.push(previewingMeeting); // add canceled meeting to the array of canceled meetings
this.approvedMeetings.splice(previewingMeeting, 1); // remove canceled meeting from approved meeting array
this._feedback = `${previewingMeeting.name}, your meeting with Elon Musk scheduled at ${previewingMeeting.time} has been canceled by Elon Musk. Don't ask me why? am not Elon Musk.`;
},
set requestHourCancelation(hr) {
if (this._hoursFree.indexOf(hr) !== -1) {
this._hoursFree.splice(this._hoursFree.indexOf(hr), 1);
}
},
};
Have multiple business owners:
Say we want Bill Gate to have his business account and maybe Larry Page as well, we don't have to copy the codes in the elonMusk
object and start pasting; that's just unnecessary. Since the getters and setters in the elonMusk
object are going to be similar to the others (of course they should be), we would simply make instances for every user.
Usually, this can be done with JavaScript classes, but we will not use classes here (but we will in the future), instead, we will use factory functions which I recently learned from Codecademy.com.
This is how it's done.
// make a function and return all properties, getters and setters in the elonMusk object
function businessUser(businessName, _hoursFree, acceptedPurpose) {
// the three parameters above are properties of this object that are going to vary with different business users
return {
businessName,
_hoursFree,
acceptedPurpose,
pendingMeetings: [], // meetings yet to be approved by Elon Musk
declinedMeetings: [], // meetings not approved by Elon Musk
approvedMeetings: [], // meetings approved by Elon Musk
canceledMeetings: [], // meetings already approved but later canceled maybe something came up
_feedback: '', // feedback to the booking user (user making the booking)
get hoursFree() {
return this._hoursFree;
},
get feedBack() {
this._feedback; // simply return a feedback.
},
set newMeeting(meeting) {
const { name, time, purpose } = meeting;
if (
this._hoursFree.indexOf(time) !== -1 &&
this.acceptedPurpose === 'any'
) {
this.pendingMeetings.push(meeting);
this._feedback = `${name}, your meeting was sent successfully. ${this.businessName} can now review and approve or decline`;
} else if (this.acceptedPurpose === purpose.toLowerCase()) {
this.pendingMeetings.push(meeting);
this._feedback = `${name}, your meeting was sent successfully. ${this.businessName} can now review and approve or decline`;
} else {
this._feedback = `${name}, this meeting is not suitable for ${this.businessName}`;
}
},
set approveMeeting(id) {
const previewingMeeting = this.pendingMeetings.filter((meeting) => {
return meeting.id === id;
})[0];
// approve previewing meeting and mark the previewingMeeting.time as a booked hour
this.approvedMeetings.push(previewingMeeting); // note that approvedMeetings is the array while approveMeeting is the setter
this._hoursFree.splice(
this._hoursFree.indexOf(previewingMeeting.time),
1
);
this._feedback = `${previewingMeeting.name}, your meeting has been approved, time of meeting: ${previewingMeeting.time}`;
},
set declineMeeting(id) {
const previewingMeeting = this.pendingMeetings.filter((meeting) => {
return meeting.id === id;
})[0];
this.declinedMeetings.push(previewingMeeting); // note that declinedMeetings is the array while declineMeeting is the setter
this._feedback = `${previewingMeeting.name}, your meeting was declined for reasons best known to ${this.businessName}`;
},
set cancelMeeting(id) {
// the meeting has to be approved first
const previewingMeeting = this.approvedMeetings.filter((meeting) => {
return meeting.id === id;
})[0];
this._hoursFree.push(previewingMeeting.time); // make the hour of the canceled meeting a free hour
this.canceledMeetings.push(previewingMeeting); // add canceled meeting to the array of canceled meetings
this.approvedMeetings.splice(previewingMeeting, 1); // remove canceled meeting from approved meeting array
this._feedback = `${previewingMeeting.name}, your meeting with ${this.businessName} scheduled at ${previewingMeeting.time} has been canceled by ${this.businessName}. Don't ask me why? am not ${this.businessName}.`;
},
set requestHourCancelation(hr) {
if (this._hoursFree.indexOf(hr) !== -1) {
this._hoursFree.splice(this._hoursFree.indexOf(hr), 1);
}
},
};
}
Everything in the businessUser function is all we need to create a million functioning business accounts. Let's try creating three and accessing their properties
const larryPage = businessUser('Larry Page', [15, 12, 9], 'any');
console.log(larryPage.hoursFree);
const willSmith = businessUser('Will Smith', [9, 10], 'fun');
console.log(willSmith.hoursFree);
const billGates = businessUser(
'Bill Gates',
[11, 10, 9, 8, 7, 6, 5, 4, 3, 2],
'any'
); // Mr. Gates is always free.
console.log(billGates.hoursFree);
Get the code on GitHub, Building a Project with JavaScript Objects. Don't forget to leave a star.
Conclusion
It is important to note that all of the setters above can be replaced with methods and will still work fine, but since we are focusing on setters we might as well use it all through. I intend to make a library on my next post using JavaScript Classes and Methods, it is completely different from this and more advanced and enjoyable than this. It's gonna be fun.
I hope you learned a lot as I did. Heads up, I have something (a project) awesome coming your way soon as a developer (you're gonna love it). Thanks for reading, don't forget to leave your comments below if you have any complaints or stories (I love stories), also don't forget to share with your colleagues. If you wish to support me then you can buy me a coffee. I appreciate.
Top comments (7)
Just started objects on Codecademy so this article is an awesome head start as to where ill be end of chapter. Any recommendations for self taught coders who are just learning the basics of OOP?
Oh. Good for you.
What I will recommend is to go through their project building. Try to build a project from what you learn for each module. It's gonna help you understand it better.
Thanks for the response
good article, really appreciated.
thanks :)
Thank you.
I have never use like it. i saw on git and i think i will use on jobs. Thanks
Ok that's nice