I'm running an angular / mvc website. And I separate all my model and stuff. At some point I feel need of an extra property which is not part of my model. I though of inheritance and start writing codes. first I went with 'getter', seeing it's get override simply, I though about something more supported by intellisense like method, so one won't simply override it without thinking.
here what I write:
/**
* Created by Hassan on 4/4/2016.
*/
abstract class DynamicPropertiesProvider {
private _dynamicProperties:Object;
constructor() {
this._dynamicProperties = {};
}
dynamicProperties():Object {
return this._dynamicProperties;
}
}
and then i use it in my model like:
/**
* Created by Hassan on 3/16/2016.
*/
///<reference path="dynamicPropertiesProvider.ts"/>
class AcDocRow extends DynamicPropertiesProvider{
public FinYear: string;
public DocNoTemp: number;
public DocRow: number;
public HsbCod: string;
public RowDsc: string;
public Bedehkar: number;
public Bestankar: number;
public Bookmark: boolean;
public MainDocNo: number;
public DocDate: string;
//Getters And Setters
get CompositeKey():string {
return this.FinYear + "-" + this.DocNoTemp + "-" + this.DocRow;
}
get Date():string {
return ((this.DocDate) ? this.DocDate.substr(0, 4) + "/" + this.DocDate.substr(4, 2) + "/" + this.DocDate.substr(6, 2) : "");
}
constructor(finYear, docNoTemp, docRow, hsbCod, rowDsc, bedehkar, bestankar, bookmark, mainDocNo, docDate){
super(); //Call Super (Parent) Class Constructor
this.setup();
if (finYear != undefined) this.FinYear = finYear;
if (docNoTemp != undefined) this.DocNoTemp = docNoTemp;
if (docRow != undefined) this.DocRow = docRow;
if (hsbCod != undefined) this.HsbCod = hsbCod;
if (rowDsc != undefined) this.RowDsc= rowDsc;
if (bedehkar != undefined) this.Bedehkar = bedehkar;
if (bestankar != undefined) this.Bestankar= bestankar;
if (bookmark != undefined) this.Bookmark = bookmark;
if (mainDocNo != undefined) this.MainDocNo= mainDocNo;
if (docDate != undefined) this.DocDate= docDate;
}
private setup():void{
this.FinYear = "";
this.DocNoTemp = 0;
this.DocRow = 0;
this.HsbCod = "";
this.RowDsc = "";
this.Bedehkar = 0;
this.Bestankar = 0;
this.Bookmark = false;
this.MainDocNo = 0;
this.DocDate = "";
}
public copy():AcDocRow{
return new AcDocRow(this.FinYear, this.DocNoTemp, this.DocRow, this.HsbCod, this.RowDsc, this.Bedehkar, this.Bestankar, this.Bookmark, this.MainDocNo, this.DocDate);
}
public resetModel(finYear, docNoTemp, docRow, hsbCod, rowDsc, bedehkar, bestankar, bookmark, mainDocNo, docDate): void{
this.constructor(finYear, docNoTemp, docRow, hsbCod, rowDsc, bedehkar, bestankar, bookmark, mainDocNo, docDate);
}
}
but the compiled JS, does not contains the method i wrote in 'DynamicPropertiesProvider' class:
For DynamicPropertiesProvider:
/**
* Created by Hassan on 4/4/2016.
*/
var DynamicPropertiesProvider = (function () {
function DynamicPropertiesProvider() {
this._dynamicProperties = {};
}
DynamicPropertiesProvider.prototype.dynamicProperties = function () {
return this._dynamicProperties;
};
return DynamicPropertiesProvider;
})();
//# sourceMappingURL=dynamicPropertiesProvider.js.map
For AcDocRow:
/**
* Created by Hassan on 3/16/2016.
*/
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
///<reference path="dynamicPropertiesProvider.ts"/>
var AcDocRow = (function (_super) {
__extends(AcDocRow, _super);
function AcDocRow(finYear, docNoTemp, docRow, hsbCod, rowDsc, bedehkar, bestankar, bookmark, mainDocNo, docDate) {
_super.call(this); //Call Super (Parent) Class Constructor
this.setup();
if (finYear != undefined)
this.FinYear = finYear;
if (docNoTemp != undefined)
this.DocNoTemp = docNoTemp;
if (docRow != undefined)
this.DocRow = docRow;
if (hsbCod != undefined)
this.HsbCod = hsbCod;
if (rowDsc != undefined)
this.RowDsc = rowDsc;
if (bedehkar != undefined)
this.Bedehkar = bedehkar;
if (bestankar != undefined)
this.Bestankar = bestankar;
if (bookmark != undefined)
this.Bookmark = bookmark;
if (mainDocNo != undefined)
this.MainDocNo = mainDocNo;
if (docDate != undefined)
this.DocDate = docDate;
}
Object.defineProperty(AcDocRow.prototype, "CompositeKey", {
//Getters And Setters
get: function () {
return this.FinYear + "-" + this.DocNoTemp + "-" + this.DocRow;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AcDocRow.prototype, "Date", {
get: function () {
return ((this.DocDate) ? this.DocDate.substr(0, 4) + "/" + this.DocDate.substr(4, 2) + "/" + this.DocDate.substr(6, 2) : "");
},
enumerable: true,
configurable: true
});
AcDocRow.prototype.setup = function () {
this.FinYear = "";
this.DocNoTemp = 0;
this.DocRow = 0;
this.HsbCod = "";
this.RowDsc = "";
this.Bedehkar = 0;
this.Bestankar = 0;
this.Bookmark = false;
this.MainDocNo = 0;
this.DocDate = "";
};
AcDocRow.prototype.copy = function () {
return new AcDocRow(this.FinYear, this.DocNoTemp, this.DocRow, this.HsbCod, this.RowDsc, this.Bedehkar, this.Bestankar, this.Bookmark, this.MainDocNo, this.DocDate);
};
AcDocRow.prototype.resetModel = function (finYear, docNoTemp, docRow, hsbCod, rowDsc, bedehkar, bestankar, bookmark, mainDocNo, docDate) {
this.constructor(finYear, docNoTemp, docRow, hsbCod, rowDsc, bedehkar, bestankar, bookmark, mainDocNo, docDate);
};
return AcDocRow;
})(DynamicPropertiesProvider);
//# sourceMappingURL=acDocRow.js.map
My ts compiler is the one come along with WebStrom 11.0 and i aslo set '--target es5' flag.
what should i do?
Edit due iberbeu comment:
My Service Where i read the data from server, and then i create a AcDocRow object from them
app.factory("AcDocRowService",
["$resource",
function ($resource) {
//noinspection JSUnusedGlobalSymbols,JSUnusedLocalSymbols
return $resource("/api/AcDocRows/:id:filter:param1/:param2",
{
id: "@id",
param1: "@param1",
param2: "@param2",
filter: "@filter"
},
{
"query": {
method: "GET",
isArray: true,
transformResponse: function(data, header) {
var wrapped = angular.fromJson(data);
//If contains exceptions, it is not a list and should return directly without modification
//noinspection JSUnresolvedVariable
if (!wrapped.ExceptionType && !wrapped.ExceptionMessage) {
angular.forEach(wrapped, function (item, idx) {
wrapped[idx] = new AcDocRow(
wrapped[idx].FinYear,
wrapped[idx].DocNoTemp,
wrapped[idx].DocRow,
wrapped[idx].HsbCod,
wrapped[idx].RowDsc,
wrapped[idx].Bedehkar,
wrapped[idx].Bestankar,
wrapped[idx].Bookmark,
wrapped[idx].MainDocNo,
wrapped[idx].DocDate
);
});
}
return wrapped;
}
},
"get": {
method: "GET",
isArray: false
},
"update": {
method: "PUT"
},
"setBookmark":{
method: "PUT",
params:{
param2: "SetBookmark"
}
}
}
);
}
]
);
My controller when i tell service to return data, and then i bind it to the view.
app.controller("IndexController", [
"$rootScope", "$scope", "$uibModal", "$timeout", "AcDocRowService", "FinYearService",
function ($rootScope, $scope, $uibModal, $timeout, AcDocRowService, FinYearService) {
$scope.View = {
SarfaslSelectionDialog: {
ShowDialog: false,
/**
* Output Result Selected Sarfasl
*/
SelectedSarfasl: null,
FinYear: null,
InitialHsbCod: null
},
CodeInfo: {
LenCod: 0,
LenK: 0,
LenM: 0,
LenT1: 0,
LenT2: 0,
LenJ: 0
},
OperationMode: null,
Errors: [],
AcDocRowList: [],
AcDocRowFilters:{
ShowFilters: false,
Bookmark: null,
FromDate: "",
ToDate: "",
FromDocNoTemp: null,
ToDocNoTemp: null,
FromPrice: null,
ToPrice: null
},
AcDocRowSummery: {
TotalResult: 0,
CheckedResult: 0,
UncheckedResult: 0,
TotalDemand: 0,
TotalDept: 0,
CheckedDemand: 0,
CheckedDept: 0,
UncheckedDemand: 0,
UncheckedDept: 0
},
SelectedItems: []
};
$scope.Events= {
selectRow: function(row){
if($scope.View.SelectedItems.contains(row)){
$scope.View.SelectedItems.remove(row);
} else {
$scope.View.SelectedItems.push(row)
}
//MY OLD CODES WHERE I READ THE 'row' Object
//if(! row.dynamicProperties()["selected"])
// row.dynamicProperties()["selected"]= true;
//row.dynamicProperties()["selected"] = !row.dynamicProperties()["selected"];
},
...
//Where i set AcDocRowList, That i use in my View
searchAcDocRows: function() {
$scope.Events.openWaitDialog();
//If Method Called On Start By $Watch, Return
if($scope.View.SarfaslSelectionDialog.SelectedSarfasl == null){
return;
}
var sarfaslParams = $scope.View.SarfaslSelectionDialog;
var filter = "FinYear=" + sarfaslParams.FinYear + "-HsbCod=" + sarfaslParams.SelectedSarfasl.getClearHsbCod();
AcDocRowService.query({ filter: filter }).$promise.then(
function (data) {
$scope.Methods.resetTotals();
$scope.View.AcDocRowList = data;
$scope.Events.closeWaitDialog();
}, function (errorResult) {
$scope.View.Errors.push(new Alert("Cannot contact web server at this moment. Please try again later.", AlertType.Danger));
$scope.Events.closeWaitDialog();
}
);
}
...
};
...
}
]);
My View:
...
<tbody>
<tr data-ng-repeat="row in View.AcDocRowList | filter: Filters.acDocRowFilterFunction"
data-ng-class="{'checked-row':row.Bookmark}" data-ng-click="Events.selectRow(row)">
<td>
<input type="checkbox" ng-model="row.Bookmark" data-ng-click="Events.setBookmark(row)">
</td>
<td class="number">
<!--Restart Total Price-->
{{Methods.setTotal($index, row.Bookmark); $index | persianNumberFilter}}
</td>
<td class="number">{{row.DocNoTemp | persianNumberFilter}}</td>
<td>
<!--row.Date is a 'getter' -->
{{row.Date | persianNumberFilter}}
</td>
<td>{{row.RowDsc | persianNumberFilter}}</td>
<td class="number">{{row.Bedehkar!=0?row.Bedehkar:"" | priceFilter | persianNumberFilter}}</td>
<td class="number">{{row.Bestankar!=0?row.Bestankar:"" | priceFilter | persianNumberFilter}}</td>
<td>
{{Methods.getTashkhis()}}
</td>
<td class="number">
{{Methods.getRemains()!=0?Methods.getRemains():"" | priceFilter | persianNumberFilter}}
</td>
</tr>
</tbody>
...
Solved
AngularJs ngResource doesn't parse transformResponse action directly. it pass it to $http in angular core to handle it. and once the result come out. it again fold the data inside object of Resource class. that's when resource constructor do a shallow copy as it named the method. and as it's name says lot of things in the deeper level go loss, also object type get changed.
I fix the issue with updating the angular ngResource and provide with new action "transformResult", and I use it instead of transformResponse. it perform it's job at the end before ngResource pass results to the user.
https://github.com/deadmann/code.angularjs.org/blob/master/1.4.9/angular-resource.js
I also made pull request, which I don't think so, but I hope they accept. https://github.com/angular/code.angularjs.org/pull/35

