当一个文件中的值用作另一个文件的参数时,如何将多个 JSON 文件传递​​给 Observable 数组?

How to pass multiple JSON file to Onservable Arrays when value in one file is used as argument for another file?

我正在尝试使用 $.getJSON 调用两个 json 文件并将它们的值分配给 observableArrays:目前 JSON 数据被硬编码到 observableArrayExample fiddle here.

我试图这样做:

        self.CountryData = ko.observableArray([]);
        self.CountryDetailData = ko.observableArray([]);

        $.when( $.getJSON( 'country.json' ), $.getJSON( 'country-detail.json' ))
.done(function( country, countryDetail ) {

            self.CountryData(country[0]);
            self.CountryDetailData(countryDetail[0]);
});

接下来,我尝试合并两个文件:

var data = country[0].concat(countryDetail[0]);

最后,出于实验目的,我简单地通过简单地从一个文件中获取值并将其放入另一个文件来手动合并两个文件,但没有给我预期的结果。

这是使用硬编码 JSON 数据的工作 JS Fiddle.

如何调用 JSON 文件并分配给可观察对象,而不是硬编码 JSON 数据?

我无法使这部分代码工作:

self.CountryDetails = function (country) {
            var data = ko.computed(function () {

                return ko.utils.arrayFilter(self.CountryDetailData(), function (item) {
                    return item.CountryId === country.CountryId;
                });
            });

            self.CountryId(data()[0].CountryId);
            self.Location(data()[0].Location);
            self.Coordinates(data()[0].Coordinates);
            self.Coastline(data()[0].Coastline);
            self.Climate(data()[0].Climate);
            self.Terrain(data()[0].Terrain);
        }

错误:Message: CountryId is not defined;

更新:

我决定应用一种本地方法,这样我就可以从 table 中获取 CountryID 并作为参数传递:我还将 $.getJSON 放在它所在的函数中被使用以便在执行时结果可用:

代码:

self.CountryDetails = function (country) {

$.getJSON( 'country-detail.json')
.done(function( result ) {

  self.CountryDetailData(result);

  var data = ko.computed(function () {

      return ko.utils.arrayFilter(self.CountryDetailData(), function (item) {

         // get CountryId from view
          var cId = $('#country-list tbody tr:first-child td:first-child').html();

      /*  Because I am unable to get ID on page load, I am doing a work-around.
          If the country parameter is undefine then use the alternative method to
          get the countryId from the first row or and first cell. */
          currentId = (country === undefined ? cId : country.CountryId);

          return item.CountryId ===  currentId;

      });
  });

  self.CountryId(data()[0].CountryId);
  self.Location(data()[0].Location);
  self.Coordinates(data()[0].Coordinates);
  self.Coastline(data()[0].Coastline);
  self.Climate(data()[0].Climate);
  self.Terrain(data()[0].Terrain);

});
}

现在我可以使用 JSON 文件并加载附加数据,就像 JSON 值被硬编码时一样。

你基本上想要一个 CountrySelector,它有一个大洲和国家的列表,并提供先选择大洲然后再根据大洲选择国家的功能。

为简单起见,我们删除所有 Ajax 并将其简化为一个纯粹的、以数据为中心的模型:

function CountrySelector(data) {
    var self = this;

    // base data
    self.countries = ko.observableArray(data.countries);
    self.continents = ko.observableArray(data.continents);

    // state data
    self.selectedContinent = ko.observable();
    self.selectedCountry = ko.observable();
    self.selectedCountryDetails = ko.observable();
    self.filteredCountries = ko.computed(function () {
        var selectedContinent = self.selectedContinent();
        return ko.utils.arrayFilter(self.countries(), function (country) {
            return selectedContinent && country.Continent === selectedContinent;
        });
    });

    // subscriptions
    self.filteredCountries.subscribe(function (countries) {
        self.selectedCountry(countries[0]);
    });
    self.selectedCountry.subscribe(function (country) {
        var selectedDetails = ko.utils.arrayFirst(data.details, function (details) {
            return details.CountryId === country.CountryId;
        });
        self.selectedCountryDetails(selectedDetails);
    });

    // state init
    self.selectedContinent(self.continents[0]);
}

这需要用数据对象初始化:

{
    continents: [/* ... list of continent names ... */],
    countries: [/* ... list of country objects ... */],
    details: [/* ... list of country detail objects ... */],  
}

现在你有一些独立于种类数据源的东西(你可以用硬编码数据初始化它,来自localStorage,来自另一个视图模型,通过Ajax, 随便).


要通过 Ajax 初始化它,我们发送两个请求:

var countryReq = $.getJSON('country.json');
var countryDetailReq = $.getJSON('country-detail.json');

等待他们并将数据整理成形状(jQuery 的 .then() 在这里派上用场):

var combinedData = $.when(countryReq, countryDetailReq).then(function (countries, details) {
    // figure out disintct continent names
    var continents = ko.utils.arrayMap(countries, function (country) {
            return country.Continent;
        });
    continents = ko.utils.arrayGetDistinctValues(continents);
    continents.sort();

    // assemble the data the viewmodel expects
    return {
        countries: countries,
        continents: continents,
        details: details
    };
});

一旦完成,我们就可以应用绑定:

combinedData.done(function (data) {
    ko.applyBindings( new CountrySelector(data) );
});

进入这样的视图:

<ul data-bind="with: selectedCountryDetails">
    <li>CountryId: <span data-bind="text: CountryId"></span></li>
    <li>Location: <span data-bind="text: Location"></span></li>
    <li>Coordinates: <span data-bind="text: Coordinates"></span></li>
    <li>Coastline: <span data-bind="text: Coastline"></span></li>
    <li>Climate: <span data-bind="text: Climate"></span></li>
    <li>Terrain: <span data-bind="text: Terrain"></span></li>
</ul>

<div id="country-select">
    <select data-bind="options: continents, value: selectedContinent"></select>
</div>

<table id="country-list">
    <thead>
        <tr>
            <th>CountryID</th>
            <th>Country Name</th>
            <th>City</th>
            <th>Continent</th>
            <th>CountryAbbr</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: filteredCountries">
        <tr data-bind="
            click: $root.selectedCountry,
            clickBubble: false,
            css: {
                active: CountryId === $root.selectedCountry().CountryId
            }
        ">
            <td data-bind="text: CountryId"></td>
            <td data-bind="text: Country"></td>
            <td data-bind="text: City"></td>
            <td data-bind="text: Continent"></td>
            <td data-bind="text: CountryAbbr"></td>
        </tr>
    </tbody>
</table>