Search code examples
javascripttypescriptknockout.jsknockout-3.0

Dynamically created selects don't bind to their observable values?


I dynamically create selects in knockout like this:

<h5 data-bind="visible: selectedChildren() > 0">@Model.SelectChildrenAge</h5>
  <input type="hidden" name="ac1" data-bind="value: selectedChildrenAgesCsv()"/>
  <div class="children-age-container__ages" data-bind="foreach: childrenAges">
       <select class="children-age-container__ages--select" data-bind="options: $data, optionsCaption: 'Age', value: $parent.selectedChildrenAges[$index]"></select>
   </div>

In my model I an observableArray that I want the dynamically created select value to bind to:

selectedChildrenAges: KnockoutObservableArray<number> = ko.observableArray([
        0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0
    ]);

However, it seems like they are always 0 even if the actual creating of the selects works like a charm. The issue here is I don't actually want to post whats in the select boxes as is, the backend require me to post it as a CSV string. What I've done is create a subscribe method that will update selectedChildrenAgesCsv accordingly:

this.selectedChildrenAges.subscribe(() => {
            console.log((this.selectedChildrenAges as any).join(", "));
            this.selectedChildrenAgesCsv((this.selectedChildrenAges as any).filter(age => age > 0).join(","));

My console log never outputs anything here, and I'm kinda lost in how to face it. I have tried so many different ways but nothing seems to work good.


Solution

  • The selectedChildrenAges is an observable array. To get it's content you should use ():

    this.selectedChildrenAges.subscribe(() => {
                console.log((this.selectedChildrenAges() as any).join(", "));
                this.selectedChildrenAgesCsv((this.selectedChildrenAges() as any).filter(age => age > 0).join(","));
    });
    

    or use newValue that is coming as argument in the subsription handler function:

    this.selectedChildrenAges.subscribe((newValue: Array<number>) => {
                console.log(newValue.join(", "));
                this.selectedChildrenAgesCsv(newValue.filter(age => age > 0).join(","));
    });
    

    Or you can use computed:

    this.selectedChildrenAgesCsv = ko.computed<string>(() => {
        return this.selectedChildrenAges().filter(age => age > 0).join(",");
    });