AngularJS directive with two-way binding and ng-change

匆匆过客 提交于 2019-12-25 16:00:29

问题


I have come across a situation where I need to change the input type of an input box based on the selected value of a dropdown. In other words, if the user selects 'String' from the dropdown then the type of the input should be 'text', etc. I decided to create a directive cuz I'm still learning Angular but also so I don't copy blocks of code all over the place (I need this more than once).

This it the contents of my attempt:

(function () {
    "use strict";

    angular
        .module('app')
        .directive('dynamicTypeInput', dynamicTypeInput);

    function dynamicTypeInput() {
        return {
            replace: true,
            restrict: 'AE',
            require: ['ngModel', '^form'],
            scope: {type: '=', placeholder: '@'},
            templateUrl: 'app/common/dynamic-type-input/dynamic-type-input.tpl.html',
            link : function(scope, element, attrs, ngModel){

                //Watch for changes to ngModel, update scope.inputValue
                scope.$watch(function(){
                    return ngModel[0].$modelValue;
                }, function (value){
                    scope.inputValue = value;
                });

                //Watch inputValue, update the model
                scope.$watch('inputValue', function(value){
                    ngModel[0].$setViewValue(value);
                });

                //Setup ng-change
                if (attrs.ngChange) {
                    ngModel[0].$viewChangeListeners.push(function () {
                        scope.$eval(attrs.ngChange);
                    });
                }
            }
        };
    }
})();

Note: The template is simply an ng-switch that selects the appropriate input box based on the value of scope.type and the inputs all bind to scope.inputValue.

I used the answer from this SO question to help me add the ability to add an ng-change attribute and fire correctly. According to that answer I needed to remove the ngModel from the isolated scope, I'm not sure why this is required but, if someone could explain it I'd be grateful.

Removing ngModel from the isolated scope made it more difficult to instantiate directive with an initial value or have the directive update when the model is changed in the main controller so now I watch ngModel[0].$modelValue and update the local value if it changes.

While the directive works and does what I expect it do but it all seems a bit convoluted and inefficient, is there no way I can achieve what I want in a more simple manner?


回答1:


Using the second answer to the SO question referenced I fixed the problem of needing to remove ngModel from the isolated scope in order to get ngChange to work. This simplified the directive and I can use two-way binding as is.

Final directive:

(function () {
    "use strict";

    angular
        .module('app')
        .directive('dynamicTypeInput', dynamicTypeInput);

    dynamicTypeInput.$inject = ['$timeout'];

    function dynamicTypeInput($timeout) {
        return {
            replace: true,
            restrict: 'AE',
            require: ['ngModel', '^form'],
            scope: {ngModel: '=', type: '=', placeholder: '@', ngChange: "&"},
            templateUrl: 'app/common/dynamic-type-input/dynamic-type-input.tpl.html',
            link: function (scope, element, attrs, ngModel) {

                scope.$watch('ngModel', function () {
                    $timeout(scope.ngChange);
                });

            }
        };
    }
})();


来源:https://stackoverflow.com/questions/30575973/angularjs-directive-with-two-way-binding-and-ng-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!