Javascript 输入[radio]与ng模型和ng值的对象相等性比较
首先,我要说的是,这个问题与使用ng选项的Javascript 输入[radio]与ng模型和ng值的对象相等性比较,javascript,angularjs,Javascript,Angularjs,首先,我要说的是,这个问题与使用ng选项的标记中的选择问题非常相似。例如具体的问题是比较一个对象的两个不同实例,它们的引用不相等,但在逻辑上表示相同的数据 为了演示,假设我们在模型中有以下选项数组和选定的选项变量: $scope.items = [ {ID: 1, Label: 'Foo', Extra: 17}, {ID: 2, Label: 'Bar', Extra: 18}, {ID: 3, Label: 'Baz', Extra: 19} ]; $scope.selec
标记中的选择问题非常相似。例如具体的问题是比较一个对象的两个不同实例,它们的引用不相等,但在逻辑上表示相同的数据
为了演示,假设我们在模型中有以下选项数组和选定的选项变量:
$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属性。我在真实对象上有一个比较原型“class”和ID的equals()
函数
然后在视图中:
<label class="radio inline" ng-repeat="item in items">
<input type="radio" ng-model="selectedItem" ng-value="item"> {{item.Label}}
</label>
但是,我遇到的问题是,在我的应用程序中,我并不是简单地在范围中声明这两个简单变量。相反,选项列表和绑定所选选项的数据结构都是使用$http从服务器查询的较大JSON数据集的一部分。在一般情况下,我很难从数据查询中将数据绑定的selected属性更改为等效选项
所以,我的问题是:
在
的ng选项中,angular提供了一个track by
表达式,允许我说“object.ID”之类的话,并通知angular它应该通过ID属性将所选模型值与选项进行比较。是否有类似的东西可以用于绑定到相同模型属性的一组无线电输入?理想情况下,我可以告诉angular使用我自己的自定义equals()方法,该方法已放置在这些模型对象上,它会检查对象类型和ID。但是如果失败,则可以指定ID比较。为什么不像这样使用ID进行选择
<input type="radio" ng-model="selectedItem" ng-value="item.ID"> {{item.Label}}
{{item.Label}
然后,您可以编写项[selectedItem]
,而不是使用selectedItem
哦,在JSFIDLE中处理您的问题时,我注意到了其他一些事情:
a、 )您忘记将名称
属性添加到输入中
b、 )不要在ng模型中使用没有点的东西。如果您实际尝试在ng repeat块之外使用
{{selectedItem}}
输出selectedItem,您将注意到当您选择单选按钮时,该值不会更新。这是因为ng repeat
创建了自己的子作用域。根据OP的请求,下面是一个处理复杂对象的示例。它用于从选项中查找所选项目。它比应该的要复杂一点,因为它还支持通过AJAX调用加载选项和所选值。好的,所以在进一步审查之后,我决定采用更“混合”的方法,本质上只是用我自己的自定义指令替换ng模型指令。这与我使用的基于以下答案生成“checkbox list”指令的方法非常相似:
.directive('radioOptions',function(){
//将此指令作为属性应用于多个无线电输入。该属性的值
//应为范围变量/表达式,其中包含
//单选列表。通常,这将是ng REPLAT指令中的集合变量
//它为应用了无线电选项的单个无线电输入设置模板。此外,
//使用设置为同一表达式的选定选项属性,而不是普通ng模型。
//例如,您可以使用如下单选选项:
//
//
//
//
//看https://stackoverflow.com/questions/19281404/object-equality-comparison-for-inputradio-with-ng-model-and-ng-value
//对于启发本指令的SO问题。
返回{
范围:{
radioOptions:“=”,
所选选项:'=',
ngValue:“=”
},
链接:功能(范围、要素、属性){
var modelChanged=function(){
if(jQuery.isArray(scope.radioOptions)){
jQuery.each(scope.radioOptions,函数(idx,item){
//这将使用我们的模型“自定义”equals“函数进行比较,但另一个应用程序可以使用
//身份证、财产等。
if(typeof item.equals==='function'&&item.equals(scope.selectedOption)){
元素属性('checked',item==scope.ngValue);
}
});
}
};
范围:$watch('radioOptions',型号更改);
范围.$watch('selectedOption',型号已更改);
var viewChanged=函数(){
var checked=要素属性(“checked”);
如果(选中){
scope.selectedOption=scope.ngValue;
}
};
元素绑定('change',function(){
范围:$apply(视图已更改);
});
}
};
});
因为我还不能添加评论,所以我必须在这里回复。达娜的回答对我来说还行。尽管我想指出,为了使用他的方法,必须在集合中的对象上实现“equals”函数。请参见以下示例:
.controller('ExampleController', ['$scope', function($scope) {
var eq = function(obj) {
return this.id === obj.id;
};
col = [{id: 1, name: 'pizza', equals: eq}, {id:2, name:'unicorns', equals: eq}, {id:3, name:'robots', equals: eq}];
$scope.collection = col;
$scope.my = { favorite : {id:2, name:'unicorns'} };
}]);
参见plunker。我编写了一个最简单的指令。使用一种“跟踪方式”来映射两个不同的对象。看 HTML
我们使用underline.js中的方法解决了这个问题,方法是在开始时从选项中选择值。我还想知道是否可以这样做。我不使用undescore.js,但我不介意使用我自己的比较函数来做我需要的事情。你到底在哪里雇佣芬德的?在自定义指令中?是的,我们有单选按钮,下拉指令就用于此。我不知道
.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:
// <label ... ng-repeat="item in collection">
// <input type="radio" ... ng-value="item" radio-options="collection" selected-option="myModel.myProperty">
// </label>
//
// 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 );
});
}
};
});
.controller('ExampleController', ['$scope', function($scope) {
var eq = function(obj) {
return this.id === obj.id;
};
col = [{id: 1, name: 'pizza', equals: eq}, {id:2, name:'unicorns', equals: eq}, {id:3, name:'robots', equals: eq}];
$scope.collection = col;
$scope.my = { favorite : {id:2, name:'unicorns'} };
}]);
<div ng-app="app">
<div ng-app ng-controller="ThingControl">
<ul >
<li ng-repeat="color in colors">
<input type="radio" name="color" ng-model="$parent.thing" ng-value="color" radio-track-by="name" />{{ color.name }}
</li>
</ul>
Preview: {{ thing }}
</div>
</div>
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;
}
}
};
});