Binding radio buttons in an ng-repeat with angular

788 Views Asked by At

I'm relatively new to angular and i'm trying to bind my form radio buttons so I can post the data to the back end.

My problem is when I try to submit the form, the variable formData doesn't contain any of the information entered in the form. I tried binding outside of the ng-repeat on a simple text input and it worked.

Here is my HTML

<section ng-app="IrsTestFactor">
<div ng-controller="IrsController as IrsCtrl">
    <h2>
        The IRS 20-Factor Test
        <span id="loading" ng-show="isProcessing">
            <span>
                -
                <img src="@Url.Content("~/Content/img/ajax-loader.gif")" alt="loading..." />
                Processing please wait
            </span>
        </span>
    </h2>
    <section class="content-indent">
        <p ng-show="emptyModel">Error - model is empty </p>
        <form ng-submit="processForm()" ng-hide="IRSCtrl.emptyModel">
            <br />
            <div ng-class="alertClass" class="alert" role="alert" id="alert" ng-show="alert">
                {{alertMessage}}
            </div>
            <br />
            <div class="jumbotron well well-lg">
                <p>
                    Please answer the questions below. The IRS developed this 20-Factor test to determine if a business controls and directs a worker, or has a right to do so. The factors (questions), applied to
                    each individual circumstance under which services are to be performed, determine the individual's classification. The questions must be objectively and consistently applied in order to determine the
                    individual's correct status. If the predominance of answers to the 20 questions is "yes", the individual is most likely an employee. If the predominance of answers is "no", the individual is most
                    likely an independent contractor.
                </p>
            </div>
            <br /><br />
            <div ng-repeat="question in questionnaire">
                <div class="btn-group col-xs-offset-1 col-xs-2 col-sm-2" data-toggle="buttons">
                    <span class="btn btn-primary">
                        <input type="radio" name="item_{{$index}}" ng-model="$parent.formData" value="false"> No
                    </span>
                    <span class="btn btn-primary">
                        <input type="radio" name="item_{{$index}}" ng-model="$parent.formData" value="true"> Yes
                    </span>
                </div>
                <span class="message col-xs-8 col-sm-8">{{question.QuestionPhrase}}</span>
                <br /><br /><br />
            </div>
            <input type="text" ng-model="formData.word" name="word" />
            <div class="centered-panel-btn">
                <a type="button" href="/@ContractManagerConfig.RootUrl()/Home/" class="btn btn-default">
                    <span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>
                    Cancel
                </a>
                <button type="submit" class="profile-savenext btn btn-success" value="next">
                    <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
                    Submit
                </button>
            </div>
        </form>
    </section>
</div>

and here is my angular:

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

    app.controller('IrsController', function ($scope, $http) {
    $scope.isProcessing = false;
    $scope.alert = false;
    $scope.alertClass = "";
    $scope.alertMessage = "";
    $scope.formData = {};
    $scope.emptyModel = false;

    /** Http request to get all questions for the irs questionnaire [caching] */
    $http({
        method  : 'GET',
        cache   : true,
        url     : 'GetQuestionnaire'
    }).success(function (data) {
        $scope.questionnaire = data.QuestionnaireList;
        $scope.emptyModel = false;
    }).error(function () {
        alert("error");
        $scope.emptyModel = true;
    });



    $scope.processForm = function () {
        $scope.isProcessing = true;
        formData = JSON.stringify($scope.formData);
        alert(formData);
        $http({
            method  : 'POST',
            url     : 'SaveIRSFactorTest',
            data    : $scope.formData,  // pass in data as strings
            headers : { 'Content-Type': 'application/x-www-form-urlencoded' }  // set the headers so angular passing info as form data (not request payload)
        })
        .success(function(data) {
            $scope.alert = false;
            $('html, body').animate({ scrollTop: 0 }, 'slow');
            if (!data.success) {
                $scope.alertClass = "alert-danger";
                $scope.alertMessage = data.message;
                $scope.isProcessing = false;
                $scope.alert = true;
            } else {
                //success
                $scope.alertClass = "alert-success";
                $scope.alertMessage = data.message;
                $scope.alert = true;
            }
            $scope.alert = true;
        })
        .error(function (data) {
            $scope.alert = false;
            $('html, body').animate({ scrollTop: 0 }, 'slow');
            $scope.alertClass = "alert-danger";
            $scope.alertMessage = data.message;
            $scope.isProcessing = false;
            $scope.alert = true;
        });
    }
});
2

There are 2 best solutions below

0
On BEST ANSWER

So it turns out that the problem was coming from the spans. I changed them to labels and it worked.

Here is the code:

<div ng-repeat="question in questionnaire">
                <div class="btn-group col-xs-offset-1 col-xs-2 col-sm-2" data-toggle="buttons">
                    <label class="btn btn-primary">
                        <input type="radio" name="question{{$index}}" ng-model="formData[$index]" value="false"> No
                    </label>
                    <label class="btn btn-primary">
                        <input type="radio" name="question{{$index}}" ng-model="formData[$index]" value="true"> Yes
                    </label>
                </div>
                {{formData}}
                <span ng-bind="question.QuestionPhrase" class="message col-xs-8 col-sm-8"></span>
                <br /><br /><br />
            </div>
3
On

ng-model should be a property from the scope. Setting it to an empty object $parent.formData will not work. Moreover you have the radio buttons inside ng-repeat so you have to generates the model based on the item index. Try something like this.

            <div ng-repeat="question in questionnaire">
                <div class="btn-group col-xs-offset-1 col-xs-2 col-sm-2" data-toggle="buttons">
                    <span class="btn btn-primary">
                        <input type="radio" name="item_{{$index}}" ng-model="formData['item_' + $index]" value="false"> No
                    </span>
                    <span class="btn btn-primary">
                        <input type="radio" name="item_{{$index}}" ng-model="formData['item_' + $index]" value="true"> Yes
                    </span>
                </div>
                <span class="message col-xs-8 col-sm-8">{{question.QuestionPhrase}}</span>
                <br /><br /><br />
            </div>