Angularjs - ngModel。$ setViewValue不是一个函数

时间:2014-02-04 23:10:38

标签: javascript jquery angularjs

这是我的plunker和我无法开始工作的代码从第32行开始 http://plnkr.co/edit/pmCjQL39BWWowIAgj9hP?p=preview

我正在尝试将一个等效的markdown过滤器应用到一个指令上...我创建了过滤器并通过手动应用过滤器进行测试,并且它以这种方式工作,但我应该只在内容类型时有条件地使用过滤器on指令设置为markdown。

我试图通过更新ng-model>>>来实现这一目标。 ngModel.$setViewValue(html)但我收到了错误 ngModel。$ setViewValue不是一个函数..这使得控制器无法被识别,尽管指令需要它。

这是一个有效的控制器:

var app = angular.module('testOne', ["ngResource", "ngSanitize"]);

app.controller('testOneCtrl', function ($scope) {

$scope.product = {
    id:12,
    name:'Cotton T-Shirt, 2000',
    description:'### markdown\n - list item 1\n - list item 2',
    price:29.99
};

}); 

app.directive("myText", function ($parse) {
return {
    restrict: "E",
    require: "?ngModel",
    scope:{
        css: "@class", type: "@type"
    },
    controller: function ($scope, $element, $attrs) {},
    templateUrl: "template.html",
    compile: function(elm, attrs, ngModel){

            var expFn = $parse(attrs.contentType + '.' + attrs.value);
            return function(scope,elm,attrs){
                scope.$parent.$watch(expFn, function(val){
                    scope.exp = { val: val };

                if ( attrs.type == 'markdown'){
                    var converter = new Showdown.converter();
                        var html = converter.makeHtml(val);
                        //scope.exp.val = html;

                        ngModel.$setViewValue(html);
                        ngModel.$render();
                }

                })

                scope.$watch('exp.val', function(val){
                    expFn.assign(scope.$parent, val)
                })
            }
    }
}
})

这是markdown的过滤器,在应用时有效..(我会考虑使用过滤器,如果我能找到有条件地将它应用于现有指令的方法,但我宁愿用ng-model做)

/*
app.filter('markdown', function ($sce) {
    var converter = new Showdown.converter();
    return function (value) {
        var html = converter.makeHtml(value || '');
        return $sce.trustAsHtml(html);
   };
});
*/

这是指令模板

<div ng-class="{{css}}"
        ng-click="view = !view" 
        ng-bind-html="exp.val">
</div>


<div>
    <textarea rows="4" cols="30" ng-model="exp.val"></textarea>
</div>

这是使用中的指令:

    <mb-text ng-cloak 
        type="markdown"
        content-type="product"
        value="description"
        class="test-one-text-2">
    </mb-text>

1 个答案:

答案 0 :(得分:4)

为什么ngModel为空?

  • 在指令上使用require时,控制器将作为第4个参数传递给链接函数。在您的代码中,您尝试将其作为编译函数的参数引用。控制器仅在链接阶段之前被实例化,因此无论如何它永远不会被传递到编译函数中。

  • 更大的问题是require只能获得相同元素({ require: 'ngModel' })或父元素({ require: '^ngmodel' })的控制器。但是您需要从子元素(模板内)引用控制器。

如何获得ngModel

根本不要使用require,因为你无法使用它来获取子元素的控制器。

来自angular.element docs

  

jQuery / jqLit​​e Extras

     

controller(name) - 检索当前元素或其父元素的控制器。默认情况下,检索与ngController指令关联的控制器。如果name以camelCase指令名提供,则将检索该指令的控制器(例如'ngModel')。

在链接功能中,你可以像这样控制控制器:

 var ngModel = elm.find('textarea').controller('ngModel');

我修正了你的指令:

这是一个吸虫:http://plnkr.co/edit/xFpK7yIYZtdgGNU5K2UR?p=preview

<强>模板:

<div ng-class="{{css}}" ng-bind-html="exp.preview"> </div>

<div>
    <textarea rows="4" cols="30" ng-model="exp.val"></textarea>
</div>

<强>指令:

app.directive("myText", function($parse) {
  return {
    restrict: "E",
    templateUrl: "template.html",
    scope: {
      css: "@class",
      type: "@type"
    },
    compile: function(elm, attrs) {

      var expFn = $parse(attrs.contentType + '.' + attrs.value);

      return function(scope, elm, attrs) {

        scope.exp = {
          val: '',
          preview: null
        };

        if (attrs.type == 'markdown') {
          var converter = new Showdown.converter();

          var updatePreview = function(val) {
            scope.exp.preview = converter.makeHtml(val);
            return val;
          };

          var ngModel = elm.find('textarea').controller('ngModel');
          ngModel.$formatters.push(updatePreview);
          ngModel.$parsers.push(updatePreview);
        }

        scope.$parent.$watch(expFn, function(val) {
          scope.exp.val = val;
        });

        scope.$watch('exp.val', function(val) {
          expFn.assign(scope.$parent, val);
        });
      };
    }
  };
});