angularjs指令中的这个错误“[$ compile:nonassign]”是什么?

时间:2015-07-25 08:01:50

标签: javascript angularjs angularjs-directive autocomplete

我正在编写一个指令并在控制台中获取以下内容:

  

错误:[$ compile:nonassign] http://errors.angularjs.org/1.3.14/ $ compile / nonassign?p0 = undefined& p1 = autocomplete

实际上我想在模板中有一个动态模型。模板中的input元素具有动态模型名称。

     <input\
        type="text"
        ng-model="modelName"\ /> 

获取动态模型名称我正在创建标记并将路径作为模型名称传递。

  <s:bind path="${path}">
       <autocomplete url="${url}" name="${path}"  model-name="${path}"
            click-activation="true"
            on-type="doSomething" on-select="doSomethingElse">      </autocomplete>

   </s:bind>

并且在$ scope.watch中我正在观看所有型号名称。

   $scope.$watch($scope.modelName, function (newValue, oldValue) {
    } 

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: '@',
                modelName:'=',
                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($scope.modelName, 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="modelName"\
                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();
                });
            }
        };
    });
.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;
    }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <div ng-app="myApp">
    <autocomplete url="url1"   model-name="result1" attr-
                                  click-activation="true"
                                  on-type="doSomething" on-select="doSomethingElse"></autocomplete>
      <autocomplete url="url2"   model-name="result2" attr-
                                  click-activation="true"
                                  on-type="doSomething" on-select="doSomethingElse"></autocomplete>
      </div>

1 个答案:

答案 0 :(得分:0)

  

[$ compile:nonassign]错误

     

当指令定义隔离范围属性时,会发生此错误   (使用指令定义的scope选项中的= mode)但是   该指令与一个不可赋值的表达式一起使用。

     

为了使双向数据绑定起作用,必须有可能   将新值写回到使用表达式定义的路径中。

您错过了在您的隔离范围内添加属性autocompleteRequired,因为您需要添加autocomplete-required属性,其值为autocomplete-required="true"

<强>标记

<s:bind path="${path}">
   <autocomplete url="${url}" name="${path}"  model-name="${path}"
        click-activation="true"
        autocomplete-required="true"
        on-type="doSomething" on-select="doSomethingElse">
   </autocomplete>
</s:bind>