How to assigned $index() to a nested object Array Property?

75 views
Skip to first unread message

Robbie Andersen

unread,
May 10, 2021, 12:25:30 AM5/10/21
to KnockoutJS

I am making a dynamic form builder using knockout components in asp net.
I have managed to get everything working how I want it however 1 bit of data I want to return to the controller level is giving me some trouble.

There are two types of forms the user can generate so far; Text Fields and Select Fields (Dropdown). The select field has children which I call options that can be of any size. The dropdown object array  looks something like:

{
    Id: id,
    Type: 1,
    SortOrder: 0,
    Question: "",
    Tip: "",
    Options: [{
        ParentIndex: id,
        SortOrder: 0,
        Text: ""
    }]
}

As you can see there are two properties called SortOrder. One to sort the field itself and one to sort the options in the dropdown. To assign the select field it's sort order I simply assign the SortOrder property with it's index when the save button is clicked:

<input hidden data-bind="value: $this.fieldsList()[$index()].SortOrder, text: $index()" />

This works perfectly and returns the correct sort order. However when trying to execute a similar technique for the nested options I only ever return it's default value of 0:

<input data-bind="value: $this.fieldsList()[$parent.ParentIndex].Options[$index()].SortOrder, text: $index()" />

The funny thing it that both the value and text parameter are valid respectively. But when trying to assign the index to the nested SortOrder property It only takes it's current assigned value unlike the parents that use the same technique. It's almost as if the most right parameter is completely ignored which doesn't make sense to me.

Is there anything I am missing? Or is this some kind of limitation or bug with ko js? I can achieve proper SortOrder with plain js however I would prefer to do it this way as it seems to be less prone to bugs and generally seems cleaner then pure js. Cheers.

Robbie Andersen

unread,
May 10, 2021, 1:42:31 AM5/10/21
to KnockoutJS
I have used plain js to deal with the SortOrder

$this.removeOption = function (index, parentIndex) {
        if (index < $this.fieldsList()[parentIndex].Options.length - 1) {
            for (var i = index + 1; i < $this.fieldsList()[parentIndex].Options.length; i++) {
                $this.fieldsList()[parentIndex].Options[i].SortOrder = i - 1;  
            }
        }

        $this.fieldsList()[parentIndex].Options.splice(index, 1);
        $this.fieldsList.valueHasMutated();
}

$this.downSortOption = function (index, parentIndex) {
        $this.fieldsList()[parentIndex].Options[index].SortOrder = $this.fieldsList()[parentIndex].Options[index].SortOrder + 1;
        $this.fieldsList()[parentIndex].Options[index + 1].SortOrder = $this.fieldsList()[parentIndex].Options[index + 1].SortOrder - 1;

        let temp = $this.fieldsList()[parentIndex].Options[index];
        $this.fieldsList()[parentIndex].Options[index] = $this.fieldsList()[parentIndex].Options[index + 1];
        $this.fieldsList()[parentIndex].Options[index + 1] = temp;
        $this.fieldsList.valueHasMutated();
}

$this.upSortOption = function (index, parentIndex) {
        $this.fieldsList()[parentIndex].Options[index].SortOrder = $this.fieldsList()[parentIndex].Options[index].SortOrder - 1;
        $this.fieldsList()[parentIndex].Options[index - 1].SortOrder = $this.fieldsList()[parentIndex].Options[index - 1].SortOrder + 1;

        let temp = $this.fieldsList()[parentIndex].Options[index];
        $this.fieldsList()[parentIndex].Options[index] = $this.fieldsList()[parentIndex].Options[index - 1];
        $this.fieldsList()[parentIndex].Options[index - 1] = temp;
        $this.fieldsList.valueHasMutated();
}

As you can see I do a bunch of index and value switching to make sure the data is correct. Index out of range is not possible as the buttons to sort options is disabled if it's index is min or max.

However I am still curious why my hidden input data-bind didn't work when capturing the options index. Cheers.

Sylvain Garden

unread,
May 17, 2021, 6:48:07 AM5/17/21
to KnockoutJS
value and text are not designed to work together. You can't define the read-only value of an input by the text binding and in the same time saying that this input value has to be bound (read and write) with a model. I'm even surprised that "text" works with input tags. So it might have work in some scenario by pure luck.

The best approach for such a not trivial model change is a read/write computed to use as the input value.
Reply all
Reply to author
Forward
0 new messages