Модель. $modelValue - NaN в директиве

См. этот jsfiddle: http://jsfiddle.net/8bENp/66/

Если вы посмотрите на консоль JavaScript, вы увидите что-то вроде этого:

TypeError: Object NaN has no method 'replace'
    at makeHtml (https://raw.github.com/coreyti/showdown/master/compressed/showdown.js:62:705)
    at render (http://fiddle.jshell.net/_display/:50:42)
    at link (http://fiddle.jshell.net/_display/:54:13)
    at k (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js:42:321)
    at e (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js:38:198)
    at k (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js:42:261)
    at e (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js:38:198)
    at https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js:37:332
    at https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js:15:440
    at Object.e.$eval (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js:85:416) <markdown ng-model="someCode" class="ng-pristine ng-valid"> angular.min.js:60

Проблема заключается в том, что model.$modelValue есть NaN, когда его тип не должен быть даже числом. Тем не менее, уценка делает. Я мог бы добавить проверку typeof model.$modelValue == 'string', но я бы скорее рассмотрел основную причину. Любая идея?

Ответ 1

Проблема в вашей директиве заключается в том, что angular запускает часы один раз до того, как выражение будет оценено. Поэтому в первый раз значение undefined. Я не верю, что это можно предотвратить, но как работает AngularJS.

Я добавил параметр val к вашей функции рендеринга, чтобы показать фактическое наблюдаемое значение (зарегистрировалось на консоли - см. скрипку внизу). ngModelController инициализирует $modelValue для NaN, поэтому NaN передается функции вместо undefined.

Но так как кажется, что функция makeHtml ожидает строку, простое исправление должно передать ей пустую строку, если значение ложно (может быть даже лучше преобразовать его в строку).

var htmlText = converter.makeHtml(model.$modelValue || '');

Обновлена ​​скрипка.

Ответ 2

Я не знал, что $modelValue был инициализирован NaN и столкнулся с аналогичной проблемой. Если для инициализации действительно требуется $modelValue, решение может быть просмотрено до тех пор, пока ему не будет присвоено новое значение:

.directive('contentEditor', function(){
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function($scope, $element, $attrs, ngModel){

            var unregister = $scope.$watch(function(){
                return ngModel.$modelValue;
            }, initialize);

            function initialize(value){
                ngModel.$setViewValue(value);
                unregister();
            }

            //...
        }
    };
});

$watch возвращает функцию дерегистрации, поэтому ее можно незарегистрировать, как только новое значение присвоено $modelValue.

Ответ 3

Я думаю, вы можете также обернуть его в функцию ngModel.$render.

Так же:

.directive('classOnValue', function($timeout) {
           return {
               restrict: 'A',
               require: 'ngModel',
               link: function(scope, element, attrs, ngModel) {

                   ngModel.$render = function(){
                       //Do something with your model
                       var actualValue = ngModel.$modelValue;
                   }

               }}
       })

Ответ 4

Другой вариант (только если кто-то найдет этот вопрос здесь): просто завершите выполнение директивы в $timeout. Например, моя директива, которая его использует:

.directive('classOnValue', function($timeout) {
               return {
                   restrict: 'A',
                   require: 'ngModel',
                   link: function(scope, element, attrs, ngModel) {
                       $timeout(function() {
                           var value = (attrs.value || ngModel.$modelValue || ngModel.$viewValue );
                           if (value) {
                               element.addClass(attrs.classOnValue);
                           }
                       });
                   }}
           })