ng-repeat on object properties but defocuses input

2020-08-12 05:37发布

问题:

I am using ng-repeat to bind form elements to the properties of a custom object I have, example:

 $scope.myObject = {
            'font-size': 10,
            'text-outline-width': 2,
            'border-color': 'black',
            'border-width': 3,
            'background-color': 'white',
            'color': '#fff'
    }

HTML:

<div ng-repeat='(key, prop) in myObject'>
    <p>{{key}} : {{prop}}</p>
    <input type='text' ng-model='myObject[key]'>
</div>

However, every time I try to type in a value into the input box, the text box gets deselected and I have to reselect it to keep typing.

Is there another way to do this two-way binding to an object so that I can type freely?

Here is the JSFiddle: http://jsfiddle.net/AQCdv/1/

回答1:

The reason inputs were unfocused is that Angular rebuilt the DOM on every myObject change. You can specifically instruct ng-repeat to track by key, so undesired behavior won't happen. Also, this will require 1.1.5 on newer version of library:

function MyCtrl($scope) {
  $scope.myObject = {
    'font-size': 10,
    'text-outline-width': 2,
    'border-color': 'black',
    'border-width': 3,
    'background-color': 'white',
    'color': '#fff'
  }
}
<script src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
<div ng-app ng-controller="MyCtrl">
  <div ng-repeat='(key, prop) in myObject track by key'>
    <p>{{key}} : {{prop}}</p>
    <input type='text' ng-model='myObject[key]'>
  </div>
</div>

Updated fiddle.



回答2:

this can be solved with a directive. I created a directive called customBlur but it can be called whatever you want, granted it matches in your HTML. View the fiddle here: http://jsfiddle.net/AQCdv/3/

angular.module('app', []).directive('customBlur', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, elm, attr, ngModelCtrl) {
            if (attr.type === 'radio' || attr.type === 'checkbox') return; //ignore check boxes and radio buttons

            elm.unbind('input').unbind('keydown').unbind('change');
            elm.bind('blur', function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(elm.val());
                });
            });
        }
    };
});

and the HTML directive to be used like

<input type='text' ng-model='myObject[key] ' custom-blur>

What this directive does is unbind the events that produce the model updates which is causing your text field to lose focus. Now when the text field loses focus (blur event) the models are updated.