Rob Hern
Rob Hern

Reputation: 128

Function inside Object not returning value

I'm attempting to write some code that runs over an array of lessons within the object below and return the percentage of completed lessons (ones marked as completed: true).

When I console.log the outcome it just shows as [Function completion], rather than a number as expected. Where am I going wrong?

For reference I'm using JS with React Native, but this should only concern JS if I'm correct?

WorkoutCategoryData.js

export default [
  {
    title: "Title 1",
    subtitle: "Subtitle 1",
    lessonCount: 4,
    lessons: [
      {
        title: "Lesson Name 1",
        completed: true
      },
      {
        title: "Lesson Name 2",
        completed: true
      },
      {
        title: "Lesson Name 3",
        completed: false
      },
      {
        title: "Lesson Name 4",
        completed: false
      },
    ],
    completion: function() {
      this.findCompletion();
    }
  },
  {
    title: "Title 2",
    subtitle: "Subtitle 2",
    lessonCount: 3,
    lessons: [
      {
        title: "Lesson Name 5",
        completed: true
      },
      {
        title: "Lesson Name 6",
        completed: true
      },
      {
        title: "Lesson Name 7",
        completed: true
      }
    ],
    completion: function() {
      this.findCompletion();
    }
  }
];

function findCompletion(lessons) {
  let lessonCompletion = 1;
  let completedLessons = lessons.filter(lesson => lesson.completed === true)
    .length;
  let totalLessons = lessons.length;
  lessonCompletion = (completedLessons / totalLessons) * 100;
  return lessonCompletion;
}

Workouts.js

import WorkoutCategoryData from "./data/WorkoutCategoryData";


 {WorkoutCategoryData.map(cat => {
            let currentCompletion = cat.completion;
            console.log(currentCompletion);
            return (
              <View style={styles.workoutContainer} key={cat.title}>
                <View style={styles.workoutProgress}>
                  <AnimatedCircularProgress
                    size={50}
                    width={5}
                    rotation={0}
                    fill={cat.completion}
                    tintColor={Colors.primary}
                    backgroundColor="#dddddd"
                  />
                </View>
                <View style={styles.workoutText}>
                  <Text style={styles.workoutTitle}>{cat.title}</Text>
                  {cat.subtitle ? (
                    <Text style={styles.workoutSubtitle}>{cat.subtitle}</Text>
                  ) : null}
                </View>
              </View>
            );
          })}

I'm hoping to get an Integer number I can then pass in as a prop in a component for a progress indicator. Any help would be very much appreciated, thanks in advance!

Upvotes: 0

Views: 119

Answers (3)

DSCH
DSCH

Reputation: 2376

Like @David Koe said you need to return. However you are passing a reference to the function instead of invoking it - Please try let currentCompletion = cat.completion(); in Workouts.js and if the rest of your code is working as you expect it should return the result.

Upvotes: 0

Ry-
Ry-

Reputation: 225074

Repeating completion like that is a bad sign – mixing data and common implementation and so on. Consider giving your objects a type (name it what it actually represents, like Course, not Thing):

class Thing {
  constructor(data) {
    this.title = data.title;
    this.subtitle = data.subtitle;
    this.lessonCount = data.lessonCount;
    this.lessons = data.lessons;
  }

  getCompletion() {
    let completedLessons = this.lessons.filter(lesson => lesson.completed).length;
    let totalLessons = this.lessons.length;
    return (completedLessons / totalLessons) * 100;
  }
}

export default [
  {
    title: "Title 1",
    subtitle: "Subtitle 1",
    lessonCount: 4,
    lessons: [
      {
        title: "Lesson Name 1",
        completed: true
      },
      {
        title: "Lesson Name 2",
        completed: true
      },
      {
        title: "Lesson Name 3",
        completed: false
      },
      {
        title: "Lesson Name 4",
        completed: false
      },
    ],
  },
  {
    title: "Title 2",
    subtitle: "Subtitle 2",
    lessonCount: 3,
    lessons: [
      {
        title: "Lesson Name 5",
        completed: true
      },
      {
        title: "Lesson Name 6",
        completed: true
      },
      {
        title: "Lesson Name 7",
        completed: true
      },
    ],
  },
].map(data => new Thing(data));

Then you use it with fill={cat.getCompletion()}. Since it’s a function, it needs to be called.

(Also, do you really need lessonCount, considering it appears to be lessons.length?)

Another option that makes sense is not requiring this function to be a method:

let getCompletion = ({lessons}) => {
  let completedLessons = lessons.filter(lesson => lesson.completed).length;
  let totalLessons = lessons.length;
  return (completedLessons / totalLessons) * 100;
};
<AnimatedCircularProgress
  size={50}
  width={5}
  rotation={0}
  fill={getCompletion(cat)}
  tintColor={Colors.primary}
  backgroundColor="#dddddd"
/>

Upvotes: 1

David Ko
David Ko

Reputation: 342

when you call completion, you might want to return the result.

completion: function() {
      return this.findCompletion();
    }

Upvotes: 0

Related Questions