Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

md-chips with autocomplete: pressing enter to select not working with angular 1.4 #3833

Closed
webley opened this issue Jul 21, 2015 · 27 comments
Closed
Assignees
Milestone

Comments

@webley
Copy link

webley commented Jul 21, 2015

I'm using angular material 0.10.1-rc2 and angular 1.4.2. Selecting items in the autocomplete using the mouse is working fine. However, selecting an item by pressing "enter" results in an empty or malformed chip. This is happening with the demo autocomplete chips as well as contact chips.

http://codepen.io/davidwolsey/pen/bdxewm

@matteocarde
Copy link

I had the same problem. Put md-autocomplete-snap="" md-require-match="" in the md-chips

@webley
Copy link
Author

webley commented Jul 21, 2015

Thanks smile, but the codepen demo already has both of those set, and in fact I don't want to use md-require-match. This is just behaviour that's changed from angular 1.3 to 1.4.

@sousandrei
Copy link

(correct me if im wrong, but as i have the same problem and want to support this issue i should comment +1?)
+1

@stevenmiles
Copy link

Having the same issue with 0.10.1-rc2 and angularjs 1.4.3.

@yigaldviri
Copy link

+1

@ilanbiala
Copy link
Contributor

Still having this issue with rc3 and 1.4.3.

@gauravbhavsar
Copy link

Same issue in md-contact-chips with angular-material v0.10.0-master-cd3e8a1 and angularJS v1.4.2

@huijari
Copy link

huijari commented Jul 23, 2015

+1

@schmkr
Copy link

schmkr commented Jul 27, 2015

+1 (using angular: 1.4.3 and angular-material: 0.10.1-rc3-master-eda4782)

@schmkr
Copy link

schmkr commented Jul 28, 2015

Yesterday's released 0.10.1-rc4 still has this issue. You can see for yourself on the demos page and start typing a name in the Contact Chips section. When you select a contact with a mouse click, everything works like before. However, when you press enter/return to confirm a autocomplete suggestion, the result is an empty chip.

@ThomasBurleson ThomasBurleson added the needs: review This PR is waiting on review from the team label Jul 31, 2015
@ThomasBurleson ThomasBurleson modified the milestone: REVISIT Jul 31, 2015
@ThomasBurleson ThomasBurleson added needs: review This PR is waiting on review from the team and removed needs: review This PR is waiting on review from the team labels Jul 31, 2015
@andreialecu
Copy link

#3900 is related.

@davidlmiller21
Copy link

Issue has to do with this:

MdChipsCtrl.prototype.inputKeydown = function(event) {
  var chipBuffer = this.getChipBuffer();
  switch (event.keyCode) {
    case this.$mdConstant.KEY_CODE.ENTER:
      if (this.$scope.requireMatch || !chipBuffer) break;
      event.preventDefault();
      this.appendChip(chipBuffer);
      this.resetChipBuffer();
      break;
    case this.$mdConstant.KEY_CODE.BACKSPACE:
      if (chipBuffer) break;
      event.stopPropagation();
      if (this.items.length) this.selectAndFocusChipSafe(this.items.length - 1);
      break;
  }
};

Is the point of enter to make a custom chip from the user input text? Otherwise, this is the simple easy fix to get enter to select the highlighted element:

MdChipsCtrl.prototype.inputKeydown = function(event) {
  var chipBuffer = this.getChipBuffer();
  switch (event.keyCode) {
    case this.$mdConstant.KEY_CODE.ENTER:
      // DO NOTHING
      break;
    case this.$mdConstant.KEY_CODE.BACKSPACE:
      if (chipBuffer) break;
      event.stopPropagation();
      if (this.items.length) this.selectAndFocusChipSafe(this.items.length - 1);
      break;
  }
};

@ngraef
Copy link
Contributor

ngraef commented Aug 6, 2015

@davidlmiller21 The code you removed is needed for chips without autocomplete.

After some debugging, the underlying issue here seems to be that requireMatch isn't being set as expected in the MdChipsDirective scope (from the attribute mdRequireMatch). This causes the chips controller to not break out of the keydown handler, and it ends up appending a chip using the input text (chipBuffer). The chip buffer then gets cleared, which resets the autocomplete's matches. So by the time MdAutocompleteCtrl selects the item (delayed using $mdUtil.nextTick), ctrl.matches is empty and there is no autocomplete item to select.

As shown in this demo (modified to use strings instead of objects), the chip buffer is getting added as a chip. This shows up as () in the original demo because the text chip doesn't have a name or type property.

@houmark
Copy link

houmark commented Aug 6, 2015

@ngraef Interesting findings there. Did you manage to make a fix? If you have a chunk of code to potentially correct it I would be happy to test it out :) We are quite bothered by this particular bug as we are using chips quite a lot.

@ngraef
Copy link
Contributor

ngraef commented Aug 7, 2015

@houmark After a little more digging, the issue is in chipsController.js line 87:

if (this.$scope.requireMatch || !chipBuffer) break;

The mdChips directive defines bindToController: true, which binds the directive's isolate scope properties to MdChipsCtrl's this _instead of_ $scope. So the simple solution here is to change the above code to:

if (this.requireMatch || !chipBuffer) break;

Now, we also have to declare an explicit true value for mdRequireMatch on mdChips otherwise it will be undefined:

<md-chips md-require-match="true" ... >

So an additional fix is needed in order to maintain the current md-require-match="" syntax, but I personally think having an explicit value is good.

@houmark
Copy link

houmark commented Aug 7, 2015

Thanks for that @ngraef, I will give it a spin and provide feedback :)

@ThomasBurleson ThomasBurleson modified the milestones: 0.11.0, REVISIT Aug 7, 2015
@ThomasBurleson ThomasBurleson removed the needs: review This PR is waiting on review from the team label Aug 7, 2015
@ngraef
Copy link
Contributor

ngraef commented Aug 7, 2015

I believe there's also an issue here with event propagation. I don't think the keydown event on the autocomplete dropdown should propagate to the chips. In the use case where you don't want md-require-match="true" (e.g. being able to select a predefined tag from the autocomplete list or optionally create a new tag from the input value), this propagation becomes an issue.

@metamatt
Copy link

I saw this problem using mdAutocomplete and mdChips together and stepped through the code adding a bunch of logging. The problem I see is that both mdAutocomplete and mdChips attach a keydown event handler, and both of these keydown event handlers run. When you select an entry from the autocomplete dropdown by pressing Enter, mdAutocomplete.keydown calls mdAutocomplete.select which defers most of its work via $mdUtils.nextTick, during which time mdChips.keydown runs and calls resetChipBuffer. When mdAutocomplete.select starts running, the $scope.searchText is valid, but by the time it gets called back via nextTick, the mdChips resetChipBuffer has cleared the mdAutocomplete searchText and handleSearchText has cleared the matches list.

I haven't tried using md-require-match but I don't think I want that behavior anyway.

Near as I can tell, if both keydown event handlers are supposed to run, they should both progress at the same rate -- either both deferred via nextTick or neither deferred.

@typotter
Copy link
Contributor

duplicate of #3475

@jherman
Copy link

jherman commented Oct 23, 2015

Still seeing this issue:
https://codepen.io/anon/pen/KdQJpW?editors=101

Type in "ca", cabbage will pop up and be auto selected. Hit 'enter'. You'll see two chips get added - what you searched for and the cabbage chip. Expecting only the cabbage chip.

@houmark
Copy link

houmark commented Oct 23, 2015

@jherman Try this codepen that has a different configuration <md-chips md-require-match="true">:
https://codepen.io/houmark/pen/YyeBWo?editors=101

This is a fork of yours and the only change is false to true for the above configuration.

@jherman
Copy link

jherman commented Oct 23, 2015

The problem here, is that you can't enter in new chips if they aren't found. I think one of the devs are looking into on #3475. I had to insert a one liner to fix the issue. You can see my remarks there. Thanks!

@houmark
Copy link

houmark commented Oct 23, 2015

You didn't say that it was a requirement to be able to add with chips :) In that case you might still have issues as you also have noticed - the fix was only a part fix and hopefully a better one for all use cases will happen at some point...

@ronwong82
Copy link

How can we make md-chips with auto complete accept only valid email address? i use md-on-append and try to load contacts (email address) from db and at the same time type email address to add to to the contacts.

@ghost
Copy link

ghost commented Nov 19, 2015

md-require-match="true" works for me

@sirlero
Copy link

sirlero commented Dec 3, 2015

md-require-match="true" works but if you wanna add new items?

@Baloche
Copy link

Baloche commented Jan 13, 2017

Based on the previous comments, here is a complete fix that worked well for my problem :)

angular.module('material.components.chips')

  // here we need to rewrite the 'inputKeyDown' method of the mdChipsCtrl in order to prevent empty chips when the user hits ENTER.
  .config(function($provide) {
    $provide.decorator('mdChipsDirective', function($delegate) {
      
      // get directive
      var directive = $delegate[0];

      // get compile method
      var oldCompile = directive.compile;

      // rewrite compile method
      directive.compile = function() {

        return {

          // return original postLink method in 'post' attribute
          post: oldCompile.apply(this, arguments),

          // create a preLink method to access controller
          pre: function(scope, element, attrs, ctrls) {

            // get original 'inputKeyDown' method
            var inputKeyDown = ctrls[0].inputKeydown;

            // and rewrite it with the fix
            ctrls[0].inputKeydown = function() {

              // if ENTER key pressed, do the magic trick
              if (event.keyCode === this.$mdConstant.KEY_CODE.ENTER) {
                var chipBuffer = this.getChipBuffer();
              }
              
              // else call original method
              else {
                return inputKeyDown.apply(this, arguments);
              }

            };
          }
        };
      };
      return $delegate;
    });
  });

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