angular无法在自定义指令中查看ng-model

时间:2015-07-30 13:25:15

标签: javascript angularjs

我有自定义指令tagPickerTagvalidationMessageTagcheck-valid-article-meta-tags。用法:

  <div class="my-form-group">
    <lable for="create_tags">Tags</lable>
    <tag-picker-tag ng-model="entityInfo.meta.tags" editable="true" name="tags" check-valid-article-meta-tags></tag-picker-tag>
    <validation-message-tag ctrl="form.tags"></validation-message-tag>
  </div>

这就是我定义这3条指令的方法

tagPickerTag:

<div class="tag-picker-tag">
  tags
  <ui-select ng-model="$parent.ngModel" ng-disabled="! editable" multiple tagging tagging-tokens="SPACE|," tagging-label="(custom 'new' label)" title="Select tags" sortable="true" theme="bootstrap" >
    <ui-select-match placeholder="Enter Tags...">{{$item}}</ui-select-match>
    <ui-select-choices repeat="tag in suggestedTags | filter:$select.search">
      {{tag}}
    </ui-select-choices>
  </ui-select>
  <p>Selected: {{ngModel}}</p>
</div>



'use strict'
var helper = require('../../helper.js')
var app = angular.module('custom_directive')

app.directive('tagPickerTag', [function() {
    return {
        restrict: 'E',
        scope: {
            editable: '='
        },
        templateUrl: '/public/common/directive/tag_picker_tag.html',
        require: 'ngModel',
        link:
function(scope, element, attrs, ngModelCtrl) {
},
        controller:
['$scope',
function($scope) {
    //todo: get popular tags from server
    $scope.suggestedTags = ['superbowl', '2016election']

}]}}])

checkValidArticleMetaTags:

app.directive('checkValidArticleMetaTags', helper.simpleValidationDirective('article', 'meta', 'tags'))


exports.simpleValidationDirective = function(module, nestedInParent, field) {
    return function() {
        return {
            restrict: 'A',
            require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
    ctrl.$validators.checkValid = function(modelValue, viewValue) {
        var validationFunction = exports.validation[module]
        if (nestedInParent)
            validationFunction = validationFunction[nestedInParent]
        validationFunction = validationFunction[field]

        var message = validationFunction(modelValue)
        ctrl.data = exports.dataAppendedWithMessage({}, 'error', message)
        return ! message
    }
}}}}

如果您对上面代码中的validationFunction感到好奇(它应该是无关紧要的,因为validation指令正确地获取了验证错误消息):

....
,meta: {
    tags: passIfListFulfill('tags', 10, 5, 10, false)
}

var passIfListFulfill = function(fieldName, amount, min, max, required) {
    return function(input) {
        if (!input || input === [])
            return messageForNoInput(fieldName, required)

        for (var i = 0; i < input.length; i++) {
            var token = input[i]
            if (token.length < min)
                return token + ' is shorter than min: ' + min
            else if (token.length > max)
                return token + ' is longer than max ' + max
        }

        return messageForNoMoreThan(fieldName, input, amount)
    }
}

ValidationMessageTag:

app.directive('validationMessageTag', [function() {
    return {
        restrict: 'E',
        scope: {
            ctrl: '=ngModel'
        },
        templateUrl: '/public/common/directive/validation_message_tag.html',
        controller:
['$scope',
function($scope) {

    $scope.$watch('ctrl.data', function(newValue, oldValue) {
        $scope.success = newValue ? newValue.success : []
        $scope.info = newValue ? newValue.info : []
        $scope.warning = newValue ? newValue.warning : []
        $scope.error = newValue ? newValue.error : []
    }, true)

}]}}])



<div class="validation-message-tag" ng-show="ctrl.$touched && ctrl.data">
  <p ng-repeat="message in success track by $index" class="validation-success">{{message}}</p>
  <p ng-repeat="message in info track by $index" class="validation-info">{{message}}</p>
  <p ng-repeat="message in warning track by $index" class="validation-warning">{{message}}</p>
  <p ng-repeat="message in error track by $index" class="validation-error">{{message}}</p>
</div>

当我输入标签['a']时,在我的验证指令中,我能够返回false并将字符串"a" is too short分配给ctrl(这意味着我的验证指令是正确的)。

但是此消息未传递到我的validation_message_tag以显示。即,不调用$watch回调。

validtion_message_tag适用于和标记,所以我认为问题可能是我的tagPickerTag自定义指令的实现。

2 个答案:

答案 0 :(得分:0)

  

不会调用$ watch回调。

所以我无法得到$watch的简单方案。

我的想法是ng-model=""是双向绑定的,你在指令中将它作为双向绑定在scope: { "ngModel" : "=" }中取出,所以当值改变时你应该看到它反映出来。所以你不需要$watch。但是我尝试了两种方法,但都没有效果。

所以我改为使用了事件。

plnkr

$scope.$broadcast(EventNames.statusChange, vm.success)

scope.$on(EventNames.statusChange, function (e, val) { scope.show = val });

旁注,为了防止'魔术串'我从事件名称中取得了一个常数。这应该有助于消除开发人员的拼写错误

也可以在工厂完成。对于工厂,您不依赖于$scope,因此在控制器依赖性列表中保持controllerAs更简洁。其次,如果它不起作用,你知道它,因为工厂没有被使用,或者没有注册回调。而不是纠缠于角度事件系统的复杂事物。

关于事件聚合器模式(角$broadcast$on)的旁注,在我看来,这会创建过于松散耦合的代码,导致很多speghetti代码。要考虑的另一个坏点是事件强制执行这些规则:

  1. 每个人都可以听取此事件
  2. 没有人也听过这个事件
  3. 通过创建服务,您可以强制开发人员收听他们正在播放的内容。在registercallbacks函数中,如果没有人注册了监听器,则可以抛出错误。此外,现在依赖于StatusService意味着我们对组件的耦合更紧密。恕我直言,代码耦合的最佳点。

    设置和收听:

    StatusService.setState(vm.success);
    
    StatusService.registerCallbacks(function (val) {  scope.show2 = val });
    

    工厂功能的实现:

    function setState(value) {
      for (var i = 0; i < cbs.length; i++) {
        cbs[i](value);
      }
    }
    
    function registerCallbacks(cb) {
      cbs.push(cb);
    }
    

    基本上,它们是相同的,但在我看来,使用工厂更安全,你可以将一些逻辑抽象出工厂。而不是在回调函数中执行它。

答案 1 :(得分:0)

事实证明我设置了Cookie标记public MyFrame () { initUI(); setVisible(true); } 并忘记将其关闭。在进行测试时,我只是对所有验证器都返回true。