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

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 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.

Method 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));

Method 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
    });
 }
)


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x