nested data and safe way to handle change on deep child value

hi guys, i’ve a little question, i’m working with deep nested data and i need to handle change on it, i’m mapping each value that i need to handle change individualy and i’m insert it within an each method in my ux page. my question is , is it safe to put inside a each method an observable who do not belong to it ?
the full project can be found here https://www.dropbox.com/s/kohfjxw7b4fi57s/Archive.zip?dl=0.

page pageMain.js of my project, this is the data structure.

var data = Observable(
  {
    "reference": "Y50zN5q",
    "createdAt": "",
    "updatedAt": "",
    "stepDtoSetIndexTotal": 2,
    "CurrentstepDtoSetIndex": 1,
    "CurrentcheckStepListIndex": 1,
    "customer": {
    "address": "3 Rue de Rivoli, 75004 Paris, France",
    "gender": "M",
    "firstName": "test",
    "lastName": "customer",
    "companyName": "my company",
    "displayName": "M test customer",
    "phoneNumber": "0123456789",
    "email": "test@dq.fr",
    "driverLicense": {
      "number": null,
      "deliveredLocation": null,
      "deliveredDate": null
    },
    "secondDriverLicense": null,
    "deliveredDate": null,
    "birthDate": null,
    "birthLocation": null
    },
    "stepDtoSet": [
    {
      "typeEnum": "FROM",
      "stepNumber": 0,
      "active": true,
      "address": "27 TER AVENUE LOUIS BREGUET 78140 VELIZY",
      "arrivalDateTime": "2017-07-03T15:30:00.000Z",
      "departureDateTime": "2017-07-03T15:40:00.000Z",
      "estimatedWaitInMinutes": 10,
      "type": "CONCESSION",
      "concession": {
        "id": "57169f1be4b0f6ce07be1d14",
        "name": "CITROËN RETAIL VELIZY",
        "shortName": "CR Velizy",
        "address": "27 TER AVENUE LOUIS BREGUET 78140 VELIZY",
        "concessionCity": "Paris",
        "phoneNumberForCustomer": "0123456789"
      },
      "checkStepList": [
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.Identity",
          "type": "IDENTITY",
          "checkStepNumber": 0,
          "transferAlone": false,
          "gender": null,
          "firstName": null,
          "lastName": null,
          "phoneNumber": null,
          "email": null,
          "registrationCardAvailable": false,
          "insuranceCertificateAvailable": false,
          "insuranceVisibleCard": false,
          "car": {
            "type": "VC",
            "brand": "Citroën",
            "model": "C3",
            "color": "ROUGE",
            "plateNumber": "AA111AA",
            "serialNumber": "82155555",
            "display": ""
          },
          "documentSet": [
            {"CAR_REGISTRATION": false,
            "CAR_INSURANCE_CERTIFICATE" : false
          }
          ]
        },
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.StateCar",
          "type": "STATE_CAR",
          "checkStepNumber": 1,
          "fuelQuantity": 0,
          "mileage": 0,
          "spareWheel": false,
          "antiTheftNut": false,
          "antiTheftNutExplanation": null,
          "stateCarProblemSet": [
            {
              "photo": "ROOF",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "HOOD",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "WINDSCREEN_FRONT",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "WINDSCREEN_BACK",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BUMPER_FRONT",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BUMPER_BACK",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_LEFT_DOOR",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_RIGHT_DOOR",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_LEFT_DOOR",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_RIGHT_DOOR",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_LEFT_FENDER",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_RIGHT_FENDER",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_LEFT_FENDER",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_RIGHT_FENDER",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_LEFT_WHEEL",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_RIGHT_WHEEL",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_LEFT_WHEEL",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_RIGHT_WHEEL",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "SPARE_WHEEL",
              "driverExplanation": null,
              "explanation": null
            }
          ],
          "stateCarProblemAloneSet": null
        },
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.Invoice",
          "type": "INVOICE",
          "checkStepNumber": 2,
          "amount": 0,
          "invoiceRef": null,
          "downloadedDateOnMobile": null,
          "lowInvoiceExplanationEnum": null,
          "explanationForLowValueText": null,
          "documentSet": [
            {"INVOICE": false}
          ]
        },
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.Signature",
          "type": "SIGNATURE",
          "active": false,
          "checkStepNumber": 3,
          "name": null,
          "relation": null,
          "hash": null
        }
      ]
    },
    {
      "typeEnum": "TO",
      "stepNumber": 1,
      "active": false,
      "address": "64 Boulevard Haussmann, 75008 Paris, France",
      "arrivalDateTime": "2017-07-03T16:25:00.000Z",
      "departureDateTime": "2017-07-03T16:35:00.000Z",
      "estimatedWaitInMinutes": 10,
      "type": "CUSTOMER",
      "concession": null,
      "checkStepList": [
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.Identity",
          "type": "IDENTITY",
          "checkStepNumber": 0,
          "transferAlone": false,
          "gender": null,
          "firstName": null,
          "lastName": null,
          "phoneNumber": null,
          "email": null,
          "registrationCardAvailable": false,
          "insuranceCertificateAvailable": false,
          "insuranceVisibleCard": false,
          "car": {
            "type": "VC",
            "brand": "Citroën",
            "model": "C3",
            "color": "ROUGE",
            "plateNumber": "AA111AA",
            "serialNumber": "82155555",
            "display": ""
          },
          "documentSet": [
            "CAR_REGISTRATION",
            "CAR_INSURANCE_CERTIFICATE"
          ]
        },
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.StateCar",
          "type": "STATE_CAR",
          "checkStepNumber": 2,
          "fuelQuantity": 0,
          "mileage": 0,
          "spareWheel": false,
          "antiTheftNut": false,
          "antiTheftNutExplanation": null,
          "stateCarProblemSet": [
            {
              "photo": "ROOF",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "HOOD",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "WINDSCREEN_FRONT",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "WINDSCREEN_BACK",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BUMPER_FRONT",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BUMPER_BACK",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_LEFT_DOOR",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_RIGHT_DOOR",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_LEFT_DOOR",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_RIGHT_DOOR",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_LEFT_FENDER",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_RIGHT_FENDER",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_LEFT_FENDER",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_RIGHT_FENDER",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_LEFT_WHEEL",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "BACK_RIGHT_WHEEL",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_LEFT_WHEEL",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "FRONT_RIGHT_WHEEL",
              "driverExplanation": null,
              "explanation": null
            },
            {
              "photo": "SPARE_WHEEL",
              "driverExplanation": null,
              "explanation": null
            }
          ],
          "stateCarProblemAloneSet": null
        },
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.Invoice",
          "type": "INVOICE",
          "checkStepNumber": 3,
          "amount": 0,
          "invoiceRef": null,
          "downloadedDateOnMobile": null,
          "lowInvoiceExplanationEnum": null,
          "explanationForLowValueText": null,
          "documentSet": [
            "INVOICE"
          ]
        },
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.Payment",
          "type": "PAYMENT",
          "checkStepNumber": 3,
          "active": false,
          "amount": 0,
          "invoiceRef": null,
          "cashTypeEnum": null,
          "paymentRef": null,
          "isPayed": false
        },
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.DriverEvaluation",
          "type": "DRIVER_EVALUATION",
          "checkStepNumber": 5,
          "punctuality": 0,
          "professionalism": 0,
          "carIntroduction": 0,
          "generalImpression": 0,
          "comment": null,
          "canBeContact": false
        },
        {
          "javaType": "fr.driverV2.domain.step.checkSteps.Signature",
          "type": "SIGNATURE",
          "checkStepNumber": 6,
          "name": null,
          "relation": null,
          "hash": null
        }
      ]
    }
    ],
    "coordinatesList": []
    }
)

this is what my data look likes (as you see its really deep).
the purpose is a bit hard to get, so i will fully explain my case here.

stepDtoSet are top pages, only one stepDtoSet is active at the time.
checkStepList is a child of stepDtoSet and represent a set of pages, its where i need to handle changes.

as only one stepDtoSet need to be available at the time, im using router.bookmark to do the navigation between stepDtoSet (navigation only go forward) all seems to work pretty well. now i need to pass my checkStepList into an each to get all child page together

i’m getting my checkStepList this way. line 467 to 476 of pageMain.js

var stepDtoSet = data.map(function(x){
  return _.first(x.stepDtoSet)
})

var checkStepList = stepDtoSet.map(function(x){return x.checkStepList}).expand()

is this checkStepList that i’m passing into my each method in my pageMain.ux, line 42.

each object of my checkStepList represent a page, that need to be verify individually before moving to the next checkStepList page.
this is how i’m affecting each data of each page inside my checkStepList depending on type.

can be found starting the line 721

var zad = checkStepList.map(function(w){
  if(w.type == "IDENTITY"){
    IDENTITY.value = w
  }else if (w.type == "DISCLAIMER"){
    DISCLAIMER.value = w
  }else if (w.type == "ORDER_OF_REPAIR"){
    ORDER_OF_REPAIR.value = w
  }else if (w.type == "RENTAL_CONTRACT"){
    RENTAL_CONTRACT.value = w
  }else if (w.type == "DRIVING_LICENCE"){
    DRIVING_LICENCE.value = w
  }else if(w.type == "CHECK_LIST_CLIENT"){
    CHECK_LIST_CLIENT.value = w
  }else if(w.type == "STATE_CAR"){
    STATE_CAR.value = w
  }else if(w.type == "INVOICE"){
    INVOICE.value = w
  }else if (w.type == "CONCESSION_DOC_VALIDATION"){
    CONCESSION_DOC_VALIDATION.value = w
  }else if (w.type == "CUSTOMER_DOC_VALIDATION"){
    CUSTOMER_DOC_VALIDATION.value = w
  }else if(w.type == "SIGNATURE"){
    SIGNATURE.value = w
  }
})

next i’m mapping each value depending on type pages , to put them inside my Each method in the pageMain.ux
all seems to work well , i can handle change easily like that , but , is it safe ?

Hi prince,

working with huge/deep nested objects usually hints at bad design. While you clearly can make it work, it will become unmaintainable in the long run.

If I were you, I would instead write several models that have methods on them, and get/set things via exported interfaces. As a result, you would interact with objects that have member functions that allows you to manipulate those objects; as opposed to digging in a huge dataset.

Here’s an example on how a very simple data model could look like:

var Observable = require("FuseJS/Observable");
var data = Observable();

var Step = function(type) {
    this.type = type;
    this.something = Observable("");
    var self = this;
    this.setSomething = function(thing) {
        switch (self.type) {
            case "IDENTITY":
                self.something = thing;
                break;
            // ...
            default:
                console.log("unknown step type: " + self.type);
                break;
        }
    }
}

data.add(new Step("IDENTITY"));
data.add(new Step("1337"));

data.forEach(function(item) {
    item.setSomething("Fuse");
});

module.exports = {
    data: data
};

If you put that in a stand-alone JS file that you require() from other models and viewmodels, you immediately get access to its’ data, like so:

var Thing = require("Modules/Thing.js");
// Thing.data is the observable list
module.exports = {
    dataFromThing: Thing.data
};

Note that you can even call the setSomething function on all Step objects if you put them in an Each, straight from UX markup:

<Each Items="{dataFromThing}">
    <Panel Clicked="{setSomething}" />
        <!-- things that define how a Step looks like go here -->
    </Panel>
</Each>

And if you proceed to build nested models that interact, that will be far more maintainable in the long run rather than a huge nested data object. Plus, you get to decide what needs to be Observable on each level, and what can stay simple types - strings, booleans etc.

Hope this helps!

Great answer, thank you uldis, will test that.