Skip to content
This repository was archived by the owner on Sep 8, 2020. It is now read-only.

select2 is never marked valid #6

Closed
Coneko opened this issue May 3, 2013 · 23 comments
Closed

select2 is never marked valid #6

Coneko opened this issue May 3, 2013 · 23 comments

Comments

@Coneko
Copy link
Contributor

Coneko commented May 3, 2013

http://plnkr.co/edit/w1TW1j

It's correctly marked as ng-invalid and ng-invalid-required, but when you choose an option the classes aren't updated. Note that if you inspect the select element which select2 hides, that one's classes are updated correctly.

(Brought over from angular-ui/angular-ui-OLDREPO#531, updated the plunker, same issue is still there.)

@ProLoser
Copy link
Member

ProLoser commented May 3, 2013

Interesting, guess we'll have to do $attrs.$observe('class') or something. The problem is that it's easy to simply ADD all the classes, but $observe doesn't really give us a good way to check the delta (to remove classes). I don't know a good way to resolve this issue.

@Coneko
Copy link
Contributor Author

Coneko commented May 3, 2013

Checking for those particular classes is also not a good idea, since ideally you'd want all angular classes to be kept in sync. Notice how ng-pristine and ng-dirty have the same problem.

@DiegoPires
Copy link

I know it's a ugly solution, but I did this modification in the directive we are using here in my job:

[...]

            controller.$parsers.push(function (value) {
                if (controller.$valid)
                    setValid(elm.prev());
                if (!controller.$valid)
                    setInvalid(elm.prev());
                if (controller.$pristine)
                    setPristine(elm.prev());
                if (controller.$dirty)
                    setDirty(elm.prev());
            });
            var setPristine = function (div) {
                if (div.hasClass("ng-dirty")) {
                    div.removeClass("ng-dirty");
                    div.addClass("ng-pristine");
                }
            }

[...]

@ProLoser
Copy link
Member

ProLoser commented May 6, 2013

Mind opening a pull request? Also, don't pass a reference to the DOM element, I would just access it directly. And remember you can chain the removeClass().addClass() etc so I wouldn't bother even creating functions.

@DiegoPires
Copy link

You mean, like this?

            controller.$parsers.push(function (value) {
                var div = elm.prev()
                if (controller.$valid) {
                    div.removeClass("ng-invalid").addClass("ng-valid");
                    div.removeClass("ng-invalid-required").addClass("ng-valid-required");
                }
                if (!controller.$valid) {
                    div.removeClass("ng-valid").addClass("ng-invalid");
                    div.removeClass("ng-valid-required").addClass("ng-invalid-required");
                }
                if (controller.$pristine)
                    div.removeClass("ng-dirty").addClass("ng-pristine");
                if (controller.$dirty)
                    div.removeClass("ng-pristine").addClass("ng-dirty");
                return value;
            });

Really better actually... I have forget to return the value too, otherwise it breaks the update of the model value

@danbarua
Copy link

danbarua commented May 7, 2013

@DiegoPires that works for me, thanks.

@ProLoser
Copy link
Member

ProLoser commented May 7, 2013

Please open a pull request instead of pasting it into an issue
On May 7, 2013 8:44 AM, "Dan Barua" [email protected] wrote:

@DiegoPires https://github.com/DiegoPires that works for me, thanks.


Reply to this email directly or view it on GitHubhttps://github.com//issues/6#issuecomment-17550479
.

@DiegoPires
Copy link

Sure @ProLoser, I've posted just to make sure it was a good solutions, now I just need to learn how to create the pull request...

@martijnsenden
Copy link

Hi,

I just downloaded the source code, which includes this fix. I still get a dropdown that is dirty and invalid when the form opens.
I put a breakpoint on the 'return value' line just after all the toggleClass() calls. I noticed that although the browser does run through this part of the code when my form loads, it doesn't set the classes properly. I still get a ng-invalid, ng-invalid-required and ng-dirty form element instead of an ng-valid, ng-valid-required and ng-pristine form element.
Do I need to set any options to make this work correctly?

This is my directive:

        directives.directive('mySelector', function () {
            return {
                template: '<input id="mySelector" name="mySelector" ng-model="data.mySelector" ui-select2="select2Options" required /><br />',
                controller: 'mySelector.controller'
            };
        });

And this is my controller:

        controllers.controller('mySelector.controller', ['$scope', 'myService', function ($scope, myService) {
            var myResult = myService.get();

            $scope.select2Options = {
                placeholder: 'Choose something',
                data: { results: myResult, text: function (item) { return item.itemName; } },
                allowClear: false,
                formatResult: function (item) { return item.itemName; },
                formatSelection: function (item) { return item.itemName; }
            };
        }]);

Best regards,
Martijn Senden.

@anagelcg
Copy link

anagelcg commented Aug 2, 2013

Hi,
I have the same problem like "martijnsenden" although I used that fix. My form is always dirty ($dirty = true) when the form is loaded when using ng-repeat or the query-function. But when I use hard-coded options in html, everything works. That means:

This example below works.

<select ui-select2>
    <option value=""></option>
    <option value="1">one</option>
</select>

But when dynamically generating a combobox with select2 by using ng-repeat or the query-function in the select2-options, the form validiation is broken --> the $dirty-flag is true just after initialization. Example:

<select ui-select2>
    <option value=""></option>
    <option ng-repeat="item in items" value="item.value">{{item.text}}</option>
</select>

Can anybody help me? Thanks
Best regards.

@chrisg93
Copy link

Hi,

I have the same problem as @anagelcg. Using ngRepeat, the select field is set to dirty after initialization. Despite, unlike @martijnsenden, the form is valid.

Here is a Plunker: http://plnkr.co/edit/DwzccaqEJQDzZx7auqUD?p=preview

Maybe this issue could be re-opened?

Thanks.
Best regards.

@fxck
Copy link

fxck commented Aug 22, 2013

Same.

@dhoffman34
Copy link

I tried changing angular-ui-select2.js to be have the following at around line 140:

      if (!opts.initSelection && !isSelect) {
        controller.$setViewValue(elm.select2('data'));
        elm.parent().controller('form').$setPristine()
      }

This seems to work, though it requires the unstable version of AngularJS.

@manikantag
Copy link

I've the same problem. Form was set to dirty, but valid.

@MattWalker
Copy link

This line appears to be the culprit. It's recommended to make sure newVal != oldVal in a watch if you don't want it to execute on initialization.

We've patched ours like so:

          if (watch) {
            scope.$watch(watch, function (newVal, oldVal, scope) {
              if (angular.equals(newVal, oldVal)) return;
              // Delayed so that the options have time to be rendered
              $timeout(function () {
                elm.select2('val', controller.$viewValue);
                // Refresh angular to remove the superfluous option
                elm.trigger('change');
              });
            });
          }

@rrpauls
Copy link

rrpauls commented Sep 19, 2013

MattWalker, great patch! Thanks!

@idangoldman
Copy link

@MattWalker, thanks for the patch! 👍

@thomaux
Copy link

thomaux commented Sep 30, 2013

At our project it seems the elm.trigger('change') is causing this issue. Any reason why this is present? Commenting it out does not seem to break functionality.

Edit: It does break, as I was afraid. Will look into a possible solution as @MattWalker's solution does not work for me.

@nadavst
Copy link

nadavst commented Oct 6, 2013

Hi,

I have tried everything you guys mentioned here, and I'm still having the same problem.

@anzeo: any news about you solution?

Thanks,

Nadavst.

@thomaux
Copy link

thomaux commented Oct 7, 2013

@nadavst I ended up writing a mock implementation of the $setPristine method introduced in angular 1.1.1.

@fxck
Copy link

fxck commented Jan 20, 2014

So there's no solution to this still?

@mavrickemman
Copy link

Still no solution for this?

@or29544
Copy link

or29544 commented Jul 30, 2014

Ok, it seems the form is marked invalid because it also takes into consideration the loading of the select elements. And because initially the select is empty and then it is loaded with the defined options, the select will always be marked dirty by default. The "dirty" means the select has been loaded with options.

I fixed this by changing line 120 from this:
if (angular.equals(newVal, oldVal)
to this:
if (angular.equals(newVal, oldVal) || oldVal == undefined) {

So basically I just check to see if the old value has not been defined before (because the select was empty). I have not yet tested all possible scenarios, but for me it works with this change and I am pretty confident the dirty is set because the select is loaded with the available options.

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

No branches or pull requests