Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular x-editable setError not displaying validation errors

I am using angular x-editable in my project. http://vitalets.github.io/angular-xeditable/#editable-row

Anything works fine except of validation error displaying. Here is my HTML template:

<table class="table">
        <thead>
            <tr>
                <th>Name</th>
                <th>Width</th>
                <th>Length</th>
                <th>Sheets quantity</th>
                <th>Low price</th>
                <th>High price</th>
                <th>Currency</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="material in sheetMaterials">
                <td>
                    <span editable-text="material.name" e-name="name" e-form="form" e-required>
                        {{ material.name }}
                    </span>
                </td>
                <td>
                    <span editable-text="material.width" e-name="width" e-form="form" e-required>
                      {{ material.width }}
                    </span>
                </td>
                <td>
                    <span editable-text="material.length" e-name="length" e-form="form" e-required>
                        {{ material.length }}
                    </span>
                </td>
                <td>
                    <span editable-text="material.sheets" e-name="sheets" e-form="form" e-required>
                        {{ material.sheets }}
                    </span>
                </td>
                <td>
                    <span editable-text="material.priceLow" e-name="priceLow" e-form="form" e-required>
                        {{ material.priceLow }}
                    </span>
                </td>
                <td>
                    <span editable-text="material.priceHigh" e-name="priceHigh" e-form="form" e-required>
                        {{ material.priceHigh }}
                    </span>
                </td>
                <td>
                    <span editable-select="material.currency"
                          e-ng-options="s.value as s.text for s in currencies"
                          e-name="currency"
                          e-form="form"
                          e-required>
                        {{ showCurrency( material ) }}
                    </span>
                </td>
                <td style="white-space: nowrap">
                    <form editable-form name="form"
                          onaftersave="updateSheetMaterial( $data, material._id, form )"
                          ng-show="form.$visible"
                          class="form-buttons form-inline"
                          shown="inserted == material">
                        <button type="submit"
                                ng-disabled="form.$waiting"
                                class="btn btn-primary">
                            Save
                        </button>
                        <button type="button"
                                ng-disabled="form.$waiting"
                                ng-click="form.$cancel()"
                                class="btn btn-default">
                            Cancel
                        </button>
                    </form>
                    <div class="buttons" ng-show="!form.$visible">
                        <button class="btn btn-primary" ng-click="form.$show()">
                            Edit
                        </button>
                        <button class="btn btn-danger" ng-click="removeSheeteMaterial( materials, $index )">
                            Delete
                        </button>
                    </div>  
                </td>
            </tr>
        </tbody>
    </table>
    <button class="pull-right btn btn-primary" ng-click="createSheetMaterial()">Add</button>

Here is a controller where I handle form behaviour:

angular.module( 'client' )
.controller(
    'materialController',
    [
        '$scope',
        '$filter',
        'sheetMaterialFactory',
        function(
            $scope,
            $filter,
            sheetMaterialFactory
        ){
            /**
             * index action
             * @return void
             */
            $scope.index = function(){
                $scope.currencies = [
                    { value: 'RUB', text: "Р" },
                    { value: 'EUR', text: "€" },
                    { value: 'USD', text: "$" },
                ]
                sheetMaterialFactory.getList().then( function( materials ){
                    $scope.sheetMaterials = materials;
                });
                $scope.content = "partials/material.html";
            }

            $scope.showCurrency = function( material ){
                var selected = $filter('filter')( $scope.currencies, { value: material.currency });
                return ( material.currency && selected.length ) ? selected[ 0 ].text : 'Not set';
            }

            /**
             * update sheet material
             * @param data – object of material options
             * @param _id – unique id of material
             * @return void
             */
            $scope.updateSheetMaterial = function( data, _id, form ){
                data._id = _id;
                var action = data._id ? "update" : "create";
                sheetMaterialFactory
                    [ action ]( data )
                    .then( function( sheetMaterial ){
                        if( "update" == action ){
                            var collection = $scope.sheetMaterials;
                            collection = collectionService.updateObject( collection, sheetMaterial );
                        } else {
                            collection.push( sheetMaterial );
                        }
                    }, function( error ){
                        if( error.data.errors ){
                            angular.forEach( error.data.errors, function( errorData, field ){
                                form.$setError( field, errorData.message );
                            });
                        } else {
                            form.$setError( 'name', 'Неизвестная ошибка' );
                        }
                    });
            }

            /**
             * create sheet material
             * @return void
             */
            $scope.createSheetMaterial = function( data ){
                if( !data ){
                    var sheetMaterial = { name: "Some name" };
                    $scope.sheetMaterials.push( sheetMaterial );
                    return;
                }
            }


            $scope.index();
        }
    ]
);

I've checked all the minor details and see that form.$setError works perfect. Error text really assigned to form element. But it does not displaying after form submitted. If anyone knows how to fix it – your reply is appreciated.

like image 927
zelibobla Avatar asked Aug 18 '14 08:08

zelibobla


2 Answers

I had similar problems, until I understood (actually read the docs) that validation of fields should be managed through onbeforesave. If you want to define validation for one or more elements, which was my case, you can do so by using onbeforesave on the editable-* elements like this:

// on template (using controller as ctrl)
<span editable-select="material.currency"
    e-ng-options="s.value as s.text for s in currencies"
    e-name="currency"
    e-form="form"
    onbeforesave="ctrl.validateNotEmpty($data)"
    e-required>
    {{ showCurrency( material ) }}
</span>

// on controller
vm.validateNotEmpty(val) {
    if (!val) {
        return "This is a required field";
    }
}

The validation method will be called and if it returns a string, then the form will remain open and the errors will be displayed as expected.

-- Update --

The above would apply to error-handling prior to sending the request. If the validation must be done server-side, then the usage of $setError is of course the right way to go. I just added validation to a form like this, and worked perfectly:

// on controller
vm.updateMethod = function() {
    return myHttpUpdateMethod(foo)
        .catch(function(errors) {
            // Extract field and error_msg
            $scope.form.$setError(field, error_msg);
            // very important, as we're catching the error reject the
            // promise here, to stop the form from closing.
            return $q.reject(errors);
        });
}

Here is a nice jsFiddle I found: http://jsfiddle.net/NfPcH/81/

But I had to use a catch instead of an error in my special case. If you also use a catch don't forget to return a reject, or else the form will close.

like image 85
andzep Avatar answered Sep 28 '22 12:09

andzep


Well, it seems I found one crappy solution. Not the best one, but it works. Any form element displaying should be typed this way:

<span editable-text="material.name" e-name="name" e-form="form" e-required>
    {{ material.name || form.$editables[ 0 ].error }}
</span>

form.$editables[ 0 ].error – is a direct access to errorText for element number 0 in form elements array. Solution is bad because you have to watch manually the index of your element and any form changes will cause fixing elements indexes.

like image 23
zelibobla Avatar answered Sep 28 '22 11:09

zelibobla