Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ngf-model-invalid not compatible with ng-messages #1335

Closed
adamreisnz opened this issue Feb 7, 2016 · 17 comments
Closed

ngf-model-invalid not compatible with ng-messages #1335

adamreisnz opened this issue Feb 7, 2016 · 17 comments

Comments

@adamreisnz
Copy link

Hi, first of all, I'm very impressed with how far this plugin has come and how much is possible to do with it out of the box. It's matured a lot over the past year.

I have an issue I hope you can help with. I would like to use ng-messages to show validation errors coming out of ng-file-upload. However, the only way to do that currently seems to be by using a form and file input field.

My UI doesn't have that, instead I am using the file drop functionality in combination with a button to select files. So when browsing the documentation, I found the directive ngf-model-invalid, thinking it could be used for displaying errors with ng-messages.

The format of the error model however is incompatible with ng-messages or with the form.field.$error output; it expects something along the lines of:

invalidFiles[0].$error = {
  pattern: true,
  required: true
}

but instead it gets:

invalidFiles[0].$error = 'pattern'

Could you make the latter compatible by setting the $error field to be an object hash with the relevant errors in there?

Thanks.

@adamreisnz adamreisnz changed the title ngf-invalid-model not compatible with ng-messages ngf-model-invalid not compatible with ng-messages Feb 7, 2016
@danialfarid
Copy link
Owner

For now you can just have a pre processor to convert the $error to that format when the invalid model is changed.

@adamreisnz
Copy link
Author

Yep, that'll have to do for now :)

@adamreisnz
Copy link
Author

Also, for simplicity's sake, perhaps if multiple files is not enabled, ngf-model-invalid could just set a simple error object instead of an array.

@adamreisnz
Copy link
Author

As for watching the error object, I'm having trouble getting Angular to watch the object for changes. $watchCollection doesn't fire when the error is populated. Are you calling any $scope.$digest() or $scope.$apply() after setting the errors?

@danialfarid
Copy link
Owner

The files will not be returned until the errors are set so if you just watch the model object of file array they should already have the errors.
For comment above that create a new issue please.

@danialfarid
Copy link
Owner

You can also have ngf-change and do your error handling there?

@adamreisnz
Copy link
Author

I've tried to check the error object in the ngf-select and ngf-drop handler function, however, while $file entered there is null, the invalid model remains an empty array for some reason. If I access it in the HTML like {{invalid}} it works fine, but a simple console.log($scope.invalid) yields [].

I've given up on this for now, so just resort to checking if the file passed in on select is null and then manually set an error flag.

@danialfarid
Copy link
Owner

Fixed at 12.0.1 use file.$errorMessages which is a mapping of errors.

@adamreisnz
Copy link
Author

Thanks 👍

@stevehanson
Copy link

In case anyone else is trying to figure out how to make this work, I got it to work like this:

<div ng-messages="form.file.$error">
  <div ng-message="maxSize">The file must be less than 2MB</div>
  <div ng-message="minHeight">The file must be at least 100px high</div>
</div>

@adamreisnz
Copy link
Author

Well, the whole point was that it can be used when you are not using a file input element, but instead a drop area, or a button. In that case you have no form.file.$error field as there will be no form.file object.

@danialfarid could you clarify how we access the new $errorMessages object? Is it on invalidFiles[0].$errorMessages where invalidFiles is the model for ngf-model-invalid?

@danialfarid
Copy link
Owner

Yes but since version 12.0.x ngf-model-invalid will be bound to single file instead of array if it is not multiple just like ng-model.

@michelem09
Copy link

How to use ng-messages with ngf-drop? Is it possible?

@adamreisnz
Copy link
Author

@michelem09 should be able to do the following now, please correct me if I'm wrong @danialfarid :

$scope.invalidFile = {};
<div ngf-drop="selectedFile($file)" ngf-model-invalid="invalidFile"></div>
<div ng-messages="invalidFile.$errorMessages">
  <div ng-message="maxSize">The file must be less than 2MB</div>
  <div ng-message="minHeight">The file must be at least 100px high</div>
</div>

This is when multiple files is not enabled. Otherwise, the invalidFile should be an array of files with errors, e.g.:

$scope.invalidFiles = [];
<div ngf-drop="selectedFile($file)" ngf-model-invalid="invalidFiles"></div>
<div ng-repeat="invalidFile in invalidFiles" ng-messages="invalidFile.$errorMessages">
  <div ng-message="maxSize">The file must be less than 2MB</div>
  <div ng-message="minHeight">The file must be at least 100px high</div>
</div>

@austpere
Copy link

austpere commented May 5, 2016

@adambuczynski Thank you for that answer! I have been attempting to make the error message go away if the user uses the correct files afterwards. Is there a way to add ng-pristine to the messages as well?

@adamreisnz
Copy link
Author

@austin4perezident I believe I just manually cleared/reset the error object when a new file was selected. It was the easiest way to do it from what I remember.

@razblack
Copy link

razblack commented May 8, 2016

This may be a bit over-kill for your project, but I found that you can create a custom validation directive to handle messaging outside ng-file-upload internal system that should work with ngMessages. It does require you to be using your own view-model services though for tracking file selection changes and applying those selected and adding them to your model. This takes a bit of work to setup right, but can be implemented in a view-model service by adding functions to the model, and calling those functions via ngf-select and/or ngf-before-model-change. When you specify the ng-model for ng-file-upload, that model basically becomes a temporary container for actions in your view-model service. Passing $file or $newFiles directly to your model function, applying those to your own file lists and then clearing the ng-model. (this does not work with ngf-keep; however, if you're using your own view-model service you don't want it to keep them anywayd ). You can also then use some of ng-file-upload validation to prevent undesired files from being selected in the first place.

(ie: ngf-pattern: "'.jpg'" or ngf-min-height="1080")

Creating a custom validation will also allow you to take advantage of MutationObservers to automatically detect an attribute change you want to be looking for on the element containing say, a thumbnail image.

an example of a custom validation that gets attached to an img tag:

//myImageValidationDirective.js

(function () {
    "use strict";

    angular.module("app").directive('myImagevalidation', function () {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function (scope, element, attrs, ctrl) {

                var observer = new MutationObserver(function (mutations) {
                    mutations.forEach(function (mutation) {
                        if (mutation.attributeName === 'src') {
                            //validate data
                            ctrl.$validators.myImagevalidation = function (modelValue, viewValue) {
                                //examine file in my view-model
                                if (modelValue.file == null) {
                                    return false;
                                } else {
                                    return true;
                                }
                            }
                        };
                    })
                });

                observer.observe(element[0], {
                    attributes: true
                });
            }
        };
    });
})();

In HTML side for viewing the preview or thumbnail:

<img ng-show="item.image.file" ngf-thumbnail="item.image.file" ngf-size="{width: 320, height: 180, quality: 0.9}" name="myimageValid" ng-model="item.image" my-imagevalidation>

In HTML side for setting an 'ok' button that this form is valid:

<input class="btn btn-primary" type="submit" ng-click="ok()" value="OK" ng-disabled="myimageValid.$error" />

Notice these:

  • In the directive, its' return value is set in ctrl.$validators.myImagevalidation function, which checks the model I pass into it (which is outside the scope passed into the ng-file-upload control)
  • I can check any value within that model I pass into the custom validation (in this case, i passed in "Item.image", which is my own view-model container), and I provide it with a name ("myimageValid")
  • the name gets applied to the scope with the result of my validation which I can now check and in my case, disable the 'OK' button (ng-disabled="myimageValid.$error)
  • the mutation observer, examines any change to the attributes of img tag. I want to verify on my own, if the view-model I created is valid or not

You should now be able to use myimageValid.$error with ngMessages too... I haven't tested that, but it should work and is not longer dependent upon any standard 'form' validations (such as: text, number, url, email, date, radio, checkbox )

https://docs.angularjs.org/guide/forms (scroll down to "custom validation" )

"If" you needed to check the value or file against other parts of your view-model, it would be easy by injecting your view-model service into the directive... then you can call your service, get a value from some other view-model part.. and compare it to the changed element and provide your result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants