2015-07-09 3 views
1

Вот соответствующий JSFiddleAngularJS Директива переменных Область применения неопределенными

https://jsfiddle.net/9Ltyru6a/3/

В скрипку, я создал контроллер и директиву, которую я хочу использовать для вызова обратного вызова всякий раз, когда значение изменения. Я знаю, что у Angular есть директива ng-change, но я хочу нечто более похожее на стандартное событие onchange (которое запускается один раз, когда поле размыто).

Контроллер:

var Controllers; 
    (function (Controllers) { 
    var MyCtrl = (function() { 
     function MyCtrl($scope) { 
      $scope.vm = this; 
     } 

     MyCtrl.prototype.callback = function (newValue) { 
      alert(newValue); 
     }; 

     return MyCtrl; 
    })(); 
    Controllers.MyCtrl = MyCtrl; 
})(Controllers || (Controllers = {})); 

Директива:

var Directives; 
(function (Directives) { 
    function OnChange() { 
     var directive = {}; 
     directive.restrict = "A"; 
     directive.scope = { 
      onchange: '&' 
     }; 
     directive.link = function (scope, elm) { 
      scope.$watch('onChange', function (nVal) { 
       elm.val(nVal); 
      }); 
      elm.bind('blur', function() { 
       var currentValue = elm.val(); 
       scope.$apply(function() { 
        scope.onchange({ newValue: currentValue }); 
       }); 
      }); 
     }; 
     return directive; 
    } 
    Directives.OnChange = OnChange; 
})(Directives || (Directives = {})); 

HTML:

<body ng-app="app" style="overflow: hidden;"> 
    <div ng-controller="MyCtrl"> 
     <button ng-click="vm.callback('Works')">Test</button> 
     <input onchange="vm.callback(newValue)"></input> 
    </div> 
</body> 

Кнопка работает, так что я могу с уверенностью сказать (я думаю), что контроллер прекрасно. Однако, когда я изменяю значение поля ввода и не фокусируется, я получаю сообщение об ошибке «vm is undefined».

Спасибо за помощь!

+2

Почему вы просто не используете 'ng-blur'? https://docs.angularjs.org/api/ng/directive/ngBlur#!/ – Claies

+0

Это определенно вариант, но в конечном итоге я хочу инкапсулировать логику проверки того, действительно ли значение изменилось в этой директиве. –

+0

Я не уверен, что вы имеете в виду? Угловой может справиться с грязной проверкой и для вас ... – Claies

ответ

2

Прежде всего, использовать надлежащие controllerAs обозначения, а не $scope.vm = this;:

ng-controller="MyCtrl as vm" 

Тогда не смешивать пользовательские директивы с нативной обработчика событий onchange - это причина, почему вы получите undefined ошибку. Назовите свою директиву примерно как onChange и используйте вместо этого атрибут on-change.

Правильный код будет выглядеть следующим образом:

var app = angular.module("app", []); 

var Directives; 
(function (Directives) { 
    function OnChange() { 
     var directive = {}; 
     directive.restrict = "A"; 
     directive.scope = { 
      onChange: '&' 
     }; 
     directive.link = function (scope, elm) { 
      elm.bind('blur', function() { 
       var currentValue = elm.val(); 
       scope.$apply(function() { 
        scope.onChange({ 
         newValue: currentValue 
        }); 
       }); 
      }); 
     }; 
     return directive; 
    } 
    Directives.onChange = OnChange; 
})(Directives || (Directives = {})); 

app.directive("onChange", Directives.onChange); 


var Controllers; 
(function (Controllers) { 
    var MyCtrl = (function() { 
     function MyCtrl($scope) { 

     } 

     MyCtrl.prototype.callback = function (newValue) { 
      alert(newValue); 
     }; 

     return MyCtrl; 
    })(); 
    Controllers.MyCtrl = MyCtrl; 
})(Controllers || (Controllers = {})); 

app.controller("MyCtrl", ["$scope", function ($scope) { 
    return new Controllers.MyCtrl($scope); 
}]); 

Демо:https://jsfiddle.net/9Ltyru6a/5/

+0

Ах, конечно. Спасибо! –

1

Если цель вашего кода только обновить ваше значение контроллера на размазывание, а не обновлять его на каждом нажатии клавиши, угловое имеет ngModelOptions для этого использования. Например:

<input type="text" ng-model="user.name" ng-model-options="{ updateOn: 'blur' }" /> 

вы могли бы даже обеспечить дребезг, или кнопку, чтобы очистить значение ....

<form name="userForm"> 
    <input type="text" name="userName" 
     ng-model="user.name" ng-model-options="{ debounce: 1000 }" /> 

    <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button> 
</form> 

В этих случаях, если вы должны были поставлять ng-change, это было бы только триггер на событии размытия или после дебюта.

Вы также можете написать директивы, которые непосредственно позволяют эффективно использовать $validators или $asyncValidators из ngModelController

вот пример из углового Developer Guide:

app.directive('username', function($q, $timeout) { 
    return { 
    require: 'ngModel', 
    link: function(scope, elm, attrs, ctrl) { 
    var usernames = ['Jim', 'John', 'Jill', 'Jackie']; 

     ctrl.$asyncValidators.username = function(modelValue, viewValue) { 

     if (ctrl.$isEmpty(modelValue)) { 
      // consider empty model valid 
      return $q.when(); 
     } 

     var def = $q.defer(); 

     $timeout(function() { 
      // Mock a delayed response 
      if (usernames.indexOf(modelValue) === -1) { 
      // The username is available 
      def.resolve(); 
      } else { 
      def.reject(); 
      } 

     }, 2000); 

     return def.promise; 
     }; 
    } 
    }; 
}); 

и HTML:

<div> 
    Username: 
    <input type="text" ng-model="name" name="name" username />{{name}}<br /> 
    <span ng-show="form.name.$pending.username">Checking if this name is available...</span> 
    <span ng-show="form.name.$error.username">This username is already taken!</span> 
</div> 

Вы может, конечно, добавить ng-model-options, чтобы гарантировать, что этот триггер gers только один раз.

+0

Это замечательно! Я понятия не имел, что это вообще возможно. Технически, другой ответ на самом деле ответил на вопрос, но я на самом деле собираюсь в конечном итоге использовать это. Большое спасибо, и извините, если я не был очень ясен в комментариях. –

+1

@ Не нужно извиняться; Угловая - это массивная структура со многими скрытыми функциями, не всегда легко выразить то, что вам нужно. Я мог бы сказать достаточно хорошо, хотя то, что вы считали единственным способом, было не совсем идеальным, и захотелось потратить время, чтобы помочь вам добраться до другой стороны. – Claies

+0

Это было намного легче. Еще раз спасибо. –

Смежные вопросы