There are very few example on SCORM implementation, so I am a little lost. I need to get the student score based on 3 questions. I don't really understand what i am doing. I know i probably need a function like calculateScore(). SCORM is confusing the crap out of me though. I use SCORMCLOUD to test but i have reupload the build everytime i wanna test something..
APP.js
function App() {
Scorm.init();
const [learnerName, setLearnerName] = useState(`${Scorm.getLearnerName()}`);
const [assessment, setAssessment] = useState([]);
const finish = () => {
Scorm.finish();
};
const updateAssesment = (correct, response) => {
setAssessment(assessment.concat([correct]));
Scorm.submitMCQ(correct, response);
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<Learner name={learnerName} />
</header>
<main>
<Mcq result={updateAssesment.bind()} question="What is 10 * 10?" correctAnswer={0} answers={["100", "20"]} />
<Mcq
result={updateAssesment.bind()}
question="What is the capital of Spain?"
correctAnswer={2}
answers={["Barcelona", "Lisbon", "Madrid"]}
/>
<Mcq
result={updateAssesment.bind()}
question="Which US President's office commissioned the creation of SCORM?"
correctAnswer={3}
answers={["Donald Trump", "Barack Obama", "Ronald Reagan", "Bill Clinton"]}
/>
<CompleteButton completeActivity={finish.bind()} />
</main>
</div>
);
}
export default App;
SCORM.js
import { SCORM } from "pipwerks-scorm-api-wrapper";
let Scorm = {
init() {
SCORM.init();
},
getLearnerName() {
return SCORM.get("cmi.core.student_name");
},
submitMCQ(correct, response) {
let nextIndex = SCORM.get("cmi.interactions._count", true);
SCORM.set("cmi.interactions." + nextIndex + ".id", "round_" + nextIndex);
SCORM.set("cmi.interactions." + nextIndex + ".type", "choice");
SCORM.set("cmi.interactions." + nextIndex + ".student_response", response);
SCORM.set("cmi.interactions." + nextIndex + ".result", correct);
},
calculateScore() {
//something here??
SCORM.set("cmi.core.score.raw", "0");
SCORM.set("cmi.core.score.max", "100");
SCORM.set("cmi.core.score.min", "0");
},
finish() {
alert("you have finished!");
SCORM.set("cmi.core.lesson_status", "completed");
SCORM.save();
SCORM.quit();
},
};
export default Scorm;
MCQ component
export default function Mcq(props) {
const [selectedOption, setSelectedOption] = useState(0);
const [answered, setAnswered] = useState(false);
const handleOptionChange = (changeEvent) => {
setSelectedOption(Number(changeEvent.target.value));
};
const renderAnswers = () => {
return props.answers.map(function (answer, index) {
return (
<div className="answer" key={index}>
<input type="radio" value={index} checked={selectedOption === index} onChange={handleOptionChange} />
<label>{answer}</label>
</div>
);
});
};
const handleFormSubmit = (formSubmitEvent) => {
formSubmitEvent.preventDefault();
setAnswered(true);
props.result(selectedOption === props.correctAnswer, props.answers[selectedOption]);
};
const currentState = () => {
if (!answered) {
return (
<form onSubmit={handleFormSubmit.bind(this)}>
{renderAnswers()}
<button className="btn btn-default" type="submit">
Submit
</button>
</form>
);
} else {
return <div>{checkCorrectAnswer()}</div>;
}
};
const checkCorrectAnswer = () => {
if (selectedOption === props.correctAnswer) {
return `yes, ${props.answers[props.correctAnswer]} is the correct answer.`;
} else {
return `You answered ${props.answers[selectedOption]}. Sorry, but the correct answer is ${
props.answers[props.correctAnswer]
}.`;
}
};
return (
<div className="Mcq">
<p>{props.question}</p>
{currentState()}
</div>
);
}
Your question is a bit confusing. SCORM is an API tying two things together:
It looks like you are trying to create learning content, although you provide a way to change the learner name, which is read-only data provided by the JS API.
If that's what you're trying to do, it's not up to SCORM to tell you the score but to you. Based on your code I'm guessing you want each question to be worth a number of points (or at least just one) if answered correctly and the score should be based on that and the total number of questions.
Since you're storing all answers in cmi.interactions
already, you could try getting the number of interactions (i.e. answers) first. This tells you the total number of answers and thus the maximum number of points, or cmi.core.score.max
.
Since the lowest possible score is zero points if you do a simple tally instead of something more complicated like negative points for incorrect choices being selected, the cmi.core.score.min
would then be 0
.
The cmi.core.score.raw
would be the total number of points, so the number of answers that are correct. You could get this by iterating over the values of cmi.interactions.n.result
you set previously (with n
being the index between zero and cmi.interactions._count
and only counting those where the result
is "correct"
).
However note that submitMCQ
should set cmi.interactions.n.result
to "correct"
or "incorrect"
not true
or false
. A conforming LMS will otherwise reject the value as invalid (which does not raise an exception but instead sets an error flag you have to check explicitly because SCORM is weird like that).