Search code examples
javascriptjqueryknockout.jsknockout-mapping-pluginjquery-select2

Knockout.js mapping ignore


We're working with knockout.js and knockout.mapping.js on .NET MVC 4. Let's say I have such JSON:

{
    "deliveryPointType": "0",
    "deliveryPointTypes": [
        {
            "id": 0,
            "text": "Pridėti rankiniu būdu"
        },
        {
            "id": 1,
            "text": "Siųsti visiems regiono objektams"
        }
    ],
    "showRegionSelection": false,
    "showDeliveryPointSelection": true,
    "regionId": "",
    "userHasRegions": "False",
    "propertyNames": {
        "deliveryPointTypeName": "Pridėti rankiniu būdu"
    },
    "initialMaterials": [
        {
            "quantity": 0,
            "materialTypeId": "",
            "propertyNames": {},
            "validMaterial": true,
            "showMaterialError": false,
            "materialTypeAjax": {
                "quietMillis": 300,
                "cache": false,
                "dataType": "json",
                "type": "GET",
                "url": "/lt-LT/Material/MaterialTypeNameLookup"
            }
        }
    ],
    "deliveryBuildings": [
        {
            "clientId": "1",
            "buildingId": "1",
            "regionId": "",
            "newBuilding": false,
            "validClient": true,
            "validBuilding": true,
            "validRegion": true,
            "showClientError": false,
            "showBuildingError": false,
            "showRegionError": false,
            "propertyNames": {
                "clientName": "klientas",
                "buildingName": "ASD project, Antagynės gatvė, Kaunas, Lietuvos Respublika"
            },
            "clientAjax": {
                "quietMillis": 300,
                "cache": false,
                "dataType": "json",
                "type": "GET",
                "url": "/lt-LT/Task/PayerLookup"
            },
            "buildingAjax": {
                "quietMillis": 300,
                "cache": false,
                "dataType": "json",
                "type": "GET",
                "url": "/lt-LT/Object/GetClientAddressListByQuery"
            },
            "regionAjax": {
                "quietMillis": 300,
                "cache": false,
                "dataType": "json",
                "type": "GET",
                "url": "/lt-LT/Object/RegionNameLookup"
            }
        }
    ],
    "hasNewBuildings": false,
    "showBuildingValidation": false,
    "showMinimumBuildingRequiredValidation": false,
    "showMaterialValidation": false,
    "validRegion": true,
    "showRegionError": false,
    "regionAjax": {
        "quietMillis": 300,
        "cache": false,
        "dataType": "json",
        "type": "GET",
        "url": "/lt-LT/Object/RegionNameLookup"
    } 
}

On form submit fail (if something goes wrong/invalid in service) it is repopulated with previous values. We convert ViewModel to JSON on form submit with $('#BuildingsJSON').val(ko.mapping.toJSON(viewModel.deliveryBuildings)).

On form repopulating, we parse JSON with ko.mapping.fromJSON(deliveryBuildings, mapping, viewModel.deliveryBuildings)(); mapping is just an empty object for now (tried "ignore" with no luck).

We use select2 fields to select addresses of buildings from a list (using ajax). Thing is, fromJSON populates almost every json property as observable, which I don't need. On select2 open we get an exception:

Uncaught TypeError: Object function observable() { if (arguments.length > 0) { // Write

        // Ignore writes if the value hasn't changed
        if (!observable['equalityComparer'] || !observable['equalityComparer'](_latestValue, arguments[0])) {
            observable.valueWillMutate();
            _latestValue = arguments[0];
            if (DEBUG) observable._latestValue = _latestValue;
            observable.valueHasMutated();
        }
        return this; // Permits chained assignments
    }
    else {
        // Read
        ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read"

operation return _latestValue; } } has no method 'toUpperCase'

I've debugged where it breaks - on type property of ajax call. I figured that we need to exclude ajax properties from casting to observable.

So, the question is: how can one not cast specific properties of specific objects to observable()? Is it enough using mapping plugin, is additional plugin needed or is it even impossible?


Solution

  • Have you looked at using the copy keyword in your mapping binding? This just copies the value over into a js property rather than making it an observable.

    From the documentation:

    var mapping = {
        'copy': ["propertyToCopy"]
    }
    ko.mapping.fromJS(data, mapping, viewModel);