'Replace $scope with "'controller' as" syntax

I'm following this AngularJS+ASP.NET tutorial and they make use of $scope, but I'm trying to replace that dated usage with the new syntax controller as described in this question: "AngularJs "controller as" syntax - clarification?"

What I did is not working at the moment. The page calls $http.get inside of the nextQuestion() function, but the view remains the same with just the title "loading question...".


My Code:

JS http://pastebin.com/RfngRuZD

var app = angular.module('QuizApp', [])

app.controller('QuizCtrl', ['$http', function ($http) {
    this.answered = false;
    this.title = "loading question...";
    this.options = [];
    this.correctAnswer = false;
    this.working = false;

    this.answer = function () {
        return this.correctAnswer ? 'correct' : 'incorrect';
    };

    // GET
    this.nextQuestion = function () {
        this.working = true;
        this.answered = false;
        this.title = "loading question...";
        this.options = [];

        $http.get('/api/trivia').success(function (data, status, headers, config) {
            this.options = data.options;
            this.title = data.title;
            this.answered = false;
            this.working = false;
        }).error(function (data, status, headers, config) {
            this.title = "Oops... something went wrong.";
            this.working = false;
        });
    };

    // POST
    this.sendAnswer = function (option) {
        this.working = true;
        this.answered = true;

        $http.post('/api/trivia', { 'questionId': option.questionId, 'optionId': option.id }).success(function (data, status, headers, config) {
            this.correctAnswer = (data === "true");
            this.working = false;
        }).error(function (data, status, headers, config) {
            this.title = "Oops... something went wrong.";
            this.working = false;
        });
    };
}]);

Index.cshtml http://pastebin.com/YmV1hwcU

@{
    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")
}


Solution 1:[1]

You basically found the reason why using this isn't a very good idea in controllers. The this in your $http's success promise is not the this of the controller because this function gets executed in a different context. This wouldn't be an issue if you get $scope via the closure.

You can workaround that by defining a variable var that = this; and then use that instead.

Solution 2:[2]

Or you could just use javascripts bind function and pass in the correct this you want to use.

$http.get('/api/trivia').success(function (data, status, headers, config) {
    this.options = data.options;
    this.title = data.title;
    this.answered = false;
    this.working = false;
}.bind(this));

Solution 3:[3]

This worked for me, thanks o/

//form.blade.php

<md-content flex ng-controller="EmployeeController as child" ng-cloak>
 <md-input-container>
    <label>State</label>
    <md-select name="fk_state" ng-model="form.fk_state">
        <md-option><em>Select</em></md-option>
        <md-option ng-repeat="state in child.states" ng-value="state.uf">
            [[state.uf]]
        </md-option>
    </md-select>
 </md-input-container>
</md-content>

//employeeController.js

angular.module("app").controller('EmployeeController',
 function($scope, $q, utilsFactory){

    var that = this;

    //service that contains a $http request
    utilsFactory.getAll('states').then(function(response) {
        that.states = response.data;
        console.log(that.states); //should be available to child.states
    });
 }
)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Julian Hollmann
Solution 2
Solution 3 Ricardo