ng-change and ng-focus not working in custom input

2019-08-11 15:51发布

I'm working on customize a input directive which including a label. I tried several days and refer to some articles.
The only problem is that except ng-change, ng-blur and ng-focus, all the other event work. https://jsfiddle.net/luneyq/mw3oz2pr/
Of course I can bind these three event manually myself and they can work as https://jsfiddle.net/luneyq/bp7f3z1o/

But I really don't know why ng-change, ng-blur and ng-focus don't work. Is there any special on these three event? Anyone can help on this?

My codes are as below:

<div ng-app="myApp">
<div ng-controller="MainController">
    <my-input type="number" name="valueNumber1" ng-model="obj.valueNumber1" label="Age" ng-click="log('click')" ng-change="log('change')" ng-blur="log('blur')" ng-focus="log('focus')" ng-mouseleave="log('mouseleave')"></my-input>
    <div id="result"></div>
</div>

The JS:

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

app.controller('MainController', function($scope, $window){
    $scope.obj = {valueNumber1: 10};
    $scope.log = function(text) {
        document.getElementById("result").innerHTML = text + ':' + $scope.obj.valueNumber1 + "<br>" + document.getElementById("result").innerHTML;
    };
});

app.directive('myInput', function() {
    return {
        require:  '^ngModel',
        restrict: 'EA',
        scope: {
            ngModel: '=',
            name: '@name',
            label: '@label'
        },
        replace: true,
        transclude: true,
        priority: 10,
        template: '<div>' +
        '<label for="{{ name }}">{{label}}</label>' +
        '<input id="{{ name }}" ng-model="ngModel" />' +
        '</div>',
        compile: function(tElement, tAttrs, transclude) {
            var tInput = tElement.find('input');
            // Move the attributed given to 'custom-input' to the real input field
            angular.forEach(tAttrs, function(value, key) {
                if (key.charAt(0) == '$')
                    return;
                tInput.attr(key, value);
            });
            tElement.replaceWith('<div class="cbay-input-div">' + tElement.html() + '</div>');
            return;
        }
    };
});


Thanks in advance.

1条回答
对你真心纯属浪费
2楼-- · 2019-08-11 16:39

The issue is that compilation/transclusion/replace don't work the way you think they work (not sure where you made an incorrect assumption).

What is wrong with your code:

1). You are using incorrect attribute name: you should use tInput.attr(tAttrs.$attr[key], value); instead of tInput.attr(key, value);.

2). All the directives specified at my-input are compiled and linked despite your changes to the tElement in compile function. Proof is here - https://jsfiddle.net/fyuz3auc/3/, take a look at the myTest directive and its output in console: it is still applied to the myInput despite any of your effort.

3). You specified scope for your directive. Thus it has an isolated scope, thus anything you've compiled inside it has no access to log function of MainController, that's why your logs aren't working. Here is the fiddle proving that: https://jsfiddle.net/m5tba2mf/1/ (take a look at $scope.log = $scope.$parent.log in link function returned from compile).

In order to solve the second issue I suggest you to try alternative approach - I am using this at my project, and like it very much. The idea is to use terminal in conjunction with extremely high priority and $compile. Here is the updated fiddle, I think it is pretty straightforward what I do there: https://jsfiddle.net/uoat55sj/1/.

查看更多
登录 后发表回答