JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.js"></script>
<div ng-app="app" ng-controller="MainCtrl as mc">
<input-person ng-model="mc.data.person1"></input-person>
<br/>
<input-person ng-model="mc.data.person2"></input-person>
<button ng-click="mc.resetPerson2()">Reset Person 2</button>
<br/>
<pre><code>{{ mc.data | json }}</code></pre>
</div>
CSS
* {
box-sizing: border-box;
}
input-person {
display: block;
}
input-person > div > label {
display: block;
width: 280px;
margin-bottom: 3px;
}
input-person > div > label > span {
display: inline-block;
width: 120px;
}
input-person > div > label > input {
display: inline-block;
width: 160px;
}
input-address {
display: block;
}
input-address > div > label {
display: block;
width: 280px;
margin-bottom: 3px;
}
input-address > div > label > span {
display: inline-block;
width: 120px;
}
input-address > div > label > input {
display: inline-block;
width: 160px;
}
JavaScript
var app = angular.module('app', []);
function Person(data) {
data = data || {};
this.name = data.name;
this.address = data.address ? new Address(data.address) : null;
}
function Address(data) {
data = data || {};
this.street = data.street;
this.number = data.number;
}
app.controller('MainCtrl', function() {
this.data = {
person1: null,
person2: new Person({
name: 'Bob',
address: new Address({
street: 'Pineapple',
number: '7'
})
})
};
this.resetPerson2 = function() {
this.data.person2 = new Person({
name: 'Bob',
address: new Address({
street: 'Pineapple',
number: '7'
})
});
}
});
function AbstractInputObjectController($scope) {
this.$scope = $scope;
this._ngModel = null;
this.value = null;
this._unwatch = angular.noop;
}
// abstract method; implement this!
AbstractInputObjectController.prototype.makeCopy = null;
AbstractInputObjectController.prototype.setNgModel = function(ngModel) {
this._ngModel = ngModel;
if( ngModel ) {
ngModel.$render = this._render.bind(this);
}
};
AbstractInputObjectController.prototype._makeWatch = function() {
this._unwatch = this.$scope.$watchCollection(
(function() {
return this.value;
}).bind(this),
(function(newval, oldval) {
if( newval !== oldval ) { // skip the initial trigger
this._ngModel.$setViewValue(newval !== null ? this.makeCopy(newval) : null);
}
}).bind(this)
);
};
AbstractInputObjectController.prototype._render = function() {
this._unwatch();
this.value = this._ngModel.$viewValue ? this.makeCopy(this._ngModel.$viewValue) : null;
this._makeWatch();
};
app.directive('inputPerson', function() {
InputPersonController.$inject = ['$scope'];
function InputPersonController($scope) {
AbstractInputObjectController.call(this, $scope);
}
InputPersonController.prototype = Object.create(AbstractInputObjectController.prototype);
InputPersonController.prototype.constructor =...