gpt4 book ai didi

javascript - 根据规则绑定(bind)到对象上任意深度的属性

转载 作者:数据小太阳 更新时间:2023-10-29 04:47:27 24 4
gpt4 key购买 nike

(很抱歉,如果我的问题标题不是很好,我想不出更好的。欢迎提出更好的选择。)

我正在尝试在 Angular 中创建一个可重用的“属性网格”,其中可以将对象绑定(bind)到网格,但通过某种方式可以自定义对象的呈现方式。

这是指令模板的样子(form-element 对我的问题不重要,所以我将其省略):

<div ng-repeat="prop in propertyData({object: propertyObject})">
<div ng-switch on="prop.type">
<div ng-switch-when="text">
<form-element type="text"
label-translation-key="{{prop.key}}"
label="{{prop.key}}"
name="{{prop.key}}"
model="propertyObject[prop.key]"
focus-events-enabled="false">
</form-element>
</div>
</div>
</div>

并且,指令代码:

angular.module("app.shared").directive('propertyGrid', ['$log', function($log) {
return {
restrict: 'E',
scope: {
propertyObject: '=',
propertyData: '&'
}
templateUrl: 'views/propertyGrid.html'
};
}]);

这是一个示例用法:

<property-grid edit-mode="true"
property-object="selectedSite"
property-data="getSitePropertyData(object)">
</property-grid>

还有 getSitePropertyData() 函数:

var lastSite;
var lastSitePropertyData;
$scope.getSitePropertyData = function (site) {
if (site == undefined) return null;

if (site == lastSite)
return lastSitePropertyData;

lastSite = site;
lastSitePropertyData = [
{key:"SiteName", value:site.SiteName, editable: true, type:"text"},
//{key:"Company.CompanyName", value:site.Company.CompanyName, editable: false, type:"text"},
{key:"Address1", value:site.Address1, editable: true, type:"text"},
{key:"Address2", value:site.Address2, editable: true, type:"text"},
{key:"PostalCode", value:site.PostalCode, editable: true, type:"text"},
{key:"City", value:site.City, editable: true, type:"text"},
{key:"Country", value:site.Country, editable: true, type:"text"},
{key:"ContactName", value:site.ContactName, editable: true, type:"text"},
{key: "ContactEmail", value: site.ContactEmail, editable: true, type:"email"},
{key: "ContactPhone", value: site.ContactPhone, editable: true, type:"text"},
{key: "Info", value: site.Info, editable: true, type:"text"}
];
return lastSitePropertyData;
};

我使用这样一个“属性数据”函数而不是直接绑定(bind)到对象的属性的原因是我需要控制属性的顺序,以及它们是否应该显示给用户,以及它是什么类型的属性(文本、电子邮件、数字、日期等)以便于展示。

起初,正如您可以从 getSitePropertyData() 函数中的 value 属性残余中看出的那样,我首先尝试直接从该函数提供值,但那不会't 绑定(bind)到对象,因此对象或属性网格中的更改不会来回同步。接下来,是使用 key 的想法,它让我可以这样做:propertyObject[prop.key]——这对直接属性非常有用,但正如你所看到的,我不得不注释掉“公司”字段,因为它是属性的属性,propertyObject["a.b"] 不起作用。

我正在努力想在这里做什么。我需要绑定(bind)才能工作,并且我需要能够在我的绑定(bind)中使用任意深度的属性。我知道这种事情在理论上是可能的;例如,我已经在 UI Grid 中看到它完成了,但此类项目的代码太多,我可能会花几天时间了解它们是如何做到的。

我是接近了,还是我做错了?

最佳答案

您想在对象上运行任意 Angular 表达式。这正是 $parse ( ref ) 的目的。这个服务可以很好地……解析一个 Angular 表达式并返回一个 getter 和 setter。以下示例是 formElement 指令的过度简化实现,演示了 $parse 的用法:

app.directive('formElement', ['$parse', function($parse) {
return {
restrict: 'E',
scope: {
label: '@',
name: '@',
rootObj: '=',
path: '@'
},
template:
'<label>{{ label }}</label>' +
'<input type="text" ng-model="data.model" />',
link: function(scope) {
var getModel = $parse(scope.path);
var setModel = getModel.assign;
scope.data = {};
Object.defineProperty(scope.data, 'model', {
get: function() {
return getModel(scope.rootObj);
},
set: function(value) {
setModel(scope.rootObj, value);
}
});
}
};
}]);

我稍微改变了指令的使用方式,希望不会改变语义:

<form-element type="text"
label-translation-key="{{prop.key}}"
label="{{prop.key}}"
name="{{prop.key}}"
root-obj="propertyObject"
path="{{prop.key}}"
focus-events-enabled="false">

其中root-obj是模型的顶层,path是到达实际数据的表达式。

如您所见,$parse 为给定的表达式、任何根对象创建 getter 和 setter 函数。在 model.data 属性中,您将 $parse 创建的访问器函数应用于根对象。整个 Object.defineProperty 构造可以用 watch 代替,但这只会增加摘要周期的开销。

这是一个有效的 fiddle :https://jsfiddle.net/zb6cfk6y/


顺便说一下,另一种(更简洁和惯用的)编写 get/set 的方法是:

  Object.defineProperty(scope.data, 'model', {
get: getModel.bind(null, scope.rootObj),
set: setModel.bind(null, scope.rootObj)
});

关于javascript - 根据规则绑定(bind)到对象上任意深度的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37721509/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com