【问题标题】:How Can I change jQuery data handling to Knockout bindings for openWeather API如何将 jQuery 数据处理更改为 openWeather API 的 Knockout 绑定
【发布时间】:2018-07-30 16:51:38
【问题描述】:

我想使用 Knockout 数据绑定来更新我的 html div 元素中的天气 API 数据。目前,我正在使用 jQuery 来更新 DOM,但我更喜欢使用 Knockout。我还想动态更改位置 zip,以便天气特定于我的 div 中的那个位置。我有一个位置数组。

这是我的代码: html:

var zip = locations[0].zipcode;
var myOpenWeatherAPIKey = 'xxxxxxxxxxxxxxxxxxxx';
var openWeatherMapUrl = "http://api.openweathermap.org/data/2.5/weather?zip=" + zip + ",us&APPID=" + myOpenWeatherAPIKey + "&units=imperial";
console.log(zip);
//using JSON method for retrieving API data
$.getJSON(openWeatherMapUrl, function(data) {
    var parameters = $(".weather-data ul");
    var iconCode = data.weather[0].icon;
    var iconDescription = data.weather[0].main;
    var iconUrl = "http://openweathermap.org/img/w/" + iconCode + ".png";
    detail = data.main;
    windspd = data.wind;
    parameters.append('<li>Temp: ' + Math.round(detail.temp) + '° F <br></li>');
    parameters.append('<li><img style="width: 25px" src="' + iconUrl + '">  ' + iconDescription + '</li>');
}).fail(weatherError = function(e) {
    $(".weather-data").append("OpenWeatherAPI is unable to load!");
});
<div id="open-weather" class="open-weather">
    <div id="weather-data" class="weather-data">
        <p>  <br> Current Weather</p>
        <ul id="weather-items" class="weather-items">
        </ul>
    </div>
</div>

谢谢,

【问题讨论】:

    标签: json api knockout.js binding


    【解决方案1】:

    您可以编写 custom KO bindingcustom KO component 来封装您的标记、API 密钥、jQuery 和 XHR 调用。

    使用您的代码和用例,组件听起来很合适。然后你的消费标记可能看起来像

    <weather params="zip: myZipCode"></weather>
    

    其中myZipCode 是消费页面视图模型中的ko.observable

    更新 1

    在代码中添加了粗略的代码,用于封装在 KO 组件中。

    更新 2

    将 jquery DOM 引用从 KO 组件代码中移出,因此组件模板使用 KO 绑定。添加了消费页面视图模型以显示完整示例。

    function openWeatherComponentViewModel(params) {
      var self = this;
      
      self.zip = ko.observable(ko.unwrap(params.zip));
      self.temperature = ko.observable();
      self.iconCode = ko.observable();
      self.iconUrl = ko.pureComputed(function() {
        return "http://openweathermap.org/img/w/" + self.iconCode() + ".png";
      });
      self.iconDescription = ko.observable();
      self.hasWeather = ko.observable(false);
      self.errorMessage = ko.observable();
      
      var apiKey = 'xxxxxxxxxxxxxxxxxxxx';
      var url = "https://api.openweathermap.org/data/2.5/weather?zip=" + self.zip() + ",us&APPID=" + apiKey + "&units=imperial";  
      $.getJSON(url, function(data) {
        self.temperature(Math.round(data.main.temp));
        self.iconCode(data.weather[0].icon);
        self.iconDescription(data.weather[0].main);
        self.hasWeather(true);
      }).fail(function(error) {
        self.hasWeather(false);
        self.errorMessage("OpenWeatherAPI is unable to load! " + error.responseJSON.message);
      });
    }
    
    ko.components.register('weather-component', {
      viewModel: openWeatherComponentViewModel,
      template: `<div id="open-weather" class="open-weather">
                    <div id="weather-data" class="weather-data" data-bind="if: hasWeather()">
                        <p>Current Weather for Zip Code <span data-bind="text: zip"></span></p>
                        <ul id="weather-items" class="weather-items">
                          <li>Temp: <span data-bind="text: temperature"></span>° F</li>
                          <li><img style="width: 25px" data-bind="attr: { src: iconUrl }"><span data-bind="text: iconDescription"></span></img></li>
                        </ul>
                    </div>
                    <div id="weather-data" class="weather-data" data-bind="if: !hasWeather()">
                        <span data-bind="text: errorMessage"></span>
                    <div>
                </div>`
    });
    
    function myConsumingPageViewModel() {
      var self = this;
      self.myZipCode = ko.observable("80130");
    }
    
    var vm = new myConsumingPageViewModel();
    
    ko.applyBindings(vm);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <weather-component params="zip: myZipCode"></weather-component>

    【讨论】:

    • 嗨@JoeWilson,我很难想出这段代码。我有function openWeatherViewModel(params) { this.temp = params.temp; this.iconCode = params.iconCode; this.iconUrl = params.iconUrl; this.iconDescription = params.iconDescription; } ko.components.register('weather-component', { viewModel: openWeatherViewModel, template: 'temp: data-bind="value:temp"/&gt;&lt;br /&gt;\ iconUrl: data-bind="value:iconUrl"/&gt;&gt;br /&gt;' }); ko.applyBindings();,但不确定如何使用 json 中的 API 数据与之绑定。任何帮助将不胜感激。
    • 我粗略地编写了上面的组件代码。它不起作用,因为我没有 API 密钥,但是一旦你进入 API 回调,你的代码应该像以前一样工作,而不使用组件。请注意,标记具有自定义元素和硬编码的邮政编码。
    • 我还没有获取天气 div 的数据。代码似乎仍在使用 jquery 方法。我需要删除 jquery DOM 更新并改用敲除模板。此外,我收到错误“您不能将绑定多次应用于同一元素。”我的 app.js 文件中已经有另一个视图模型。这就是问题所在。我查找了如何绑定多个视图模型,但似乎不是首选方式。这是我的 gitHub 存储库:github.com/ressen1012/neighborhood-map
    • 更新了将 jquery DOM 引用移出 KO 组件代码的答案,因此组件模板使用 KO 绑定。添加消费页面视图模型以显示组件代码和组件消费代码的完整示例。
    • 谢谢乔!当我将新的 openWeatherComponentViewModel 放入 initMap 函数之外的代码中时,我收到 2 个错误:未捕获的错误:您不能将绑定多次应用于同一个元素。和未捕获的 ReferenceError:无法处理绑定“textInput:函数(){return query}”消息:未定义查询。我尝试将其移动到现有的 ViewModel 中,但出现 Uncaught ReferenceError: myConsumingPageViewModel is not defined 错误。我不确定为什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-02
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    • 2019-01-05
    相关资源
    最近更新 更多