敲除计算和订阅的意外行为

时间:2016-01-26 08:03:00

标签: knockout.js

我有以下数据结构

[{
    "name": "root1",
    "ecomCategories": [{
      "name": "sub11"
    }, {
      "name": "sub12",
      "ecomCategories": null
    }, {
      "name": "sub13",
      "ecomCategories": null
    }]
  }, {
    "name": "root2",
    "ecomCategories": [{
      "name": "sub21",
      "ecomCategories": null
    }]
  }] 

现在我想显示在选择根类别时会发生变化的下拉菜单: 请看这个小提琴 - jsfiddle

但是如果我正在更新订阅函数中的任何observable,那么它的更改将反映在父可观察

在小提琴中重现此问题的步骤:

  1. 选择根类别" root1"它将有3个子类别sub11,sub12,sub13

  2. 选择任何子类别,即sub11

  3. 选择根类别" root2"

  4. 再次选择根类别" root1" 现在您将看到子类别中只有一个子类别下拉,因为它应该有3个子类别

  5. 
    
    // Here's my data model
    var ViewModel = function() {
      this.rootCategory = ko.observableArray([{
        "name": "root1",
        "ecomCategories": [{
          "name": "sub11"
        }, {
          "name": "sub12",
          "ecomCategories": null
        }, {
          "name": "sub13",
          "ecomCategories": null
        }]
      }, {
        "name": "root2",
        "ecomCategories": [{
          "name": "sub21",
          "ecomCategories": null
        }]
      }]);
      this.newObjectToSave = ko.observable();
      this.selectedCategory = ko.observable();
      this.selectedSubCategory = ko.observable();
    
      var that = this;
      //subscribers  
      this.selectedCategory.extend({
        notify: 'always'
      });
      this.selectedCategory.subscribe(function(newVal) {
    
        if (newVal != undefined) {
          that.newObjectToSave(newVal);
          // newObjectToSave().ecomCategories = [];
        }
    
      });
    
      this.selectedSubCategory.extend({
        notify: 'always'
      });
      this.selectedSubCategory.subscribe(function(subCat) {
    
        if (subCat != undefined) {
          that.newObjectToSave().ecomCategories = [subCat];
          that.newObjectToSave(that.newObjectToSave().ecomCategories[0]);
        }
    
      });
    
    
    
    
    
      //computed 
      this.subCategories = ko.computed(function() {
        if (this.selectedCategory() != undefined) {
          return this.selectedCategory().ecomCategories;
        } else {
          return "";
        }
    
      }, this);
    
    
    
    
    
    };
    
    ko.applyBindings(new ViewModel()); // This makes Knockout get to work
    
    .paddingTop15 {
      padding-top: 15px;
    }
    .browseCategory select {
      -webkit-appearance: none;
      /*Removes default chrome and safari style*/
      -moz-appearance: none;
      /* Removes Default Firefox style*/
    }
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <div class="container">
      <div class="row paddingTop15">
        <div class="col-lg-2">
          Select Root Category:
          <br>
          <div class="btn-group btn-group-sm browseCategory">
            <select class="btn btn-default" data-bind="options: rootCategory,
    	                       optionsText: 'name',
    	                       value: selectedCategory,
    	                       optionsCaption: 'Select Category'"></select>
          </div>
        </div>
      </div>
    
      <div class="row paddingTop15">
    
        <div class="col-lg-2">
          Select SubCategory:
          <br>
          <div class="btn-group btn-group-sm browseCategory">
            <select class="btn btn-default" data-bind="options: subCategories,
    	                       optionsText: 'name',
    	                       value: selectedSubCategory,
    	                       optionsCaption: 'Select Sub Category'"></select>
          </div>
        </div>
    
    
    
      </div>
    </div>
    &#13;
    &#13;
    &#13;

    为什么更新&#34; newObjectToSave&#34;正在更新&#34; selectedCategory&#34;价值???

1 个答案:

答案 0 :(得分:0)

您正面临的问题正在发生,因为您通过引用<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <MediaElement x:Name="playMedia" AutoPlay="True"/> <StackPanel> <Slider Name="slider" Margin="50,0" Value="{Binding Position, ElementName=playMedia, Converter={StaticResource TimeSpanToTicksConverter}, Mode=TwoWay}" Maximum="{Binding NaturalDuration.TimeSpan, ElementName=playMedia, Converter={StaticResource TimeSpanToTicksConverter}, Mode=OneWay}" /> <Button Name="btnNewSong" Content="New Song" HorizontalAlignment="Center" Margin="0,50,0,0" Click="btnNewSong_Click"/> </StackPanel> </Grid> 传递<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <MediaElement x:Name="playMedia" AutoPlay="True"/> <StackPanel> <Slider Name="slider" Margin="50,0" Value="{x:Bind playMedia.Position, Converter={StaticResource TimeSpanToTicksConverter}, Mode=TwoWay}" Maximum="{x:Bind playMedia.NaturalDuration.TimeSpan, Converter={StaticResource TimeSpanToTicksConverter}, Mode=OneWay}" /> <Button Name="btnNewSong" Content="New Song" HorizontalAlignment="Center" Margin="0,50,0,0" Click="btnNewSong_Click"/> </StackPanel> </Grid> 。那时 private async void btnNewSong_Click(object sender, RoutedEventArgs e) { FileOpenPicker openPicker = new FileOpenPicker(); openPicker.ViewMode = PickerViewMode.Thumbnail; openPicker.SuggestedStartLocation = PickerLocationId.MusicLibrary; openPicker.FileTypeFilter.Add(".wav"); openPicker.FileTypeFilter.Add(".mp3"); openPicker.FileTypeFilter.Add(".m4a"); StorageFile storageFile = await openPicker.PickSingleFileAsync(); if (storageFile != null) { var contentType = storageFile.ContentType; playMedia.SetSource(await storageFile.OpenAsync(FileAccessMode.Read), contentType); playMedia.Play(); } } 可观察的值链接到public class TimeSpanToTicksConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { TimeSpan ts = (TimeSpan)value; double result = System.Convert.ToDouble(ts.Ticks); return result; } public object ConvertBack(object value, Type targetType, object parameter, string language) { double ticks = (double)value; TimeSpan ts = new TimeSpan(System.Convert.ToInt64(ticks)); return ts; } }

中的一个选定元素
newVal

...然后在引用的值上修改ecomCategories,导致选项修改:

newObjectToSave

解决方案:我建议深度复制newVal对象,以便在之后修改它时不会将其链接到原始值:

newObjectToSave

工作fiddle