使用ng-model和ng-value进行input[radio]的对象相等性比较。

15 浏览
0 Comments

使用ng-model和ng-value进行input[radio]的对象相等性比较。

让我先说一下,这个问题很类似于在使用ng-options的使用AngularJS的ng-options选择

为了演示,假设我们有下面的选项数组和模型中的选定选项变量:

$scope.items = [
   {ID: 1, Label: 'Foo', Extra: 17},
   {ID: 2, Label: 'Bar', Extra: 18},
   {ID: 3, Label: 'Baz', Extra: 19}
];
$scope.selectedItem = {ID: 1, Label: 'Foo'};

请注意,上面的对象仅供演示。我故意在selectedItem上留下了“Extra”属性,以表明我的模型对象有时在其特定属性上有所不同。重要的是我想在ID属性上进行比较。我的真实对象中有一个equals()函数,可以比较原型“类”和ID。

然后在视图中:


现在,这里的“Foo”单选按钮不会开始被选中,因为Angular在使用对象的引用相等性。如果我将我的作用域中的最后一行更改为以下内容,则一切都将按预期工作。

$scope.selectedItem = items[0];

但是,我遇到的问题是,在我的应用程序中,我不仅仅是在作用域中声明这两个简单的变量。相反,选项列表和被绑定选定的选项的数据结构都是从服务器使用$http查询的更大的JSON数据集的一部分。通常情况下,很难让我将数据绑定的选定属性更改为数据查询的等效选项。

所以,我的问题是:

在ng-options中,对于,Angular提供了一个track by表达式,使我可以说类似于“object.ID”,并告诉Angular应该通过ID属性将所选模型值与选项进行比较。是否有类似的方法可以用于一堆绑定到相同模型属性的单选按钮?理想情况下,我希望能够告诉Angular使用我自己放置在这些模型对象上的自定义equals()方法,该方法检查对象类型和ID。不过,即使是能够指定ID比较也可以起作用。

admin 更改状态以发布 2023年5月24日
0
0 Comments

好的,经过进一步的审查,我决定采用更多的“混合”方法,只用自己定义的指令替换ng-model指令。实质上,这非常类似我用于创建基于此答案的“复选框列表”指令的方法:https://stackoverflow.com/a/14519881/561604

.directive('radioOptions', function() {
    // Apply this directive as an attribute to multiple radio inputs. The value of the attribute
    // should be the scope variable/expression which contains the available options for the
    // radio list. Typically, this will be the collection variable in an ng-repeat directive
    // that templates the individual radio inputs which have radio-options applied. In addition,
    // instead of the normal ng-model, use a selected-option attribute set to the same expression.
    // For example, you might use radio-options like this:
    // 
    //
    // See https://stackoverflow.com/questions/19281404/object-equality-comparison-for-inputradio-with-ng-model-and-ng-value
    // for the SO question that inspired this directive.
    return {
        scope: {
            radioOptions: '=',
            selectedOption: '=',
            ngValue: '='
        },
        link: function( scope, elem, attrs ) {
            var modelChanged =  function() {
                if( jQuery.isArray(scope.radioOptions) ) {
                    jQuery.each( scope.radioOptions, function(idx, item) {
                        // This uses our models' custom 'equals' function for comparison, but another application could use
                        // ID propeties, etc.
                        if( typeof item.equals === 'function' && item.equals(scope.selectedOption) ) {
                            elem.prop( 'checked', item === scope.ngValue );
                        }
                    });
                }
            };
            scope.$watch( 'radioOptions', modelChanged );
            scope.$watch( 'selectedOption', modelChanged );
            var viewChanged = function() {
                var checked = elem.prop( 'checked' );
                if( checked ) {
                    scope.selectedOption = scope.ngValue;
                }
            };
            elem.bind( 'change', function() {
                scope.$apply( viewChanged );
            });
        }
    };
});

0
0 Comments

我编写了一个最简单的指令,使用一种“track-by”方法映射两个不同的对象。请参见http://jsfiddle.net/xWWwT/146/

HTML

    
  • {{ color.name }}
Preview: {{ thing }}

JS

var app = angular.module('app', []);
app.controller('ThingControl', function($scope){
    $scope.colors = [
        { name: "White", hex: "#ffffff"},
        { name: "Black", hex: "#000000"},
        { name: "Red", hex: "#000000"},
        { name: "Green", hex: "#000000"}
    ];
    $scope.thing = { name: "White", hex: "#ffffff"};
});
app.directive('radioTrackBy', function(){
return {
        restrict: "A",
        scope: {
            ngModel: "=",
            ngValue: "=",
            radioTrackBy: "@"
        },
        link: function (ng) {   
            if (ng.ngValue[ng.radioTrackBy] === ng.ngModel[ng.radioTrackBy]) {                                
                ng.ngModel = ng.ngValue;
            }
        }
    };
});

0