JSFiddle - React, Tailwind, and code Playground

HTML

<div ng-app="app" ng-controller="Ctrl as ctrl">
  <property-grid edit-mode="true"
                 property-object="ctrl.selectedSite"
                 property-data="ctrl.getSitePropertyData(object)">
  </property-grid>
  <hr/>
  <button ng-click="ctrl.showModel()">Show</button>
</div>

JavaScript

var app = angular.module('app', []);

app.controller('Ctrl', function() {
	this.selectedSite = {};

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

      if (site == lastSite)
          return lastSitePropertyData;

      lastSite = site;
      lastSitePropertyData = [
          { key: "SiteName", editable: true, type: "text" },
          { key: "Company.CompanyName", editable: false, type: "text" },
          { key: "Info", editable: true, type: "text" }
      ];
      return lastSitePropertyData;
  };
  
  this.showModel = function() {
  	console.log(this.selectedSite);
  };
});

app.directive('propertyGrid', ['$log', function($log) {
    return {
        restrict: 'E',
        scope: {
            propertyObject: '=',
            propertyData: '&'
        },
        template:
          '<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}}" ' +
                                    'root-obj="propertyObject" ' +
                                    'path="{{prop.key}}" ' +
                                    'focus-events-enabled="false">' +
                      '</form-element>' +
                  '</div>' +
              '</div>' +
          '</div>'
    };
}]);

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