In regards to the School Catalog exercise, the SchoolCatalog class is not an extension of the School Class.
It should have objects of schools. How does that work?
Can you show what the SchoolCatalog class should look like ?
Many thanks!
In regards to the School Catalog exercise, the SchoolCatalog class is not an extension of the School Class.
It should have objects of schools. How does that work?
Can you show what the SchoolCatalog class should look like ?
Many thanks!
Could you give me a link to your problem? I could help you more if you showed me it.
Hi ,
here is the link : https://www.codecademy.com/courses/introduction-to-javascript/projects/school-catalog
The questions is about the additional execercise under point 19. : * Create a class called SchoolCatalog
that holds a collection of schools. Create an instance of SchoolCatalog
for primary, middle, and high schools.
I am trying to put together that class, but am stuck on the fact that it should hold âschool objectsâ. Can you show me what that class should look like?
Many thanks
Sorry, but I have not gotten to that lesson, so I just found out it wonât let me in. Please type the directions I guess, and then I will be able to help you. Sorry for complicating things
We want three instances of the SchoolCatalog classâŚ
class SchoolCatalog {
}
primary = new SchoolCatalog();
middle = new SchoolCatalog();
high = new SchoolCatalog();
Thatâs the skeleton. Now we need to visualize the data that goes into each instance. The idea would appear to be storing an array of schools in each instance so that it can polled and printed.
Question: Should this class need a constructor method? Or is a class variable adequate?
class SchoolCatalog {
_list = [];
get list () {
}
addSchool (school) {
}
}
This is not a how-to, but a sketch to help organize our ideas. What if we want the array to consist of School objects?
One consideration would be to create the instance of a School, first, then pass that object to the SchoolCatalog instance that applies to its level. For now this will be a manual process.
Letâs insist upon get list()
returning the full list of objects. This way we can use the getter in our instance methods be able to drill down into each object.
return this._list;
In answer to the question about a constructor, turns out we do need one.
constructor () {
this._list = [];
}
In the addSchool
method, we are given a School
object from an outside instance of that class. The new array element will be a reference to that object. The reference added to the SchoolCatalog instance is not a copy, but a reference to that actual instance. In other words, weâre not creating data, only accessing it.
The data in this class is merely a pointer to data in the School class and its subsidiaries.
this.list.push(school); // uses the getter
Remember quickFacts
? We can write our own for this class.
quickFacts(x) {
console.log(
`${x.name} educates ${x.numberOfStudents} ${x.level} school students.`
);
}
Hi mtf,
Thank you for clarifying, much appreciated.
PS It might be useful to add the how-to of that particular class (SchoolCatalog) to the tutorial, because it touches OOP logic that was not yet explained.
As stated earlier, this is a sketch, but we can rustle up some trial code to help give us some direction.
Start with some HighSchool instancesâŚ
const alSmith = new HighSchool(
'Al E. Smith',
415,
['Baseball', 'Basketball', 'Volleyball', 'Track and Field']
);
const anHenday = new HighSchool(
'Anthony Henday',
515,
['Baseball', 'Basketball', 'Volleyball', 'Track and Field', 'Hockey']
);
const salisbury = new HighSchool(
'Salisbury',
315,
['Baseball', 'Basketball', 'Volleyball', 'Track and Field', 'Hockey']
);
Given this class definition,
class SchoolCatalog {
constructor () {
this._list = [];
}
get list () {
return this._list;
}
addSchool (school) {
this.list.push(school);
}
quickFacts (x) {
console.log(
`${x.name} educates ${x.numberOfStudents} ${x.level} school students.`
);
}
print () {
this.list.forEach(this.quickFacts);
}
}
and the three instances mentioned,
primary = new SchoolCatalog();
middle = new SchoolCatalog();
high = new SchoolCatalog();
we can now load up the high school instanceâŚ
high.addSchool(alSmith);
high.addSchool(salisbury);
high.addSchool(anHenday);
and now we can print all the quickFactsâŚ
high.print();
Al E. Smith educates 415 high school students. Salisbury educates 315 high school students. Anthony Henday educates 515 high school students.
This is still very basic, as we need to give our class some intuition so schools of one level cannot be added to the list of another. That logic will take some thought.
const lorraineHansbury = new PrimarySchool(
'Lorraine Hansbury',
514,
'Students must be picked up by a parent, guardian, or a family member over the age of 13.'
);
high.addSchool(lorraineHansbury);
LevelMismatchError: Cannot insert Lorraine Hansbury school into the list.
[ Edited to reveal more logic. 181218 1828h UTC -7h ]
Hi mtf,
Great, I understand now.
Thank you so much for taking the time to clarify, much appreciated.
Best
Marco
Please let us know when you have the logic to produce the above output.
Al E. Smith has 415 high school students.
Intramural sports programs:
Baseball, Basketball, Volleyball, Track and Field
Salisbury has 315 high school students.
Intramural sports programs:
Baseball, Basketball, Volleyball, Track and Field, Hockey
Anthony Henday has 515 high school students.
Intramural sports programs:
Baseball, Basketball, Volleyball, Track and Field, Hockey
or should I say, all the above notwithstanding?
Hi Roy,
Thank you for following up.
This is what I put together
class SchoolCatalog{
constructor(){
this._list = [];
}
get list(){
return this._list;
}
addSchool(school){
this._list.push(school);
}
quickFacts(x){
const teams = (x.sportsTeams ? `Intramural sports programs ${x.sportsTeams}` : '');
console.log(`${x.name} educates ${x.numberOfStudents} ${x.level} school students. ${teams}`);
}
print(){
this._list.forEach(this.quickFacts);
}
}
class School {
constructor(name, level, numberOfStudents){
this._name = name;
this._level = level;
this._numberOfStudents = numberOfStudents;
}
get name(){
return this._name;
}
get level(){
return this._level;
}
get numberOfStudents(){
return this._numberOfStudents;
}
set numberOfStudents(value){
if(value.isNaN){
console.log('Invalid input: numberOfStudents must be set to a number.');
}
else{this._numberOfStudents = value;}
}
quickFacts(){
console.log(`${this.name} educates ${this.numberOfStudents} students of the ${this.level} school level.`);
}
static pickSubstituteTeacher(substituteTeachers){
const randomIndex = Math.floor(Math.random()*substituteTeachers.length);
console.log(substituteTeachers[randomIndex]);
}
}
class PrimarySchool extends School {
constructor(name, numberOfStudents, pickupPolicy){
super(name, 'primary', numberOfStudents);
this._pickupPolicy = pickupPolicy;
}
get pickupPolicy(){
return this._pickupPolicy;
}
}
class HighSchool extends School {
constructor(name, numberOfStudents, sportsTeams){
super(name, 'high', numberOfStudents);
this._sportsTeams = sportsTeams;
}
get sportsTeams(){
return this._sportsTeams;
}
}
/*
School.pickSubstituteTeacher(['Jamal Crawford', 'Lou Williams', 'J. R. Smith', 'James Harden', 'Jason Terry', 'Manu Ginobli']);
*/
const alSmith = new HighSchool('Al E. Smith', 415, ['Baseball', 'Basketball', 'Volleyball', 'Track and Field']);
const anHenday = new HighSchool(
'Anthony Henday',
515,
['Baseball', 'Basketball', 'Volleyball', 'Track and Field', 'Hockey']
);
const salisbury = new HighSchool(
'Salisbury',
315,
['Baseball', 'Basketball', 'Volleyball', 'Track and Field', 'Hockey']
);
primary = new SchoolCatalog();
middle = new SchoolCatalog();
high = new SchoolCatalog();
high.addSchool(alSmith);
high.addSchool(anHenday);
high.addSchool(salisbury);
/*
high.quickFacts(alSmith);
high.quickFacts(anHenday);
high.quickFacts(salisbury);
*/
high.print();
Have you figured out the logic to prevent inserting a School object into the wrong list?
Both of those lines can call upon the getter for the list.
this.list.push(...)
print (this.list.forEach(...)
Hi Roy,
Yes, thank you for pointing that out. It should be without underscore outside of constructor, getter or setter, right?
Marco
I wouldnât go so far as to say, âshouldâ, but âcanâ. Getters are not just for accessing the backing variable from the outside, but for other methods, as well. No point having a getter if it is never used.
The less instances of direct access to the backing variable the better, from my view. Note that addSchool
is not a setter, only a method for adding data to the list, so there are no circular references. A setter would naturally need to access the backing variable, but that is for another discussion.
Still interested to see how you handle the list insertion restriction. Could you use a hint?
In regards to the insertion restriction, I have been trying to find the solution (with instanceof,âŚ)
But cannot get my head around it.
Could use a hint, yes
Many thanks.
I appreciate how hard you are working on this problem, and expect you are familiar enough with the existing logic to make sense of this hint:
constructor(level) {
this._list = [];
this._level = level;
}
Give it a getter to access the backing variable with this.level
.
Now we have a state to test in both the list insertion step of addSchool
and when printing the quickFacts
.
Interested in how you complete these steps, so keep us posted.
Thank you for that, very helpful.
I have modified the SchoolCatalog as follows;
class SchoolCatalog{
constructor(level){
this._list = [];
this._level = level;
}
get list(){
return this._list;
}
get level(){
return this._level;
}
addSchool(school){
if(this.level == school.level){this.list.push(school);}
else{console.log(`Oops! You tried to add a ${school.level} school. This list accepts ${this.level} schools only.`)}
}
quickFacts(x){
const teams = (x.sportsTeams ? `Intramural sports programs ${x.sportsTeams}` : '');
console.log(`${x.name} educates ${x.numberOfStudents} ${x.level} school students. ${teams}`);
}
print(){
this.list.forEach(this.quickFacts);
}
}
I have tested with correct and incorrect instances and the outcome is positive.
I am not sure why a test is needed in quickFacts as well, though. Can you clarify?
We can test level
instead of sportsTeams
, for greater simplicity. A straight if statement will do the trick (as opposed to the verbose ternary).
I understand now.
I have rewritten quickfacts(x) as follows .
quickFacts(x){
if(this.level == 'primary'){
const addition = `The policy is: ${x.pickupPolicy}`;
}
else if(this.level == 'high'){
const addition = `Intramural sports programs ${x.sportsTeams}`;
}
console.log(`${x.name} educates ${x.numberOfStudents} ${x.level} school students. ${addition}`);
}
@mtf, @marco.los
Iâve been following your code through, as I used the same method to build the SchoolCatalog class, and to verify the level of school added using the addSchool()
method.
Although I didnât add the quickFacts()
method to my version, Iâm interested in how it works; but I donât understand the use of the âx
â parameter: quickFacts(x)
âŚ
Does âx
â stand for whatever school object is passed into the method? If thatâs the case, then whatâs the point of having this method in the SchoolCatalog class, as it wouldnât be referencing the schools already stored in the this._list
array. Shouldnât quickFacts()
be iterating through the this._list
array and either printing a list of facts for all the schools at a particular level, or for a particular sample, perhaps also using .filter()
?