персонализираната директива за въвеждане с помощта на ngModel не актуализира стойността на модела

Бих искал да използвам ngPattern в персонализирана директива за въвеждане. За да си поиграя, първо създадох следната директива:

myApp.directive('myInput', [function() {
    return{
        restrict: 'A',
        replace: true,
        require: 'ngModel',
        scope: true,
        template:
            '<div>' +
            '  <input type="text" ng-model="val" ng-change="updateValue()" ng-pattern="/^-?(?:\d+|\d*\.(\d+)?)$/i">' +
            '</div>',
        link: function(scope, element, attrs, ngModelCtrl){     
            scope.updateValue = function(){
                ngModelCtrl.$setViewValue(scope.val);
            }

            ngModelCtrl.$render = function () {
                scope.val = ngModelCtrl.$viewValue;
            };
        }
    };
}]);

Виждам в програмата за отстраняване на грешки стойността на scope.val винаги е недефинирана, така че извикването $setValue няма ефект. Опитах се да премахна атрибута ng-pattern, но и тогава актуализацията не работи.

какво не е наред тук Plunkr може да бъде намерен тук, където се свързвам с модел, а не с примитивен!

Актуализация

Изглежда, че извикването на ngModelCtrl.$setViewValue(scope.val) в scope.updateValue има странен резултат. Ако имате такъв модел:

scope.model = {
    'testValue' : 12
};

И се свързвам с "model.testValue" (както в plunkr), след което моделът става празен обект {} след изпълнението на ngModelCtrl.$setViewValue(scope.val). Повторното задаване на стойността в нормално поле за въвеждане ще нулира променливата scope.model до нормален обект. За мен това няма смисъл. Някаква идея защо се случва това?


person Sjoerd222888    schedule 09.12.2015    source източник


Отговори (2)


Самият аз намерих решение. Не съм сигурен дали това е най-добрият начин за това, но работи. Видях доста подобни директиви като моята оригинална версия (в смисъл как се изпълнява обвързването на данни), например jkuri.touchSpin.

Важното беше да запазите препратка към оригиналната $render функция на ngModelController и да извикате тази функция след използване на $setViewValue.

Но това, което проработи за мен в крайна сметка, беше следното:

myApp.directive('myInput', ['$parse', function($parse) {
    return{
        restrict: 'A',
        replace: true,
        require: 'ngModel',
        scope: true,
        template:
            '<div>' +
            '  <input type="text" ng-model="val" ng-change="updateValue()"  ng-pattern="regex" >' +
            '</div>',
        link: function(scope, element, attrs, ngModelCtrl){
            var orignalRender = ngModelCtrl.$render;
            scope.regex = /^-?(?:\d+|\d*\.(\d+)?)$/i;
            ngModelCtrl.$render = function () {
                scope.val = ngModelCtrl.$viewValue;
            };              
            scope.updateValue = function(){
                ngModelCtrl.$setViewValue(scope.val);
                orignalRender();
            }
        }
    };
}]);
person Sjoerd222888    schedule 11.12.2015

Основно правило:

Каквото и да подадете към ng-model, трябва да има . което означава, че не искате да се свързвате с примитиви.

https://www.youtube.com/watch?v=ZhfUv0spHCY&feature=youtu.be&t=30m

https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance

person Chris Hermut    schedule 09.12.2015
comment
Както можете да видите в plunkr има ., така че обвързвам модел, а не примитивен. - person Sjoerd222888; 09.12.2015
comment
Мисля, че той имаше предвид вашия ng-модел в шаблонния низ, където не използвате . - person Ryan M; 15.06.2017