1

I have created a table with a row that has three dropdowns

Drug - Dose - Period

I also created a button Add Drug that will add another row of the same dropdowns

I am getting the data from a database and populating it in the dropdown

Exception:

The dose dropdown changes depending on what the drug is. So I created a watcher to check when the value of the drug changes, and then created an array of the dose data called $scope.array and populated it in $scope.selectedDose which are the values inside the dose dropdown. So the first drug dose data is different than the second drug dose data. Please select the second drug and 5th drug from dropdown in jsfiddle and see how dose values changes

$scope.$watch("value",  function() {
  $scope.array = $scope.value.dose_array.split(',');
  $scope.selectedDose = $scope.array[0];
});

Problem:

If you play around with my JSFiddle link that I shared, you will find that when adding a drug with the button and selecting another drug from the first, the dose data of the first row changes too. The reason for that is because $scope.selectedDose is changing with any drug data from any row

The solution that I thought of is creating an array of an array

$scope.selectedDose[rowIndex] = $scope.array[0];

with every row added, the dose dropdown will have its own selectedDose data. However it was complicated and was not able to accomplish it

Any solutions for this problem ? I have added the JSFiddle and organized my code as much as possible. It should demonstrate my problem very well

JSFIDDLE

http://jsfiddle.net/jq3fxx72/3/

4
  • TypeError: Cannot read property 'dose_array' of null at $scope.array = $scope.value.dose_array.split(','); Commented Aug 23, 2015 at 18:56
  • Thats just the first error becuase there's no value selected for the first dropdown. @MikkoViitala Commented Aug 23, 2015 at 19:03
  • I think the problem is that instead of copying an inert object, your addRow function is copying the first element of the array ($scope.rows[0]). Try creating an object you can clone from outside the array so that when you set the first row to a value, it doesn't cascade. Commented Aug 23, 2015 at 19:05
  • Could you elaborate by writing an answer ? There is already the object rows created. and if I replace ($scope.rows[0]) by ($scope.rows) it still copies the Dose array @Claies Commented Aug 23, 2015 at 19:40

1 Answer 1

3

I wouldn't add a watch for adding the doseArray. You could add it to the ng-click event and add it to the current row as doseArray.

Also improve your variable & function names because no one knows what a function func does. Good names will help you to understand your code.

Please have a look at the demo below or in this jsfiddle.

app = angular.module('app', []);
app.controller('myCtrl', ['$scope', '$http', function ($scope, $http) {
    $scope.rows = [];
    var rowTmpl = {
        'drug': "Drug",
        'dose': 'Dose',
        'period': "Period",
    };

    // init first row
    $scope.rows.push(angular.copy(rowTmpl));

    //PERIOD

    $scope.period = {
        currentPeriod: "1 day"
    };

    $scope.periods = [
        "1 day",
        "2 days",
        "3 days",
        "4 days"];

    $http.get('http://medicaladvisto.com/getDrugs').success(function (data) {
        $scope.ourDatas = data;
        //console.log(data);
    });

    $scope.setDose = function (row, drug) {
        //console.log('Selcted', drug);
        var index = $scope.ourDatas.indexOf(drug);
        if (index === -1) return;

        var doseArray = $scope.ourDatas[index].dose_array.split(',');
        row.doseOptions = doseArray;
    };

    //ADDING ROWS

    $scope.addRow = function () {
        var newRow = angular.copy(rowTmpl);
        newRow.selectedPeriod = null;
        newRow.singleSelect = null;
        $scope.rows.push(newRow);
    };

    $scope.removeRow = function (rowIndex) {
        if (confirm('Are you sure you want to delete this?')) $scope.rows.splice(rowIndex, 1);
    }
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
    <div class="buttons"> <a class="navbar-brand" ng-click="addRow()" href="#">
                    <button class="btn btn-default"> Add Drug</button></a> 
        <!-- adds rows -->
    </div>
    <table class="table">
        <tr ng-repeat="(rowIndex, row) in rows">
            <td>{{ourDatas.doseOptions}}</td>
            <td>
                <label for="singleSelect">{{row.drug}}
                    <select class="form-control" popover="Choose your input drug, type to filter list of drugs" data-ng-model="row.singleSelect" ng-click="setDose(row, row.singleSelect)" data-ng-options="name.dname for name in ourDatas" style="width:300px;" required></select>
                </label>
            </td>
            <td>
                <label for="selectedDose">{{row.dose}}
                    <select class="form-control" popover="Choose dosage amount" data-ng-model="row.selectedDose" ng-options='dose for dose in row.doseOptions' style="width:200px;" required></select>
                </label>
            </td>
            <td>
                <!-- Periods dropdown selection box -->
                <label>{{row.period}}
                    <select class="form-control" popover="Choose how many times a day taken" data-ng-model="row.selectedPeriod" data-ng-options="name for name in periods" style="width:100px;" required></select>
                </label>
            </td>
            <td>
                <input type="button" value="-" class="btn btn-primary" ng-click="removeRow(rowIndex)" />
            </td>
        </tr>
    </table>
</div>

Sign up to request clarification or add additional context in comments.

2 Comments

Than you very much good sir. I would like to know why adding a watch function is not a good idea ?
You're welcome. I think adding watches is OK if you really need them but they can slow down your app if you have many of them because they are checked pretty often by angular. So it's better to do something on user interaction (ng-click / ng-change ...) and try to avoid $watch. There is also a nice post about avoiding watches.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.