简体   繁体   中英

Create knockout computed with Underscore.js groupBy & map for select control

I am trying to create a partial view that will display a select control with grouped options.

I have an initial bit of JSON:

[{
    "customFrequencyId": 1008,
    "startDate": "2016-10-29T00:00:00Z",
    "endDate": "2016-11-25T00:00:00Z",
    "label": "P11 2016"
}, {
    "customFrequencyId": 1008,
    "startDate": "2016-11-26T00:00:00Z",
    "endDate": "2016-12-31T00:00:00Z",
    "label": "P12 2016"
}, {
    "customFrequencyId": 1008,
    "startDate": "2017-01-01T00:00:00Z",
    "endDate": "2017-01-28T00:00:00Z",
    "label": "P1 2017"
}, {
    "customFrequencyId": 1008,
    "startDate": "2017-01-29T00:00:00Z",
    "endDate": "2017-02-25T00:00:00Z",
    "label": "P2 2017"
}, {
    "customFrequencyId": 1008,
    "startDate": "2017-02-26T00:00:00Z",
    "endDate": "2017-03-23T00:00:00Z",
    "label": "P3 2017"
}]

My current TypeScript:

export class CustomPeriodSelection {

    customPeriods: KnockoutObservable<any[]> = ko.observable([]);
    selectedOption: KnockoutObservable<any> = ko.observable();

    customGroups: KnockoutComputed<any[]> = ko.computed(() => {
        var groupedList = _.groupBy(this.customPeriods(), function (item: any) {
            return item.endDate.substring(0, 4);
        });

        return _.map(groupedList, function (item: any) {
            return item;
        });
    });

    constructor(
        customPeriods: any[]
    ) {
        this.customPeriods(customPeriods);
    }
}

My intention is to end up with the following JSON from the Knockout computed...

[{
    "label": 2016,
    "customPeriods": [{
        "customFrequencyId": 1008,
        "startDate": "2016-10-29T00:00:00Z",
        "endDate": "2016-11-25T00:00:00Z",
        "label": "P11 2016"
    }, {
        "customFrequencyId": 1008,
        "startDate": "2016-11-26T00:00:00Z",
        "endDate": "2016-12-31T00:00:00Z",
        "label": "P12 2016"
    }]
}, {
    "label": 2017,
    "customPeriods": [{
        "customFrequencyId": 1008,
        "startDate": "2017-01-01T00:00:00Z",
        "endDate": "2017-01-28T00:00:00Z",
        "label": "P1 2017"
    }, {
        "customFrequencyId": 1008,
        "startDate": "2017-01-29T00:00:00Z",
        "endDate": "2017-02-25T00:00:00Z",
        "label": "P2 2017"
    }, {
        "customFrequencyId": 1008,
        "startDate": "2017-02-26T00:00:00Z",
        "endDate": "2017-03-23T00:00:00Z",
        "label": "P3 2017"
    }]
}]

Which will then be put to the select control like this..

<select class="form-control" data-bind="foreach: customGroups, event: { change: periodChanged }">
    <optgroup data-bind="attr: { label: $data.label}, foreach: customPeriods">
        <option data-bind="text: $data.label, value: $data"></option>
    </optgroup>
</select>

I'm assuming it is the implementation of groupBy & map that are incorrect. How do I group the customPeriods array by year, and then map the result to a new array with the required structure above?

I currently get the following from the code I have written.

[
  [
    {
      "customFrequencyId": 1008,
      "startDate": "2016-10-29T00:00:00Z",
      "endDate": "2016-11-25T00:00:00Z",
      "label": "P11 2016"
    },
    {
      "customFrequencyId": 1008,
      "startDate": "2016-11-26T00:00:00Z",
      "endDate": "2016-12-31T00:00:00Z",
      "label": "P12 2016"
    }
  ],
  [
    {
      "customFrequencyId": 1008,
      "startDate": "2017-01-01T00:00:00Z",
      "endDate": "2017-01-28T00:00:00Z",
      "label": "P1 2017"
    },
    {
      "customFrequencyId": 1008,
      "startDate": "2017-01-29T00:00:00Z",
      "endDate": "2017-02-25T00:00:00Z",
      "label": "P2 2017"
    },
    {
      "customFrequencyId": 1008,
      "startDate": "2017-02-26T00:00:00Z",
      "endDate": "2017-03-23T00:00:00Z",
      "label": "P3 2017"
    }
  ]
]

I have read other questions but I'm struggling. Any help would be greatly appreciated (with an explanation if possible as opposed to just doing it for me). Thanks!

You're close.

Change:

return _.map(groupedList, function (item: any) {
            return item;
        });

to

return _.map(groupedList, function (item: any) {
            return { label: item[0].endDate.substring(0, 4), customPeriods: item };
        });

Though I'd like to verify this in a plunker first.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM