最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angularjs - ngModel.$setViewValue is not a function - Stack Overflow

programmeradmin0浏览0评论

Here is my plunker and the code I can't get to work starts on line 32

I am trying to apply an equivalent to markdown filter onto a directive... I created the filter and tested with manually applying the filter and it works that way,, but I should only use the filter conditionally when the type of content on directive is set to markdown.

I am trying to acplish this by updating ng-model >>> ngModel.$setViewValue(html) but I am getting an error ngModel.$setViewValue is not a function.. which makes me thing that the controller is not recognized although it is required by the directive.

Here is a working controller:

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",
    pile: 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)
                })
            }
    }
}
})

This is a filter for markdown which works when applied.. (I would consider using the filter if I could figure out the way to conditionally apply it to existing directive but I'd rather do it with ng-model)

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

Here is the directive template

<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>

This is the directive in use:

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

Here is my plunker and the code I can't get to work starts on line 32 http://plnkr.co/edit/pmCjQL39BWWowIAgj9hP?p=preview

I am trying to apply an equivalent to markdown filter onto a directive... I created the filter and tested with manually applying the filter and it works that way,, but I should only use the filter conditionally when the type of content on directive is set to markdown.

I am trying to acplish this by updating ng-model >>> ngModel.$setViewValue(html) but I am getting an error ngModel.$setViewValue is not a function.. which makes me thing that the controller is not recognized although it is required by the directive.

Here is a working controller:

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",
    pile: 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)
                })
            }
    }
}
})

This is a filter for markdown which works when applied.. (I would consider using the filter if I could figure out the way to conditionally apply it to existing directive but I'd rather do it with ng-model)

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

Here is the directive template

<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>

This is the directive in use:

    <mb-text ng-cloak 
        type="markdown"
        content-type="product"
        value="description"
        class="test-one-text-2">
    </mb-text>
Share Improve this question asked Feb 4, 2014 at 23:10 GRowingGRowing 4,72713 gold badges55 silver badges75 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 4

Why ngModel is empty?

  • When using require on a directive the controller is passed as the 4th argument to the linking function. In you code you try to reference it as an argument of the pile function. The controller is only instantiated before the linking phase so it could never be passed into the pile function anyway.

  • The bigger issue is that require can only get a controller of the same element ({ require: 'ngModel' }), or parent elements ({ require: '^ngmodel' } ). But you need to reference a controller from a child element (within the template).

How to get ngModel?

Do not use require at all as you cannot get child element's controller with it.

From angular.element docs:

jQuery/jqLite Extras

controller(name) - retrieves the controller of the current element or its parent. By default retrieves controller associated with the ngController directive. If name is provided as camelCase directive name, then the controller for this directive will be retrieved (e.g. 'ngModel').

Inside the linking function you can get the hold of the controller like so:

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

I fixed your directive:

here is a plunker: http://plnkr.co/edit/xFpK7yIYZtdgGNU5K2UR?p=preview

template:

<div ng-class="{{css}}" ng-bind-html="exp.preview"> </div>
    
<div>
    <textarea rows="4" cols="30" ng-model="exp.val"></textarea>
</div>

Directive:

app.directive("myText", function($parse) {
  return {
    restrict: "E",
    templateUrl: "template.html",
    scope: {
      css: "@class",
      type: "@type"
    },
    pile: 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);
        });
      };
    }
  };
});
发布评论

评论列表(0)

  1. 暂无评论