Syntax guide for working with Salesforce Web Components

UPDATE

My initial understanding of the wired property was incorrect.

While trying to reproduce the issue, I had used data.length and thus had come to the conclusion that unless the wired property is referred in HTML, it does not get populated. Whereas in reality, once the component is rendered, the wired property does get populated.

Upon testing further found that the actual issue is that data is returned as JSON, and that length is not a valid property on the JSON being returned, which causes an error. So to verify if the property is blank or not, the approach that should be used here should be as:

if(this.studentCourseRelationships.data !== undefined) {
    if(JSON.stringify(this.contacts.data).length > 0);
          return true; // data populated
} else {
    return false; // no data
}

OR

Just use undefined

if(this.studentCourseRelationships.data !== undefined) {
    return true; // data populated
} else {
    return false; // no data
}

UPDATE

Calling Apex Method Imperatively

While you can wire an Apex method, you can also call it imperatively. To do so, you will need to utilize it in your hasCourses() function as below, and then verify it on HTML. This way you don't need to go through the approach mentioned earlier in the answer.

// declare a tracked variable
@track myStudentCourseRelationships;

get handleCourses() {

    // invoke the Apex method here
    getCourseData()
        .then(result => {
            this.myStudentCourseRelationships = result;
        })
        .catch(error => {
            this.error = error;
        });

    // myStudentCourseRelationships will be returned as a JSON
    // verify if you get a valid JSON, then return accordingly
}

Contents not valid have been striked-off and updated with relevant findings.

Utilizing wired Apex method

After trying to reproduce the scenario, it seems the wired service does get invoked only when it is referred in the HTML. So in your scenario studentCourseRelationships gets populated as JSON only when it's referred in the HTML when it's referred as {studentCourseRelationships.data}. So if you try to find the length of this attribute before it getting populated, that's when you will receive the error.

The option that I could see working is to display the contents only when length is not 0, is by using something as below. The idea is to ensure that studentCourseRelationships gets populated before you call hasCourses which checks on a valid data.length.

<template if:true={studentCourseRelationships.data}>

    <template if:true={hasCourses}>
        ...
    </template>
</template>

I will continue to see if there's a better option.


You need to check if the objects are yet populated:

get hasCourses() {
  return this.studentCourseRelationships && 
         this.studentCourseRelationships.data && 
         this.studentCourseRelationships.data.length > 0;
}

The && operator evaluates the right-hand value only if the left-side is "truthy", and the > operator only returns true if the result is a number and is greater than 0.