Search code examples
angularjsangularjs-ng-repeatangular-ngmodel

Dynamically setting new ng-model when pushing model to array


Can't figure out how to dynamically add a new model whenever a new row is added to the page. For example, the input select box ng-model= infos.rigBonusInfo.rigName is used for all select box I've added to the page. I would like to have a different model attached to a each select inputs. I tried using ng-model= infos.rigBonusInfo.rigName[rigBonus] but it doesn't work for the rates as the same model gets attachedto each rate field.

Pretty much what I want to do is to bind a new model whenever a new row gets pushed into the array.

Currently, I have a nested table which is the following:

<div class="col-lg-5">
    <table class="table table-striped table-bordered">
        <thead>
            <tr>
                <th>Rig</th>
                <th>Rig Name</th>
            </tr>
        </thead>

        <tbody>
            <tr ng-repeat="rig in rigs">
                <td>{{ $index + 1 }}</td>
                <td>{{ rig.name }}</td>
            </tr>
        </tbody>
    </table>
</div>

<div class="col-lg-2"></div>

<div class="col-lg-5">
    <table class="table table-striped table-bordered">
        <thead>
            <tr>
                <th>Bonus Name</th>
                <th>Rate</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="bonus in create.rigBonusRates">
                <td>{{ bonus.rateName }}</td>
                <td>{{ bonus.rate }}</td>
            </tr>
        </tbody>
    </table>
</div>

<table>       
    <thead>
        <tr>
            <th>Date</th>
        </tr>
    </thead>
        <tbody>
            <tr ng-repeat="rigDate in rigDateList track by $index">
                <td><input ui-date="datepickerOptions" ng-model="date" /></td>
                <td>
                    <table>
                        <thead>
                            <tr>
                                <th>Rig</th>
                                <th>Rate1</th>
                                <th></th>
                                <th>Rate2</th>
                                <th></th>
                                <th>Rate3</th>
                                <th></th>
                                <th>Rate4</th>
                                <th></th>
                                <th>Comments</th>
                            </tr>
                        </thead>
                        <tr ng-repeat="rigBonus in rigBonusList track by $index">
                            <td><select ng-options="rig as rigs.indexOf(rig) + 1 for rig in rigs" ng-model="infos.rigBonusInfo.rigName[rigBonus]" ></select></td>
                            @for (var i = 1; i < 5; i++)
                            {
                                <td><select ng-options="rigBonus.rateName for rigBonus in create.rigBonusRates" ng-model="infos.rigBonusInfo.rate@(@i)"></select></td>
                                <td><input type="text" ng-disabled="infos.rigBonusInfo.rate@(@i).rateName != 'Special' " ng-model=infos.rigBonusInfo.rate@(@i).rate /></td>
                            }

                          <td><input ng-model="info.rigBonusInfo.comments" /></td>
                        </tr>
                    </table>
                </td>
            </tr>
        </tbody>
</table> 

<div>
    <button type="button" ng-click="add()">Add</button>
    <button type="button" ng-click="addDate()">Add Date</button>
</div>

My current controller has the following:

   angular.module('RigBonus').controller('rigCreateController', ['$scope', '$http', 'PayPeriodService', 'RigLegendService',
    function ($scope, $http, PayPeriodService, RigLegendService, RigBonusRateService) {

        $scope.rigs = RigLegendService.getRigLegend();

        $scope.datepickerOptions = {
            orientation: 'top',
            startDate: PayPeriodService.getStartDate(),
            endDate: PayPeriodService.getEndDate()
        };


        $http({ method: 'GET', url: '/Home/CreateData' }).success(function (data) {
            $scope.create = data;

            $scope.infos = {
                rigBonusInfo: {
                    rigName: $scope.rigs[0],
                    rate1: $scope.create.rigBonusRates[0],
                    rate2: $scope.create.rigBonusRates[0],
                    rate3: $scope.create.rigBonusRates[0],
                    rate4: $scope.create.rigBonusRates[0],
                    comment: ""
                }
            };

            $scope.add = function () {
                $scope.rigBonusList.push();
            };

            $scope.addDate = function(){
                $scope.rigDateList.push("");
            };

        });

        $scope.rigBonusList = [$scope.rigBonusInfo];
        $scope.rigDateList = [];

        $scope.submit = function () {
            $http.post('/Home/Create', {model: "testing"} );
        };


}]);

Solution

  • I figured out my issue. My problem was that I was not sure how to generate a new object when a new row of controls are added. Think I should have put something on fiddleJS to help people visualize it better. As a static model was used ($scope.infos) as ng-model, the same model was used for two different controls which I don't want. I want all my controls to be unique.

    The fix was to create the object I had in mind which is the following:

    $scope.rigDateList = [{
            date: "",
            rigBonusList: [{}]
        }];
    

    So it is an array of objects where the object contains a date and another array of objects.

    When I want to push new objects to the inside array which I didn't know I could just create objects like this at the time. I was trying to figure out a way to dynamically create new models ng-model could by declaring them in the controller. I use the following function:

     $scope.rigDateList[$scope.rigListIndex].rigBonusList.push({
                            rigName: "",
                            rate1: "",
                            rate2: "",
                            rate3: "",
                            comments: ""
                        });
    

    I also didn't know that I could use elements inside the array from ng-repeat. In the following case, it is rigBonus that I could have used as a model instead of infos model.

    <tr ng-repeat="rigBonus in rigDate.rigBonusList track by $index">
                                    <td><select ng-options="rig as rigs.indexOf(rig) + 1 for rig in rigs" ng-model="rigBonus.rigName"></select></td>
    

    and when I want to push to the outside array I use the following:

         $scope.rigDateList.push({
                                date: "",
                                rigBonusList: [""]
                            });
    
    $scope.rigListIndex = $scope.rigListIndex + 1;
    

    I use an index to keep track of which object I'm in.