如何在Angularjs指令中使用动态ng-model

时间:2015-07-23 05:23:42

标签: javascript angularjs

我想在同一页面中使用多个指令。这些指令动态添加。可以在同一页面中我有2个指令或更多。如何将ng-model添加到指令中,当一个指令的更改值不改变其他指令时 此指令代码源为https://github.com/JustGoscha/allmighty-autocomplete



var app = angular.module('myApp', []);
app.directive('autocomplete', function () {
    var array1 =[ {title:"apple", value:1},{title:"sony", value:2},{title:"LG", value:3}];
    var array2 = [{title:"java", value:1},{title:"c++", value:2},{title:"c#", value:3}];
    var index = -1;
    return {
        restrict: 'E',
        scope: {
            url: '@',
            name: '@',
            searchParam: '=ngModel',
            onType: '=onType',
            onSelect: '=onSelect',
            autocompleteRequired: '='
        },
        controller: ['$scope', '$http', function ($scope, $http) {
           if($scope.url == 'url1')
                    $scope.Items = array1;
            if($scope.url == 'url2')
                    $scope.Items = array2;    

            $scope.getItems = function () {
                return $scope.Items;
            }
            // the index of the suggestions that's currently selected
            $scope.selectedIndex = -1;

            $scope.initLock = true;

            // set new index
            $scope.setIndex = function (i) {
                $scope.selectedIndex = parseInt(i);
            };

            this.setIndex = function (i) {
                $scope.setIndex(i);
                $scope.$apply();
            };

            $scope.getIndex = function (i) {
                return $scope.selectedIndex;
            };

            // watches if the parameter filter should be changed
            var watching = true;

            // autocompleting drop down on/off
            $scope.completing = false;

            // starts autocompleting on typing in something
            $scope.$watch('searchParam', function (newValue, oldValue) {

                if (oldValue === newValue || (!oldValue && $scope.initLock)) {
                    return;
                }

                if (watching && typeof $scope.searchParam !== 'undefined' && $scope.searchParam !== null) {
                    $scope.completing = true;
                    $scope.searchFilter = $scope.searchParam;
                    $scope.selectedIndex = -1;
                }

                // function thats passed to on-type attribute gets executed
                if ($scope.onType)
                    $scope.onType($scope.searchParam);
            });

            // for hovering over suggestions
            this.preSelect = function (suggestion) {

                watching = false;

                // this line determines if it is shown
                // in the input field before it's selected:
                //$scope.searchParam = suggestion;

                $scope.$apply();
                watching = true;

            };

            $scope.preSelect = this.preSelect;

            this.preSelectOff = function () {
                watching = true;
            };

            $scope.preSelectOff = this.preSelectOff;

            // selecting a suggestion with RIGHT ARROW or ENTER
            $scope.select = function (suggestion, value) {
                if (suggestion) {
                    $scope.val = value;
                    $scope.searchParam = suggestion;
                    $scope.searchFilter = suggestion;
                    if ($scope.onSelect)
                        $scope.onSelect(suggestion);
                }
                watching = false;
                $scope.completing = false;
                setTimeout(function () {
                    watching = true;
                }, 1000);
                $scope.setIndex(-1);
            };


        }],
        link: function (scope, element, attrs) {

            setTimeout(function () {
                scope.initLock = false;
                scope.$apply();
            }, 250);

            var attr = '';

            // Default atts
            scope.attrs = {
                "placeholder": "start typing...",
                "class": "",
                "id": "",
                "inputclass": "",
                "inputid": ""
            };

            for (var a in attrs) {
                attr = a.replace('attr', '').toLowerCase();
                // add attribute overriding defaults
                // and preventing duplication
                if (a.indexOf('attr') === 0) {
                    scope.attrs[attr] = attrs[a];
                }
            }

            if (attrs.clickActivation) {
                element[0].onclick = function (e) {
                    if (!scope.searchParam) {
                        setTimeout(function () {
                            scope.completing = true;
                            scope.$apply();
                        }, 200);
                    }
                };
            }

            var key = {left: 37, up: 38, right: 39, down: 40, enter: 13, esc: 27, tab: 9};

            document.addEventListener("keydown", function (e) {
                var keycode = e.keyCode || e.which;

                switch (keycode) {
                    case key.esc:
                        // disable suggestions on escape
                        scope.select();
                        scope.setIndex(-1);
                        scope.$apply();
                        e.preventDefault();
                }
            }, true);

            document.addEventListener("blur", function (e) {
                // disable suggestions on blur
                // we do a timeout to prevent hiding it before a click event is registered
                setTimeout(function () {
                    scope.select();
                    scope.setIndex(-1);
                    scope.$apply();
                }, 150);
            }, true);

            element[0].addEventListener("keydown", function (e) {
                var keycode = e.keyCode || e.which;

                var l = angular.element(this).find('li').length;

                // this allows submitting forms by pressing Enter in the autocompleted field
                if (!scope.completing || l == 0) return;

                // implementation of the up and down movement in the list of suggestions
                switch (keycode) {
                    case key.up:

                        index = scope.getIndex() - 1;
                        if (index < -1) {
                            index = l - 1;
                        } else if (index >= l) {
                            index = -1;
                            scope.setIndex(index);
                            scope.preSelectOff();
                            break;
                        }
                        scope.setIndex(index);

                        if (index !== -1)
                            scope.preSelect(angular.element(angular.element(this).find('li')[index]).text());

                        scope.$apply();

                        break;
                    case key.down:
                        index = scope.getIndex() + 1;
                        if (index < -1) {
                            index = l - 1;
                        } else if (index >= l) {
                            index = -1;
                            scope.setIndex(index);
                            scope.preSelectOff();
                            scope.$apply();
                            break;
                        }
                        scope.setIndex(index);

                        if (index !== -1)
                            scope.preSelect(angular.element(angular.element(this).find('li')[index]).text());

                        break;
                    case key.left:
                        break;
                    case key.right:
                    case key.enter:
                    case key.tab:

                        index = scope.getIndex();
                        // scope.preSelectOff();
                        if (index !== -1) {
                            scope.select(angular.element(angular.element(this).find('li')[index]).text(),
                                angular.element(angular.element(this).find('li')[index])[0].id);
                            if (keycode == key.enter) {
                                e.preventDefault();
                            }
                        } else {
                            if (keycode == key.enter) {
                                scope.select();
                            }
                        }
                        scope.setIndex(-1);
                        scope.$apply();

                        break;
                    case key.esc:
                        // disable suggestions on escape
                        scope.select();
                        scope.setIndex(-1);
                        scope.$apply();
                        e.preventDefault();
                        break;
                    default:
                        return;
                }

            });
        },
        template: '\
        <div class="autocomplete {{ attrs.class }}" id="{{ attrs.id }}">\
          <input\
            type="text"\
            ng-model="searchParam"\
            placeholder="{{ attrs.placeholder }}"\
            class="{{ attrs.inputclass }}"\
            id="{{ attrs.inputid }}"\
            ng-required="{{ autocompleteRequired }}" />\
            <input\
            type="hidden"\
             name="{{name}}" ng-value="{{ val }}"\
            />\
          <ul ng-show="completing && (Items | filter:searchFilter).length > 0">\
            <li\
              \
              ng-repeat="item in Items | filter:searchFilter | orderBy:\'toString()\' track by $index"\
              index="{{ $index }}"\
              id="{{item.value}}"\
              val="{{ item.title }}"\
              ng-class="{ active: ($index === selectedIndex) }"\
              ng-click="select(item.title,item.value)"\
              ng-bind-html="item.title | highlight:searchParam">\
              </li>\
          </ul>\
        </div>'
    };
});

app.filter('highlight', ['$sce', function ($sce) {
    return function (input, searchParam) {
        if (typeof input === 'function') return '';
        if (searchParam) {
            var words = '(' +
                    searchParam.split(/\ /).join(' |') + '|' +
                    searchParam.split(/\ /).join('|') +
                    ')',
                exp = new RegExp(words, 'gi');
            if (words.length) {
                input = input.replace(exp, "<span class=\"highlight\">$1</span>");
            }
        }
        return $sce.trustAsHtml(input);
    };
}]);

app.directive('suggestion', function () {
    return {
        restrict: 'A',
        require: '^autocomplete', // ^look for controller on parents element
        link: function (scope, element, attrs, autoCtrl) {
            element.bind('mouseenter', function () {
                autoCtrl.preSelect(attrs.val);
                autoCtrl.setIndex(attrs.index);
            });

            element.bind('mouseleave', function () {
                autoCtrl.preSelectOff();
            });
        }
    };
});
&#13;
/* AUTOCOMPLETE */

.autocomplete {
  width: 100%;
  position: relative;
}

.autocomplete input {
  font-size: 1.2em;
  width: 100%;
  padding: 0.4em;
}

.autocomplete ul {
  position: absolute;
  left: 0;
  width: 100%;
  border-left: 1px solid #888;
  border-right: 1px solid #888;
  border-bottom: 1px solid #888;
  z-index: 1;
}

.autocomplete li {
  text-align: left;
  list-style: none;
  width: 100%;
  padding: 0.4em;
  background-color: #fff;
}

.autocomplete li.active {
  width: 100%;
  background-color: #4bf;
}

.autocomplete .highlight {
  background-color: #E2E2E2;
}

.autocomplete li.active .highlight {
  background: #666;
  color: #fff;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<autocomplete url="url1"  ng-model="result" attr-
                              click-activation="true"
                              on-type="doSomething" on-select="doSomethingElse"></autocomplete>
  <autocomplete url="url2"  ng-model="result" attr-
                              click-activation="true"
                              on-type="doSomething" on-select="doSomethingElse"></autocomplete>
  </div>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:2)

你可以尝试使用数组变量作为ng-model,

$scope.result = [];

然后将其用作

ng-model="result[$index]" //if you are using ng-repeat

ng-model="result[0]"
ng-model="result[1]" //.. like this 

答案 1 :(得分:0)

我认为你完全不理解这个指令。你不应该在指令中写下你的数据。它是为了重用。因此,您应该创建一个控制器,它可以获取您的数据并通过data属性将其提供给指令。

app.controller('MyCtrl', function($scope){
  var $scope.array1 =[ {title:"apple", value:1},{title:"sony", value:2},{title:"LG", value:3}];
  var $scope.array2 = [{title:"java", value:1},{title:"c++", value:2},{title:"c#", value:3}];
});

HTML

<div ng-controller="MyCtrl">
  <autocomplete ng-model="result1" data="array1"></autocomplete>
  <autocomplete ng-model="result2" data="array2"></autocomplete>
</div>