How to render errors to client? AngularJS/WebApi ModelState

angularjs, asp.net-web-api, modelstate, validation

Solution

When making your call to your server, capture the error based upon the rejection of the `$http` promise.

Then in your controller I would suggest flattening the response to an array of errors upon handling of the error for display as shown in this fiddle example:

for (var key in resp.ModelState) {
    for (var i = 0; i < resp.ModelState[key].length; i++) {
        errors.push(resp.ModelState[key][i]);
    }
}

To put it all together:

// Post the data to the web api/service
$http.post(url, data)
    .success(successHandler)
    .error(function (response) {
        // when there's an error, parse the error
        // and set it to the scope (for binding)
        $scope.errors = parseErrors(response);
    });

//separate method for parsing errors into a single flat array
function parseErrors(response) {
    var errors = [];
    for (var key in response.ModelState) {
        for (var i = 0; i < response.ModelState[key].length; i++) {
            errors.push(response.ModelState[key][i]);
        }
    }
    return errors;
}

Problem

I'm building an AngularJS SPA application with WebApi for the backend. I am using attributes for model validation on the server, if validation fails this is what I return from the ModelState. ``` {"Message":"The request is invalid.","ModelState":{"model.LastName":["Last Name must be at least 2 characters long."]}} ``` How do I then render this to the client with AngularJS? ``` //Save User Info $scope.processDriverForm = function(isValid) { if (isValid) { //set button disabled, icon, text $scope.locked = true; $scope.icon = 'fa fa-spinner fa-spin'; $scope.buttonText = 'Saving...'; $scope.submitted = true; $scope.formData.birthDate = $scope.formData.birthMonth + '/' + $scope.formData.birthDay + '/' + $scope.formData.birthYear; $http({ method: 'POST', url: 'api/Account/Register', data: $.param($scope.formData), headers: { 'Content-Type': 'application/x-www-form-urlencoded' } // set the headers so angular passing info as form data (not request payload) }) .success(function (data) { console.log(data); toastr.success('User ' + $scope.formData.username + ' created!'); $scope.userForm.$setPristine(); $scope.formData = {}; //reset the button $scope.locked = false; $scope.icon = ''; $scope.buttonText = 'Save'; //reset validation submitted $scope.submitted = false; }) .error(function (data, response) { console.log(data); toastr.error('Ooops! There was an error creating the user. Try again and if the problem persists, contact Support.'); //reset the button $scope.locked = false; $scope.icon = ''; $scope.buttonText = 'Save'; $scope.submitted = false; var resp = {}; var errors = []; for (var key in resp.ModelState) { for (var i = 0; i < resp.ModelState[key].length; i++) { errors.push(resp.ModelState[key][i]); } } $scope.errors = errors; }); } else { toastr.warning('Invalid User Form, correct errors and try again.'); } }; ```

Original source