Как обновить $modelValue ngModel на основе обновления $viewValue с помощью пользовательского ввода

Скажем, у меня есть следующая директива:

myApp.directive('myDirective', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        scope: {
            ngModel: '='
        },
        link: function(scope, elem, attrs, ngModelCtrl) {
            scope.$watch('ngModel', function() {
                ngModelCtrl.$modelValue = 'foo';
            });
        }
    }
}); 

И следующий html:

<input ng-model="name" my-directive></input>

По сути, всякий раз, когда пользователь изменяет ввод, my-directive в идеале меняет значение внутренней модели на «foo», оставляя значение представления нетронутым.

Но когда я распечатываю $scope.name в соответствующем контроллере, он не регистрирует «foo», он регистрирует все, что ввел пользователь.

Казалось бы, ngModelCtrl.$modelValue - это не то, к чему обращается контроллер - я неправильно подхожу к этой проблеме?

(Кроме того, наблюдение за ngModel в прицеле кажется действительно неправильным, но я не уверен, что есть другой способ. Любые предложения будут высоко оценены!)


person Cody    schedule 03.10.2014    source источник
comment
Вместо просмотра ngModel вы можете использовать $viewChangeListeners, который специально разработан для этой цели. Но почему вы хотите установить $modelValue иначе, чем viewValue?   -  person PSL    schedule 03.10.2014
comment
Я хотел бы, чтобы пользователи могли вводить данные с разделителями-запятыми, но базовая модель хранила информацию в виде массива.   -  person Cody    schedule 03.10.2014
comment
Так? plnkr.co/edit/pWpnup?p=preview   -  person PSL    schedule 03.10.2014
comment
Вау ты классный, спасибо большое!   -  person Cody    schedule 03.10.2014
comment
То же, что Коди (выше) — я должен разобрать type="tel" и предоставить маску $viewValue, сохраняя при этом $modelValue как целое число.   -  person Cody    schedule 23.03.2016


Ответы (1)


Если вы ищете изменение представления, вам никогда не следует регистрировать часы. $viewChangeListeners в ngModelController специально разработаны для этой цели и во избежание создания любые дополнительные часы на ngModel. Вы также можете удалить двухстороннюю привязку, настроенную в ngModel.

Я могу думать об этом.

.directive('myDirective', function($parse) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, elem, attrs, ngModelCtrl) {
          /*Register a viewchange listener*/
          ngModelCtrl.$viewChangeListeners.push(function(){ 
              /*Set model value differently based on the viewvalue entered*/
              $parse(attrs.ngModel).assign(scope, ngModelCtrl.$viewValue.split(',')); 
          });
        }
    }
});

Демо

Думая об этом с другой стороны (Кредиты @Cody), это становится более кратким и уместным при использовании $parser.

 ngModelCtrl.$parsers.push(function(val) { return val.split(',') });
person PSL    schedule 03.10.2014
comment
Для справки в будущем я проверил $parsers и, кажется, нашел немного более краткое решение: ngModelCtrl.$parsers.push(function(val) { return val.split(',') }). - person Cody; 03.10.2014
comment
Нет, вы правы.. Я не знаю, почему я не подумал об этом наоборот, наверное, действительно поздно спать, я думаю. :) здесь на самом деле каждый раз, когда значение изменяется, мы также назначаем массив для значения представления ngModel, но оно становится строковым... - person PSL; 03.10.2014