javascript - Binding to arbitrarily deep properties on an object based on rules -


(i'm sorry if question title isn't good, couldn't think of better one. feel free suggest better options.)

i'm trying create reusable "property grid" in angular, 1 can bind object grid, in such way presentation of object can customized somewhat.

this directive template looks (the form-element isn't important question, i'll leave out):

<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> 

and, directive code:

angular.module("app.shared").directive('propertygrid', ['$log', function($log) {     return {         restrict: 'e',         scope: {             propertyobject: '=',             propertydata: '&'         }         templateurl: 'views/propertygrid.html'     }; }]); 

here's example usage:

<property-grid edit-mode="true"                property-object="selectedsite"                property-data="getsitepropertydata(object)"> </property-grid> 

and getsitepropertydata() function goes it:

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; }; 

the reason i'm going through such "property data" function , not binding directly properties on object need control order of properties, whether should shown user @ all, , kind of property (text, email, number, date, etc.) sake of presentation.

at first, can tell value property remnant in getsitepropertydata() function, first tried providing values directly function, wouldn't bind object, changes either in object or form property grid didn't sync , forth. next up, then, using key idea, lets me this: propertyobject[prop.key]—which works great direct properties, can see, had comment out "company" field, because it's property of property, , propertyobject["a.b"] doesn't work.

i'm struggling figure out here. need bindings work, , need able use arbitrarily deep properties in bindings. know kind of thing theoretically possible; i've seen done instance in ui grid, such projects have code spend days finding out how it.

am getting close, or going wrong?

you want run arbitrary angular expression on object. purpose of $parse (ref). service can well... parse angular expression , return getter , setter. following example oversimplified implementation of formelement directive, demonstrating use of $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);         }       });     }   }; }]); 

i have altered way directive used, without changing semantics:

<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"> 

where root-obj top of model , path expression reach actual data.

as can see, $parse creates getter , setter function given expression, root object. in model.data property, apply accessor functions created $parse root object. entire object.defineproperty construct replaced watches, add overhead digest cycle.

here working fiddle: https://jsfiddle.net/zb6cfk6y/


by way, (more terse , idiomatic) way write get/set be:

  object.defineproperty(scope.data, 'model', {     get: getmodel.bind(null, scope.rootobj),     set: setmodel.bind(null, scope.rootobj)   }); 

Comments

Popular posts from this blog

sequelize.js - Sequelize group by with association includes id -

android - Robolectric "INTERNET permission is required" -

java - Android raising EPERM (Operation not permitted) when attempting to send UDP packet after network connection -