TypeError: $scope.array.reduce is not a function

2019-09-12 13:27发布

问题:

I have 3 drop-down-lists that load attributes related to a page. These attributes are: instruments, style, scoring. The attributes are loaded from a service call.

Example using instruments:

  //Get Instruments
  $http.get('/api/Instrument/GetAllInstruments').success(function (data, status, headers, config) {
      $scope.instruments = data;
  }).error(function (data, status, headers, config) {
      $scope.error = "An Error has occured while fetching Instruments!" + data;
  });

and the html:

<select class="form-control" 
        name="recordInstrument" 
        data-ng-model="recordInstrument" 
        required
        data-ng-options="i.ID as i.Description for i in instruments">
    <option value="">-- Choose an Instrument --</option>
</select>

A user can select a record from a list, and on a form, the values of that record are loaded. These values also include the attribute values that set the selected value for the drop-downs.

When the user clicks the record, a, "edit" function gets called. The function calls a service that gets the record, then it does an if statement to determine if the record attribute array is not empty. If the attribute array is not empty then it does a forEach loop on the array, sets the ng-model, in this case "$scope.recordInstrument" so that the selected default value is set for the record's drop-down. If the array is empty, then it set the ng-model to 0, to reset the drop-down to the no record selected value "Choose an instrument".

Here is that piece of code: //Edit Store Page $scope.edit = function () {

      if (this.page.SPPreambleID === null || this.page.SPPreambleID === 0) {
          this.page.SPPreambleID = -1;
      }

      $http.get('/api/StorePage/GetStorePage?StorePageID=' +
        this.page.StorePageID +
        '&SPPreambleID=' +
        this.page.SPPreambleID).success(function (data) {

            $scope.updateShow = true;
            $scope.addShow = false;
            $scope.newpage = data;

            if (data.SPAttributeRefID.length > 0) {

                angular.forEach($scope.newpage.SPAttributeRefID, function (attribute, index) {

                    if (attribute == 1) {

                        $scope.instruments = $scope.instruments.reduce(function (result, instrument) {
                            result[instrument.ID] = instrument;
                            return result
                        }, {});

                        $scope.recordInstrument = $scope.instruments[data.AttributeID[0]].ID;
                    };

                    if (attribute == 2) {

                        $scope.style = $scope.styles.reduce(function (result, style) {
                            result[style.ID] = style;
                            return result
                        }, {});
                        $scope.recordStyle = $scope.styles[data.AttributeID[1]].ID;
                    };

                    if (attribute == 3) {
                        $scope.scoring = $scope.scorings.reduce(function (result, scoring) {
                            result[scoring.ID] = scoring;
                            return result
                        }, {});
                        $scope.recordScoring = $scope.scorings[data.AttributeID[2]].ID;
                    };
                });
            }
            else {
                $scope.recordInstrument = 0;
                $scope.recordStyle = 0;
                $scope.recordScoring = 0;
            }
        }).error(function () {
            $scope.error = "An Error has occured while Editing this Store Page!" + data;
        });
  }

The code above was working before I put the if line: if ($scope.newpage.SPAttributeRefID.length > 0) { ... }

The reason I added the if to check the array's length was because some records do not have drop down attributes, and if I was coming from a previous record that it had values, then the drop downs will stay with those values from the record before.

After I added the if, I started getting the error pointing to the reduce function and I am not sure what I am doing wrong.

I would like to ask for help trying to resolve this issue.

Thank you very much.

回答1:

I ended up not using .reduce anymore. I changed the code to use a for loop after posting a new question and getting a working answer: JavaScript: flatten an array without using reduce library

Here is the code snippet that replaces the reduce function:

if (attribute == 1) {

    var arrInstruments = $scope.instruments;
    var arrLength = arrInstruments.length;
    var result = {}
    for (var i = 0; i < arrLength; i++) {
        result[arrInstruments[i].ID] = arrInstruments[i];
    }
    $scope.recordInstrument = result[$scope.newpage.AttributeID[0]].ID;
}


回答2:

It looks like your problem is here.

});
// you have a closing bracket missing
    }else {
        $scope.recordInstrument = 0;
    }
}).error(function () {
    $scope.error = "An Error has occured while Editing this Store Page!" + data;
});

Fixed

});
  };  // added a close bracket
    }else {
        $scope.recordInstrument = 0;
    }
}).error(function () {
    $scope.error = "An Error has occured while Editing this Store Page!" + data;
});