Misha Tsvelik
Misha Tsvelik

Reputation: 53

Angular Materials md-select and trackBy allowing options to be selected

I'm trying to customise this Angular Material example code (https://material.angularjs.org/latest/api/directive/mdSelect) to my needs.

I have three groups of select options. If an option is selected in a group, it should unselect all options in other groups (but leave other options in own group as they are).

In my code I have managed to get the logic working right (as you will see from the console.log outputs at the bottom), but the actual select options do not interact with user input.

My JSFiddle: https://jsfiddle.net/e2LLLxnb/8/

My JS code:

var myModule = angular.module('BlankApp', ['ngMaterial']);
myModule.controller("FilterCtrl", function($scope, $element) {

  $scope.categories = ["Any", "Target Category", "Option 1", "Option 2", "Option 3", "Option 4"];

            $scope.mustCatSelected;

            $scope.categoryObj = {};
            // build the list of options with values and groups - create equivalent of $scope.data for <md-option ng-repeat="item in categoryObj.data.items"> 
            var finGroup = [];
            $scope.categories.forEach(function(value,key){
                if(key>1){
                    finGroup.push(key);
                };

            });

            $scope.categoryObj.data = {items: [], groups: [{
                                                            group: [0]
                                                          }, {
                                                            group: [1]
                                                          }, {
                                                            group: finGroup
                                                          }]};  

            $scope.categories.forEach(function(value,key){

                $scope.categoryObj.data.items.push({name: value,
                                                    value: false,
                                                    id: (key + 1)});

            });


            $scope.clickOn = function(item, index) {

             if(item.value == false){item.value = item.name;}
             else {item.value = false;}

              if (item.value === false) {

              } else {

                var thisGroup = [];
                angular.forEach($scope.categoryObj.data.groups, function(value, key) {

                  if (value.group.indexOf(index) !== -1) {
                    thisGroup = value.group;
                  }
                });



                angular.forEach($scope.categoryObj.data.items, function(value, key) {

                  if (thisGroup.indexOf(key) !== -1) {
                    return;
                  } else {
                    value.value = false;
                    }
                });

                $scope.mustCatSelected = $scope.categoryObj.data.items.filter(function(e){


                            return e.value != false;

                });             
                console.log($scope.mustCatSelected);                
                console.log($scope.categoryObj.data.items); 

              }


            }           


            //search-term header
            $scope.searchTerm;
            $scope.clearSearchTerm = function() {
                $scope.searchTerm = '';
            };
              // The md-select directive eats keydown events for some quick select
              // logic. Since we have a search input here, we don't need that logic.
            $element.find('input').on('keydown', function(ev) {
                  ev.stopPropagation();
            });



});

Upvotes: 0

Views: 576

Answers (1)

Misha Tsvelik
Misha Tsvelik

Reputation: 53

Solved (finally!): https://jsfiddle.net/hqck87t1/4/

    var myModule = angular.module('BlankApp', ['ngMaterial']);
    myModule.controller("FilterCtrl", function($scope, $element) {

              $scope.categories = ["Any", "None", "Option 1", "Option 2", "Option 3", "Option 4"];

                $scope.mustCatSelected = [];

                $scope.categoryObj = {};
                $scope.categoryObj.items = [];  
                $scope.categories.forEach(function(value,key){
                    var grp;
                    if (key < 2){grp = key;}
                    if (key >= 2){grp = 2;}
                    $scope.categoryObj.items.push({
                                                        name: value,
                                                        id: (key + 1),
                                                        group: grp});                       
                });         
                //set default
                $scope.mustCatSelected.push($scope.categoryObj.items[0]);






                $scope.clickOn = clickOn;
                function clickOn(newValue, oldValue, type) {

                    //console.log($scope.categoryObj.items);
                    //console.log(oldValue);
                    if(oldValue.length == 0) { 
                        return false; 
                    }

                    //create arrays of new and old option ids
                    oldValue = JSON.parse(oldValue);
                    var newIds = [];
                    var oldIds = [];

                    newValue.forEach(function(value,key){

                        newIds.push(value.id);

                    });

                    oldValue.forEach(function(value,key){

                        oldIds.push(value.id);

                    });

                    //define and set the clicked value
                    var clickedValue; 
                    newIds.forEach(function(value, key){

                        if(oldIds.indexOf(value) == -1) {
                            clickedValue = value;
                        }

                    });

                    var clickedGroup;
                    newValue.forEach(function(value,key){

                        if(value.id == clickedValue){

                            clickedGroup = value.group;

                        }

                    });

                    //console.log([clickedValue, clickedGroup]);    
                    //console.log([newIds, oldIds, clickedValue]);
                    if(type == 'mustCat'){
                        $scope.mustCatSelected = $scope.mustCatSelected.filter(function(e){

                                return e.group == clickedGroup;

                        });
                    }

                }


                //search term above select
                $scope.searchTerm;
                $scope.clearSearchTerm = function() {
                    $scope.searchTerm = '';
                };
                  // The md-select directive eats keydown events for some quick select
                  // logic. Since we have a search input here, we don't need that logic.
                $element.find('input').on('keydown', function(ev) {
                      ev.stopPropagation();
                });



    });

There key to the solution lies in two things:

  1. Using ng-change instead of ng-click. The former is used to distinguish the state of ng-model inline vs the specified state of ng-model after the change event. Whereas ng-click is not reliable for this.

  2. Write the ng-change function in the html like this: ng-change="clickOn(mustCatSelected, '{{mustCatSelected}}')" where mustCatSelected is the ng-model and '{{mustCatSelected}}' the inline state of ng-model before the change event.

Now we have an multiple md-select with logic handling the selection of options / groups of options.

Upvotes: 1

Related Questions