【问题标题】:AngularJS Multiple directives asking for ngModelAngularJS 多个指令要求 ngModel
【发布时间】:2015-02-15 03:23:29
【问题描述】:

这是我正在努力完成的jsfiddle example

我正在尝试构建一个美国电话号码输入,其中视图显示为 (333) 555-1212,但模型绑定到数字整数 3335551212。​​

我的意图是向NgModelController 添加自定义验证器,这就是我有require: ng-model 的原因;有没有隔离范围和NgModelController 的更简单的解决方案,但我需要两者。

您会在控制台中立即看到一个错误:Error: Multiple directives [ngModel, ngModel] asking for 'ngModel' controller on: <input ng-model="user.mobile numeric" name="telephone" type="tel">——我以为我在这里使用了隔离作用域...

【问题讨论】:

    标签: javascript angularjs angularjs-directive angularjs-ng-model


    【解决方案1】:

    感谢您查看@mimir137,但我似乎已经解决了它:

    http://jsfiddle.net/hr121r18/8/

    该指令使用replace: true,最终得到以下结构:

    <form ng-controller="FooCtrl" class="ng-scope">
        <p>Enter US phone number</p>
        <input ng-model="user.mobile numeric" name="telephone" type="tel">
    </form>
    

    模板和标记都调用了ng-model,这导致了问题描述中的症状错误。一旦我删除它,它就会导致这个标记(注意包装元素phone-number):

    <form ng-controller="FooCtrl" class="ng-valid ng-scope ng-dirty ng-valid-parse" abineguid="BC0D9644F7434BBF80094FF6ABDF4418">
        <p>Enter US phone number</p>
        <phone-number ng-model="user.mobile" class="ng-untouched ng-valid ng-isolate-scope ng-dirty ng-valid-parse">
           <input ng-model="numeric" name="telephone" type="tel" class="ng-valid ng-dirty ng-touched">
        </phone-number>
    </form>
    

    但是删除这个需要对$render 进行更改;传递给链接函数的elem 现在是phone-number,因此您需要挖掘其中的input 并为其设置值:

    ngModel.$render = function () {
      elem.find('input').val($filter('phonenumber')(ngModel.$viewValue));
    }; 
    

    还有其他一些问题。 $render() 也需要被观察者调用。

    决赛:

    var app = angular.module('myApp', []);
    
    // i want to bind user.mobile to the numeric version of the number, e.g. 3335551212, but 
    // display it in a formatted version of a us phone number (333) 555-1212
    // i am trying to make the directive's scope.numeric to have two-way binding with the controller's
    // $scope.user.mobile (using isolate scope, etc.).
    app.controller('FooCtrl', function ($scope) {
        $scope.user = {
            mobile: 3335551212
        };
    });
    
    app.directive('phoneNumber', ['$filter', function ($filter) {
        return {
            restrict: 'E',
            template: '<input ng-model="numeric" name="telephone" type="tel">',
            require: 'ngModel',
            scope: {
                numeric: '=ngModel'
            },
            link: function (scope, elem, attrs, ngModel) {
    
                // update $viewValue on model change
                scope.$watch('numeric', function () {
                    ngModel.$setViewValue(scope.numeric);
                    ngModel.$render();
                });
    
                // $modelValue convert to $viewValue as (999) 999-9999
                ngModel.$formatters.push(function (modelValue) {
                    return $filter('phonenumber')(String(modelValue).replace(/[^0-9]+/, ''));
                });
    
                // $viewValue back to model
                ngModel.$parsers.push(function (viewValue) {
                    var n = viewValue;
                    if (angular.isString(n)) {
                        n = parseInt(n.replace(/[^0-9]+/g, ''));
                    }
                    return n;
                });
    
                // render $viewValue through filter
                ngModel.$render = function () {
                    elem.find('input').val($filter('phonenumber')(ngModel.$viewValue));
                };
    
            }
        };
    }]);
    
    app.filter('phonenumber', function () {
        return function (number) {
            if (!number) {
                return '';
            }
            number = String(number);
            var formattedNumber = number;
            var c = (number[0] === '1') ? '1 ' : '';
            number = number[0] === '1' ? number.slice(1) : number;
    
            var area = number.substring(0, 3),
                exchange = number.substring(3, 6),
                subscriber = number.substring(6, 10);
    
            if (exchange) {
                formattedNumber = (c + '(' + area + ') ' + exchange);
            }
            if (subscriber) {
                formattedNumber += ('-' + subscriber);
            }
            return formattedNumber;
        }
    });
    

    HTML

    <form ng-controller="FooCtrl">
        <p>Enter US phone number</p>
        <phone-number ng-model='user.mobile'></phone-number>
    </form>
    

    【讨论】:

    • 您在代码中所做的更改并不明显,但很高兴您找到了解决方案。
    • @Claies 比较开始小提琴:jsfiddle.net/hr121r18/3(这是一个完整的黑客马拉松)和结束小提琴:jsfiddle.net/hr121r18/8
    • 如果我真的对差异感兴趣,我可以比较它们,但一个好的答案不依赖于指向小提琴的链接或未来可能不存在的东西。任何有类似问题并发现您的问题的人都在寻找一些东西来解释问题所在,而不是他们必须比较和对比的代码。
    【解决方案2】:

    我创建了this fiddle,它消除了控制台中出现的大部分错误。希望这至少能让你走上正轨。

    我更改了模板,以便您可以看到过滤器确实在工作。 它现在在文本框下方以纯文本形式显示典型的{{ngModel | FilterName}}。 唯一真正的问题是在文本框中显示它。我相信你不会有任何问题。我会在早上检查以防您对此仍有疑问。

    编辑:好吧,看来你已经解决了。干得好!

    【讨论】:

    • 我有一个自定义过滤器 - 不确定你是否看过小提琴。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    相关资源
    最近更新 更多