https://github.com/CarlosOnline/knockout.es5.mapping
/* Knockout ES5 track nested objects: TypeScript version.
Solves the problem of ko.track not traversing into nested objects.
- Calls ko.es5.track on nested objects: allowing tracking of strings, numbers, & arrays.
- Use ko.es5.computed(function() ...) to mark computed functions. ko.es5.track will call ko.defineProperty on these marked functions, after calling ko.track on the primitive members.
- Excludes nested functions/objects with named constructors. Idea is that TypeScript classes with constructors can call ko.es5.track themselves. This exclusion can be removed.
- Does not traverse into nested classes/objects with named constructors will not be traversed. These constructors should call ko.es5.track themselves.
- Does not handle null valued variables. Cannot deduce the type from these variables.
interface KnockoutStatic { es5: { computed: Function; track: Function; }; } module koES5 { function getType(x) { if ((x) && (typeof (x) === "object")) { if (x.constructor === Date) return "date"; if (x.constructor === Array) return "array"; } return typeof x; } export class Track { mapped = []; constructor(private rootObject: any) { this.track(rootObject); this.clearAllMapped(); } track(source, name: string = null) { if (source == null || this.isMapped(source)) return; if (name == null) name = this.name(source); var keys = []; var computed = []; this.setMapped(source); for (var key in source) { var value = source[key]; var type = getType(value); switch (type) { case "array": case "string": case "number": //console.log(name + "." + key, type); keys.push(key); break; case "function": if (this.isComputed(value)) { //console.log("f> " + name + "." + key, type); computed.push({ name: key, fn: value }); } break; case "object": if (value == null || this.isMapped(value) || !this.isTrackable(value) || !this.isTrackableField(key)) continue; //console.log("o> " + name + "." + key, type); this.track(value, key); break; } } if (keys.length > 0) { ko.track(source, keys); } if (computed.length > 0) { computed.forEach((item) => { this.makeComputed(source, item.name, item.fn); }); } } private name(value) { var xtor = value.__proto__.constructor; return xtor !== undefined && xtor.name != undefined ? xtor.name : ""; } private isTrackable(value) { var xtor = value.__proto__.constructor; return xtor.name === "Object"; } private isTrackableField(key: string) { return key != "__ko_mapping__"; } private isMapped(value: any) { return (value.__tracked__ === true); } private setMapped(value: any) { if (this.isMapped(value)) return; value.__tracked__ = true; this.mapped.push(value); } private clearAllMapped() { this.mapped.forEach((value) => { delete value["__tracked__"]; }); this.mapped.unshift(); } private isComputed(fn: Function) { return (fn["__ko_es5_computed__"] === true); } private makeComputed(container: any, name: string, fn: Function) { var nameOverride = fn["__ko_es5_computed_name__"]; if (nameOverride !== undefined && nameOverride !== "") { name = nameOverride; delete fn["__ko_es5_computed_name__"]; } if (name === undefined || name == "") { console.log("Error. Function missing name", fn); return; } ko.defineProperty(container, name, fn); delete fn["__ko_es5_computed__"]; } } export function track(root: any) { new Track(root); } export function computed(fn: Function, name: string = null) { fn["__ko_es5_computed__"] = true; if (name || false) { fn["__ko_es5_computed_name__"] = true; } return fn; } ko.es5 = { computed: koES5.computed, track: koES5.track, }; }
This comment has been removed by the author.
ReplyDeleteNice Information Keep LeraningAngularJS Online Training Bangalore
ReplyDelete