Skip to content

Add property name translation support. #64

Closed
wants to merge 1 commit into from
View
29 knockout.mapping.js
@@ -381,25 +381,31 @@
// For non-atomic types, visit all properties and update recursively
visitPropertiesOrArrayEntries(rootObject, function (indexer) {
var fullPropertyName = getPropertyName(parentPropertyName, rootObject, indexer);
+ var mappedIndexer = indexer;
+
+ if (options.propertyNameTranslator) {
+ fullPropertyName = options.propertyNameTranslator(fullPropertyName);
+ mappedIndexer = options.propertyNameTranslator(indexer);
+ }
if (ko.utils.arrayIndexOf(options.ignore, fullPropertyName) != -1) {
return;
}
if (ko.utils.arrayIndexOf(options.copy, fullPropertyName) != -1) {
- mappedRootObject[indexer] = rootObject[indexer];
+ mappedRootObject[mappedIndexer] = rootObject[indexer];
return;
}
// In case we are adding an already mapped property, fill it with the previously mapped property value to prevent recursion.
// If this is a property that was generated by fromJS, we should use the options specified there
var prevMappedProperty = visitedObjects.get(rootObject[indexer]);
- var value = prevMappedProperty || updateViewModel(mappedRootObject[indexer], rootObject[indexer], options, indexer, mappedRootObject, fullPropertyName);
+ var value = prevMappedProperty || updateViewModel(mappedRootObject[mappedIndexer], rootObject[indexer], options, indexer, mappedRootObject, fullPropertyName);
- if (ko.isWriteableObservable(mappedRootObject[indexer])) {
- mappedRootObject[indexer](ko.utils.unwrapObservable(value));
+ if (ko.isWriteableObservable(mappedRootObject[mappedIndexer])) {
+ mappedRootObject[mappedIndexer](ko.utils.unwrapObservable(value));
} else {
- mappedRootObject[indexer] = value;
+ mappedRootObject[mappedIndexer] = value;
}
options.mappedProperties[fullPropertyName] = true;
@@ -629,6 +635,13 @@
var propertyValue = unwrappedRootObject[indexer];
var fullPropertyName = getPropertyName(parentName, unwrappedRootObject, indexer);
+
+ var mappedIndexer = indexer;
+
+ if (options.propertyNameTranslator) {
+ fullPropertyName = options.propertyNameTranslator(fullPropertyName);
+ mappedIndexer = options.propertyNameTranslator(indexer);
+ }
// If we don't want to explicitly copy the unmapped property...
if (ko.utils.arrayIndexOf(options.copy, indexer) === -1) {
@@ -648,10 +661,10 @@
case "array":
case "undefined":
var previouslyMappedValue = visitedObjects.get(propertyValue);
- mappedRootObject[indexer] = (exports.getType(previouslyMappedValue) !== "undefined") ? previouslyMappedValue : visitModel(propertyValue, callback, options, fullPropertyName);
+ mappedRootObject[mappedIndexer] = (exports.getType(previouslyMappedValue) !== "undefined") ? previouslyMappedValue : visitModel(propertyValue, callback, options, fullPropertyName);
break;
default:
- mappedRootObject[indexer] = callback(propertyValue, parentName);
+ mappedRootObject[mappedIndexer] = callback(propertyValue, parentName);
}
});
@@ -674,4 +687,4 @@
return (existingIndex >= 0) ? values[existingIndex] : undefined;
};
};
-}));
+}));
View
24 spec/mappingBehaviors.js
@@ -1561,3 +1561,27 @@ test('ko.mapping.visitModel on a regular object', function() {
value: 0
});
});
+
+test('ko.mapping.fromJS should translate property names', function() {
+
+ var target = {
+ id: ko.observable(),
+ title: ko.observable(),
+ items: ko.observableArray(),
+ child: {
+ a: ko.observable(),
+ b: ''
+ }
+ };
+
+ var obj = { Id: 1, Title: "Lorem ipsum", Items: [ 1, 2, 3 ], Child: { A: 'a', B: 'b'} };
+
+ ko.mapping.fromJS(obj, { propertyNameTranslator: function(name) { return name[0].toLowerCase() + name.slice(1); }}, target);
+
+ equal(obj.Id, target.id());
+ equal(obj.Title, target.title());
+ equal(obj.Items.length, target.items().length);
+ equal(obj.Child.A, target.child.a());
+ equal(obj.Child.B, target.child.b()); // Knockout promotes this to an observable!!!
+});
+
Something went wrong with that request. Please try again.