Search code examples
templatesobjectdatatemplatejsrenderjsviews

Is there a versatile engine to translate JavaScript object into a different object?


I'm looking for a versatile way to translate a big object into a custom object using a template. It should be able to traverse each value of arrays, and reference parent values in the loop.

Imagine an object like:

{
    collectionId : 432,
    products : [
        {
            productId : 1155,
            suppliers : [
                {
                    supplierId : 252,
                    supplier : 'SupplyCompany',
                    shipments : [
                        {
                            date : 'foo',
                            order : 'bar',
                            id : 45
                        },
                        {},
                        {},
                        //...
                    ]
                },
                {},
                {},
                //...
            ]
        },
        {},
        {},
        //...
    ],
}

I would for example want to flatten this into:

[
    {
        collectionId : 432,
        productId : 1155,
        supplierId : 252,
        supplier : 'SupplyCompany',
        date : 'foo',
        order : 'bar',
        id : 45
    },
    {},
    {},
    //...
]

Right now I'm using manual for for for loops, but this isn't very versatile when the source object changes or one of my output objects change. It's not very maintainable to 'hardcode' these translations.

There are templating engines that do something resembling what I want, e.g. JsRender. It theoretically allows you to do what I need:

{{for products}}
    {{for suppliers}}
        {{for shipments}}
            collectionId : {{:#parent.parent.parent.parent.data.collectionId}}
            productId : {{:#parent.parent.parent.data.productId}},
            supplierId : {{:#parent.parent.data.supplierId}},
            supplier : {{:#parent.parent.data.supplier}},
            date : {{:date}},
            order : {{:order}},
            id : {{:id}
        {{/for}}
    {{/for}}
{{/for}}

(This is pretty nice because Mustache doesn't allow you to do this.)

However, jsRender reads strings (templates) and output strings (html). The overhead from all the stringify and parse is not doing any good in my case.

I'm looking for something that does this kind of processing with objects. From objects to objects.


Solution

  • There are a few ways you can do that kind of thing using JsRender. For example it is really easy to create custom tags, converters, etc. (or use helper functions) and make them have side effects of mapping objects to some output object. Of course the philosophy of JsRender is generally to be declarative, without side effects, but if you want to you can indeed use it a 'processor'.

    Here is a jsfiddle sample which can give you some ideas:

    It uses a custom tag:

    $.views.tags({
      addObject: function(target) {
        var item = $.extend({}, this.tagCtx.props);
        target.push(item);
        ...
      }
    })
    

    and a template:

    {{for products ~collectionId=collectionId}}
        {{for suppliers ~productId=productId}}
            {{for shipments ~supplierId=supplierId ~supplier=supplier}}
                {{addObject ~target collectionId=~collectionId productId=~productId supplierId=~supplierId supplier=~supplier date=date order=order id=id/}}
            {{/for}}
        {{/for}}
    {{/for}}