javascriptmongodbmeteormeteor-blaze

Blaze template, loop through fields?


I have been unable to find reference to any shortcut that might be available to loop through fields that are named "week01", "week02", "week03" where I could reference the field which is an object containing child fields in the same structure.

I know of #each for each document but don't know how to go about each field. I have 30 week fields and would like to loop over the fields, then reference the object properties too.

Can anyone give me a hint or an online resource that might help me? I am a VB/php developer, developing my first Meteor app, and working with Mongo for the first time. Hoping I am missing something that is possible.

    "personId": "rY7XaJJkrdAWaByQK",
    "week01": {
        "date": {
            "$date": "2021-04-07T12:00:00.000Z"
        },
        "field1": "chunks as necessary",
        "field2": "readable English",
        "field3": "Contrary to popular belief"
    },
    "week02": {
        "date": {
            "$date": "2021-04-14T12:00:00.000Z"
        },
        "field1": "consectetur, from",
        "field2": "more recently with desktop",
        "field3": "Contrary to popular belief"
    },
    "week03": {
        "date": {
            "$date": "2021-04-21T12:00:00.000Z"
        },
        "field1": "going through",
        "field2": "readable English",
        "field3": "Contrary to popular belief"
    },
    "week04": {
        "date": {
            "$date": "2021-04-28T12:00:00.000Z"
        },
        "field1": "words which don't look",
        "field2": "sure there isn't",
        "field3": "Contrary to popular belief"
    },
    "week05": {
        "date": {
            "$date": "2021-05-05T12:00:00.000Z"
        },
        "field1": "only five centuries",
        "field2": "Where can I get some",
        "field3": "infancy. Various"
    }
} ```

Solution

  • #each accetps only arrays or cursors, so you need to extract an Array from your Object.

    In JavaScript you can generate an array from the fields (properties) of an Object (which is your document) and filter them to contain only those that contain week in their property name (key). You can then return them via helper:

    const document = {
       "personId": "rY7XaJJkrdAWaByQK",
        "week01": {
            "date": {
                "$date": "2021-04-07T12:00:00.000Z"
            },
            "field1": "chunks as necessary",
            "field2": "readable English",
            "field3": "Contrary to popular belief"
        },
        "week02": {
            "date": {
                "$date": "2021-04-14T12:00:00.000Z"
            },
            "field1": "consectetur, from",
            "field2": "more recently with desktop",
            "field3": "Contrary to popular belief"
        },
        "week03": {
            "date": {
                "$date": "2021-04-21T12:00:00.000Z"
            },
            "field1": "going through",
            "field2": "readable English",
            "field3": "Contrary to popular belief"
        },
        "week04": {
            "date": {
                "$date": "2021-04-28T12:00:00.000Z"
            },
            "field1": "words which don't look",
            "field2": "sure there isn't",
            "field3": "Contrary to popular belief"
        },
        "week05": {
            "date": {
                "$date": "2021-05-05T12:00:00.000Z"
            },
            "field1": "only five centuries",
            "field2": "Where can I get some",
            "field3": "infancy. Various"
        }
    }
    
    const weeks = Object.entries(document) // will be an array of key/value pairs
      .filter(([key, value]) => key.includes('week')) // only use week fields
      .map(([key, value]) => value) // only use the value
    
    Template.helpers({
      allWeeks () {
        return weeks
      }
    })
    
    

    You can then iterate over it via {{#each week in allWeeks}}.

    Note: This is a bit imperformant, because on every redraw it will run the above code. You will introduce a ReactiveVar or ReactiveDict and save the week in there and return the value from this reactive source:

    const state = new ReactiveDict()
    const weeks = Object.entries(document) // will be an array of key/value pairs
      .filter(([key, value]) => key.includes('week')) // only use week fields
      .map(([key, value]) => value) // only use the value
    
    state.set({ weeks })
    
    
    Template.helpers({
      allWeeks () {
        return state.get('weeks')
      }
    })
    

    Readings:

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

    https://docs.meteor.com/api/reactive-dict.html