Я прохожу через эту учебную лабораторию для AngularJS. Я могу заставить пример работать как есть (с незначительным исправлением ошибок).
Я также пытаюсь изучить некоторые хорошие методы кодирования, касающиеся AngluarJS, ссылаясь на это руководство. Это привело к созданию js файла, который выглядит так:
(function () {
'use strict';
angular.module('QuizApp', []);
angular.module('QuizApp').controller('QuizCtrl', QuizController);
function QuizController($http) {
var vm = this;
vm.answer = answer();
vm.answered = false;
vm.correctAnswer = false;
vm.nextQuestion = nextQuestion();
vm.options = [];
vm.sendAnswer = sendAnswer(option);
vm.title = "loading question...";
vm.working = false;
function answer() {
return vm.correctAnswer ? 'correct' : 'incorrect';
}
function nextQuestion() {
vm.working = true;
vm.answered = false;
vm.title = "loading question...";
vm.options = [];
$http.get("/api/trivia")
.success(function (data, status, headers, config) {
vm.options = data.options;
vm.title = data.title;
vm.answered = false;
vm.working = false;
}).error(function (data, status, headers, config) {
vm.title = "Oops... something went wrong.";
vm.working = false;
});
}
function sendAnswer(option) {
vm.working = true;
vm.answered = true;
$http.post('/api/trivia', { 'questionId': option.questionId, 'optionId': option.id })
.success(function (data, status, headers, config) {
vm.correctAnswer = (data === true);
vm.working = false;
})
.error(function (data, status, headers, config) {
vm.title = "Oops... something went wrong.";
vm.working = false;
});
}
};
})();
Однако этот код вызывает следующую ошибку при загрузке страницы.
ReferenceError: опция "option" не определена в QuizController (http://localhost: 17640/Scripts/app/quiz-controller.js: 16: 9) при вызове (http://localhost: 17640/Scripts/angular.js: 4473: 7) в функции Anonymous (http://localhost: 17640/Scripts/angular.js: 9093: 11) в nodeLinkFn (http://localhost: 17640/Scripts/angular.js: 8205: 13) на составномLinkFn (http ://localhost: 17640/Scripts/angular.js: 7637: 13) в составнойLinkFn (http://localhost: 17640/Scripts/angular.js: 7641:13) в составнойLinkFn (http://localhost: 17640/Scripts/angular.js:7641:13) в составнойLinkFn (http://localhost: 17640/Scripts/angular.js: 7641:13) в составномLinkFn (http://localhost: 17640/Scripts/angular.js: 7641:13) в publicLinkFn (http://localhost: 17640/Scripts/angular.js: 7512: 30)
По какой-то причине он, похоже, пытается немедленно выполнить sendAnswer
. Поскольку он не работает, javascript останавливается на середине страницы, отображая угловое имя свойства {{title}} на странице вместо того, чтобы задавать вопрос на странице. Я пробовал разные способы определения и вызова vm.sendAnswer
и function sendAnswer
, без везения.
Для справки, вот код для моего представления (обратите внимание на ng-repeat on options - этот код представления отлично работает, когда он точно соответствует лабораторному упражнению):
<div id="bodyContainer" ng-app="QuizApp">
<section id="content">
<div class="container">
<div class="row">
<div class="flip-container text-center col-md-12" ng-controller="QuizCtrl" ng-init="nextQuestion()">
<div class="back" ng-class="{flip: answered, correct: correctAnswer, incorrect:!correctAnswer}">
<p class="lead">{{answer()}}</p>
<p>
<button class="btn btn-info btn-lg next option" ng-click="nextQuestion()" ng-disabled="working">Next Question</button>
</p>
</div>
<div class="front" ng-class="{flip: answered}">
<p class="lead">{{title}}</p>
<div class="row text-center">
<button class="btn btn-info btn-lg option" ng-repeat="option in options" ng-click="sendAnswer(option)" ng-disabled="working">{{option.title}}</button>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
Как я могу сохранить свою практику кодирования (по существу, избегать использования $scope
в этой ситуации и объявить все мои свойства viewmodel в верхней части контроллера), но заставить функцию работать правильно?
У меня есть этот пример, работающий сейчас.
Для начала, свойства контроллера, которые подключены к функциям, просто должны ссылаться на имена функций.
vm.answer = answer;
vm.nextQuestion = nextQuestion;
vm.sendAnswer = sendAnswer;
Тогда нам нужен псевдоним для нашего контроллера на нашем представлении, чтобы мы могли легче ссылаться на него.
<div class="flip-container text-center col-md-12" ng-controller="QuizCtrl as quiz" ng-init="quiz.nextQuestion()">
<div class="back" ng-class="{flip: quiz.answered, correct: quiz.correctAnswer, incorrect:!quiz.correctAnswer}">
<p class="lead">{{quiz.answer()}}</p>
<p>
<button class="btn btn-info btn-lg next option" ng-click="quiz.nextQuestion()" ng-disabled="quiz.working">Next Question</button>
</p>
</div>
<div class="front" ng-class="{flip: quiz.answered}">
<p class="lead">{{quiz.title}}</p>
<div class="row text-center">
<button class="btn btn-info btn-lg option" ng-repeat="option in quiz.options" ng-click="quiz.sendAnswer(option)" ng-disabled="quiz.working">{{option.title}}</button>
</div>
</div>
</div>
И это в значительной степени. Просто очистите определения свойств в угловом контроллере, а затем используйте псевдоним для контроллера на представлении. Все остальное - это почти тот же код, что и в вопросе.
Вот полный код сейчас. Угловой контроллер:
(function () {
'use strict';
angular.module('QuizApp', []);
angular.module('QuizApp').controller('QuizCtrl', QuizController);
function QuizController($http) {
var vm = this;
vm.answer = answer;
vm.answered = false;
vm.correctAnswer = false;
vm.nextQuestion = nextQuestion;
vm.options = [];
vm.sendAnswer = sendAnswer;
vm.title = "loading question...";
vm.working = false;
function answer() {
return vm.correctAnswer ? 'correct' : 'incorrect';
};
function nextQuestion() {
vm.working = true;
vm.answered = false;
vm.title = "loading question...";
vm.options = [];
$http.get("/api/trivia")
.success(function (data, status, headers, config) {
var answerOptions = data.options;
while (answerOptions.length > 0){
var random = Math.floor(Math.random() * answerOptions.length, 0);
alert(random);
vm.options.push(answerOptions[random]);
answerOptions.splice(random, 1);
}
//vm.options = data.options;
vm.title = data.title;
vm.answered = false;
vm.working = false;
}).error(function (data, status, headers, config) {
vm.title = "Oops... something went wrong.";
vm.working = false;
});
};
function sendAnswer(option)
{
vm.working = true;
vm.answered = true;
$http.post('/api/trivia', { 'questionId': option.questionId, 'optionId': option.id }).success(function (data, status, headers, config) {
vm.correctAnswer = (data === true);
}).error(function (data, status, headers, config) {
vm.title = "Oops... something went wrong";
});
vm.working = false;
}
};
})();
Просмотр MVC:
@{
ViewBag.Title = "Play";
}
<div id="bodyContainer" ng-app="QuizApp">
<section id="content">
<div class="container">
<div class="row">
<div class="flip-container text-center col-md-12" ng-controller="QuizCtrl as quiz" ng-init="quiz.nextQuestion()">
<div class="back" ng-class="{flip: quiz.answered, correct: quiz.correctAnswer, incorrect:!quiz.correctAnswer}">
<p class="lead">{{quiz.answer()}}</p>
<p>
<button class="btn btn-info btn-lg next option" ng-click="quiz.nextQuestion()" ng-disabled="quiz.working">Next Question</button>
</p>
</div>
<div class="front" ng-class="{flip: quiz.answered}">
<p class="lead">{{quiz.title}}</p>
<div class="row text-center">
<button class="btn btn-info btn-lg option" ng-repeat="option in quiz.options" ng-click="quiz.sendAnswer(option)" ng-disabled="quiz.working">{{option.title}}</button>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
@section scripts {
@Scripts.Render("~/Scripts/angular.js")
@Scripts.Render("~/Scripts/app/quiz-controller.js")
}
Вы планируете отправить vm.options = []; vm.sendAnswer = sendAnswer(option);
vm.options = []; vm.sendAnswer = sendAnswer(option);
vm.options
в функцию sendAnswer(), потому что option
не определена. вы не получите ошибку, если вы вложите "параметр" в строку и передаете ее в функцию. Но тогда вы не получите желаемого объекта. добавьте это где-нибудь в верхнюю var option = {}
.
options
есть ng-repeat, которое разбивает их на несколькоoption
. Тогда есть ng-щелчок дляsendAnswer(option)
.vm.sendAnswer
твоя функция все равно будет работать правильно. Также вы не можете получить доступ к даннымoption
из его функцииsendAnswer()
за исключением того, что вы передаете ответ об успешном выполнении в другую функцию.