So when I click on the tutorial navigation menu it fires the ng-click="loadNewTutorial($index)" function, everything works ok tutorialNumber gets updated by the index number and that in turn changes the URL of the current video. The only problem is that video.load()/video.play() apparently fires before that change occurs in the DOM because the video is always 1 click behind. What I mean is I can click the menu item to load the second tutorial video but it will will load the first, then the NEXT time I click it will load the second, then if I click the first again it will be stuck on the second until I click the first again. So the current video doesnt load the correct URL in time and is always 1 click behind! How can I make the video.load() function wait until the videos src attribute in the DOM has been changed before it fires?
<!DOCTYPE html>
<html ng-app="Tutorials">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js"></script>
<script src="./functions.js"></script>
<script src="./tutorials.js"></script>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/ui/1.10.0/jquery-ui.js"></script>
<script type="text/javascript" src="./script-ng.js"></script>
<link rel="stylesheet" href="main.css"></link>
</head>
<body ng-controller="getAnswers">
<div id="sidebar_left"><div id="header"></div>
<ul id="nav" ng-repeat="section in sets">
<li class="section_title {{section.active}}" >
{{section.name}}
</li>
<ul><li class="tutorial_title {{tutorial.active}}" ng-click="loadNewTutorial({{$index}})" ng-repeat="tutorial in section.tutorials">{{tutorial.name}}</li></ul>
</ul><span>{{score}}</span>
</div>
<div id="container">
<video id="video" controls>
<source src="{{videoURLs[tutorialNumber]}}.mp4"></source>
<source src="{{videoURLs[tutorialNumber]}}.webm"></source>
Your browser does not support the video tag.
</video>
<br />
<button id="reset">Replay</button>
<br />
<div id="pannel">
<div id="base">{{verbs.base}}</div>
<ul class="answers">
<li ng-click="checkAnswer(answer)" ng-repeat="answer in verbs.conjugations" class="{{answer.colorReveal}} answer {{answer.correct}}" id="answer{{$index}}">{{answer.text}}</li>
</ul>
</div>
<br />
<br />
<br />
<div id="warning"></div>
</div>
</body>
</html>
angular.module('Tutorials', ['functions', 'tutorials']).controller('getAnswers', function ($scope, $element) {
$scope.sectionNumber = 0;
$scope.tutorialNumber = 0;
$scope.loadNewVerbs = function () {
$scope.verbs = conjugate(conjugationsets[$scope.tutorialNumber][$scope.questionNumber]);
$scope.correct = $scope.verbs.conjugations[0].text;
fisherYates($scope.verbs.conjugations);
};
$scope.checkAnswer = function (answer) {
if (false) {//wait for tutorial to pause
$("#warning").text("Not yet!").fadeIn(300).delay(1400).fadeOut(300);
return;
};
answer.colorReveal = "reveal-color";
if (answer.text === $scope.correct) { //if correct skip to congratulations
$scope.questionNumber++;
if(sectionNumber === 0 && $scope.tutorialNumber ===0){ //if first video play congratulations etc
congrats();
}
setTimeout(function () {
$scope.loadNewVerbs();
$scope.$digest();
}, 2000);
} else { //if incorrect skip to try again msg
if(sectionNumber === 0 && $scope.tutorialNumber ===0){start(160.5); pause(163.8)}
}
};
$scope.sets = [{
active:"inactive",
name: "Conjugation",
tutorials: [
{active:"inactive",name: "ㅗ and ㅏ regular"},
{active:"inactive",name:"ㅜ, ㅓ and ㅣ regular"},
{active:"inactive",name:"ㅏ and ㅓ reductive"},
{active:"inactive",name: "ㅗ and ㅜ reductive"},
{active:"inactive",name: "ㅣ reductive"}]
}, {
active:"inactive",
name: "Sentence_Building",
tutorials: [
{active:"inactive",name:"Particles"},
{active:"inactive",name:"Word Order"}]
}];
$scope.video = $("#video").get(0);
$scope.videoURLs = ["ㅗㅏregular", "ㅜㅓㅣregular"];
$scope.loadNewTutorial = function (tut) {
$scope.score = 0;
$scope.questionNumber = 0;
if(tut){
$scope.tutorialNumber = tut;
}
video.load();
video.play();
video.hasPlayed = true;
$(video).bind('ended', endVideoHandler);
$scope.loadNewVerbs();
};
$scope.loadNewTutorial();
var congrats = function(){
if ($scope.questionNumber === 1) {start(164.15); pause(166.8); $scope.score++;
} else if ($scope.questionNumber === 2) {start(167.1); pause(170); $scope.score++;
} else if ($scope.questionNumber === 3) {
start(171.1); $scope.score ++;$scope.questionNumber = 0;$scope.tutorialNumber++;
}
}
function endVideoHandler() {
$(this).unbind('ended');
if (!this.hasPlayed) {
return;
}
$scope.tutorialNumber++;
$scope.$digest();
this.currentTime = 0;
$scope.loadNewTutorial();
}
});
var conjugationsets = [
["작다", "놀다", "닦다"],
["웃다", "울다", "멀다"]
];
var sectionNumber = 0;
var tutorialNumber = 0;
var questionNumber = 0;
$(function () {
$("#nav").accordion({
heightStyle: "content",
header: ".section_title"
});
$("#reset").click(function () {
currentTutorial.currentVideo.videoObject.currentTime = 0;
currentTutorial.currentVideo.start();
});
});
edit: I'm not sure I understand your code here, but why does loadNewTutorial take $scope as an argumen when it's already available? I'm guessing that that this is part of your problem since you can't pass the scope to it from the template.
original: "loadNewTutorial({{$index}})" should be "loadNewTutorial($index)".
I see several problems with your "loadNewTutorial" function:
It is taking a $scope parameter as an argument when it shouldn't (the function is defined inside the $scope so the $scope is available to the function by default).
It is expected to receive a $scope as it's first argument, but in one place you are calling it with current scope, in other place you are calling it without any parameters and then in view you are calling it while passing the $index (which resolves to a primitive number) as it's first parameter.
It is redefining the 'loadNewVerbs' and 'checkAnswer' function every time it gets invoked.
Just to name a few.