0

I have a controller action in ASP.Net Core that is returning a BadRequest with some model state. I want to flatten the validation messages into a single array within my Angular promise error handler. I'm not sure how to go about doing it though.

This is how I am returning the BadRequest in my Web API controller action.

return base.BadRequest(base.ModelState);

Then in my Angular controller, I have an error handler like this for now.

(function () {
    angular.module('app')
        .controller('AccountCreationController', AccountCreationController);

    function AccountCreationController(AccountCreationService) {
        var viewModel = this;
        viewModel.accountSetup = AccountCreationService.getAccountTypes();
        viewModel.create = create;
        viewModel.errors = new Array();

        function create(user) {
            var result = AccountCreationService.createAccount(user).$promise.then(function (response) {
                var x = response;
            },
            function (error) {
                // iterate over each key in the key/value pair.
                for (var key in error.data) {
                    // iterate over each element in the data[key] array of validation messages
                    for (var e in error.data[key]) {
                        errors.push(e);
                    }
                }
            });
        }
    }
})();

The error object has a data property on it, that contains the model state array. The model looks like this:

enter image description here

I can get access to the array of validation messages by typing error.data["1"] into the Chrome console, and I can get the message shown in the screenshot with error.data["1"][0]. However, when I try to iterate over the data property to pull out the errors into a flattened array, the array is empty. I'm not sure what I'm doing wrong here (new to JS) - I was iterating over each key in the data property, then iterating over each value in the array held for that key.

What am I supposed to do in order to get the underlying array of messages out?

edit

If I run the for loop in the Chrome console, I get the following output

var errors = new Array();
for (var key in error.data) {
    for (var e in error.data[key]) {
        console.log(key + ":" + e[0]);
    }
}

1:0

Johnathon Sullinger
  • 7,097
  • 5
  • 37
  • 102
  • [Avoid](http://stackoverflow.com/a/3010848/758991) the `for..in` for iterating over array. Also you can not iterate at all here. Just use `errors = errors.concat(error.data[key])` – Ruslan Stelmachenko Jan 02 '17 at 02:31
  • had a similiar question to yours here http://stackoverflow.com/questions/33545909/displaying-invalid-modelstate-in-web-api-via-jquery-ajax only difference is I was using knockout instead of angular – Bryan Dellinger Jan 02 '17 at 02:36
  • @djxak Like `for(var key in error.data) { viewModel.errors.concat(error.data[key])}` ? That doesn't yield an array with any values. Am I doing it wrong? – Johnathon Sullinger Jan 02 '17 at 02:43
  • 1
    No. The `concat` doesn't change the array. It creates a new array. So it should be `for(var key in error.data) { viewModel.errors = viewModel.errors.concat(error.data[key])}` – Ruslan Stelmachenko Jan 02 '17 at 02:55
  • 1
    Also note: in your origina question you push strings to the `errors` variable, but actually your variable is defined as `viewModel.errors`. About your **edit**: the `e` is the key name, or array index in this case, so `e[0]` is pointless. use `error.data[key][e]`. – Ruslan Stelmachenko Jan 02 '17 at 03:09

2 Answers2

1
  1. You push strings into the errors variable, but actually your variable is defined as viewModel.errors.

  2. Avoid the for..in loop for iterating over array. See this answer for more details why.

  3. If you after all use for..in loop, the e variable will be an array index, not a value. So you should use viewModel.errors.push(error.data[key][e]); instead if errors.push(e).

  4. Because your errors array already is array of plain strings, you can avoid inner loop at all here. Just use viewModel.errors = viewModel.errors.concat(error.data[key]).

Community
  • 1
  • 1
Ruslan Stelmachenko
  • 4,987
  • 2
  • 36
  • 51
  • That worked great! Also appreciate the correction on my usage of `e`. I didn't realize it was giving me back an index - which makes sense now that I look at it. – Johnathon Sullinger Jan 02 '17 at 19:20
-1

Use this to access the validation messages

error.data[1].0
Aravind
  • 40,391
  • 16
  • 91
  • 110
  • How do I do that recursively though? I want to take all validation messages and stuff them into a single array. Each Key/Value pair represents an array of messages. As mentioned in my OP, I can access them directly like you show, within the console. My foreach loop though doesn't have the expected result – Johnathon Sullinger Jan 02 '17 at 02:29
  • sure after solving your problem I will update the answer.. The point is I need to see the data binding into the objects for every error. – Aravind Jan 02 '17 at 02:33
  • I did. Your answer doesn't give me what the question asked. My OP specifically mentioned I could get the data using your approach via the console, but needed a way to flatten each array in the Key/Value pair without hard-coded key/indexes. Your answer just duplicates what I already tried and doesn't give the desired result – Johnathon Sullinger Jan 03 '17 at 01:42