【问题标题】:AngularJS - load images using REST API callsAngularJS - 使用 REST API 调用加载图像
【发布时间】:2014-09-23 16:45:05
【问题描述】:

我正在编写一个需要显示汽车库存的应用程序。我 ping 一个 API 以获取所有符合搜索条件的汽车,例如汽车制造商、型号和年份。我需要显示每辆车的图像以及其他信息。一旦 JSON 数据可用,它还会在我的结果中为每辆汽车提供一个 ID (StyleID),我需要使用它来进行另一个 API 调用以请求该汽车的图像。

在阅读了几篇文章 (such as this one) 后,我想我需要使用自定义指令,以便在循环结果时查询并将每辆车的图像插入特定位置。

我阅读了 Jim Lavin 的 custom directive tutorial 来创建我的示例。我希望这种方法能够奏效,但是我必须遗漏一些东西,因为它根本不执行我的自定义指令并按照我的意愿显示汽车图像。

有人可以帮忙吗?


这是显示我的代码的 plunker: http://plnkr.co/edit/5DqAspT92RUPd1UmCIpn?p=preview

这是关于我正在尝试使用的 specific media call to Edmunds API 的信息。

这是URL to the media endpoint


重复我的代码:

我的 HTML 代码:

<div firstImageOfMyCar data-styleid="style.id"></div>

<firstImageOfMyCar data-styleid="style.id"></firstImageOfMyCar>

这是我的自定义指令:

// Custom Directive to get first image of each car.
  app.directive('firstImageOfMyCar', function() {
    return {
      restrict: "E",
      link: function(scope, elm, attrs) {
        // by default the values will come in as undefined so we need to setup a
        // watch to notify us when the value changes
        scope.$watch(attrs.styleid, function(value) {
          //elm.text(value);

          // let's do nothing if the value comes in empty, null or undefined
          if ((value !== null) && (value !== undefined) && (value !== '')) {

            // get the photos for the specified car using the styleID.
            // This returns a collection of photos in photoSrcs.
            $http.get('https://api.edmunds.com/v1/api/vehiclephoto/service/findphotosbystyleid?styleId=' + value + '&fmt=json&api_key=mexvxqeke9qmhhawsfy8j9qd')
              .then(function(response) {
              $scope.photoSrcs = response.photoSrcs;

              // construct the tag to insert into the element.
              var tag = '<img alt="" src="http://media.ed.edmunds-media.com' + response.photoSrcs[0] + '" />" />'
              // insert the tag into the element
              elm.append(tag);
            }, function(error) {
              $scope.error3 = JSON.stringify(error);
            });
          } 
        });
      }
    }; 
  });

【问题讨论】:

  • 为什么不将图像 URL 添加到您的范围,然后像处理其余数据一样将其添加到模板中?

标签: javascript json angularjs api rest


【解决方案1】:

Angular 规范化元素的标签和属性名称以确定哪些元素匹配哪些指令。我们通常通过区分大小写的 camelCase 规范化名称(例如 ngModel)来引用指令。然而,由于 HTML 不区分大小写,我们在 DOM 中使用小写形式引用指令,通常在 DOM 元素上使用破折号分隔的属性(例如 ng-model)。

试试

<div first-image-of-my-car data-styleid="style.id"></div>

<first-image-of-my-car data-styleid="style.id"></first-image-of-my-car>

注意:如果您使用第一个属性,您需要将指令中的限制更改为restrict: "A",(或"AE" 以涵盖这两种情况)

另外,$http$scope 未在您的指令中定义。您可以简单地将$http 添加到指令函数中,DI 将注入它。您可能想使用scope 而不是$scope

提供的示例还存在一些其他问题。这是一个工作版本:http://plnkr.co/edit/re30Xu0bA1XrsM0VZKbX?p=preview

注意$http.then()会用data, status, headers, config调用提供的函数,数据会有你要找的响应。 (response.data[0].photoSrcs[0])

【讨论】:

  • 另一个不相关的注释,您似乎受到 API 的速率限制。在短时间内发出太多请求。一些请求返回403s 和message: "Account Over Queries Per Second Limit"
  • 非常感谢。另外,感谢其他提示。您还说我的代码还有其他一些问题。你能告诉我你认为可以改进的地方吗?我一直在考虑将 REST 调用转移到单个服务。还有别的事吗?再次感谢。
  • snies 有一个示例,说明如何从使用服务来抽象调用的服务器并整合它们中受益。不需要做他正在做的$q 的事情,只需返回$http 调用(它返回自己的承诺,不需要自己做)。
【解决方案2】:

请看@TheScharpieOne 的回答。但我也玩弄了你的代码和 api。我想补充一点,您的代码可能会受益于使用角度服务来包装 api 调用。

这是一个服务示例:

app.service('VehicleService', function ($q, $http) {

this.getAllMakes = function () {
    var deferred = $q.defer();
    var url = 'https://api.edmunds.com/api/vehicle/v2/makes?state=new&view=basic&fmt=json&api_key=mexvxqeke9qmhhawsfy8j9qd'
    $http.get(url).then(function (response) {
        deferred.resolve(response.data.makes);
    }, function (error) {
        deferred.reject(new Error(JSON.stringify(error)));
    });
    return deferred.promise;
}

this.getCar = function (makeName, modelName, year) {
    var deferred = $q.defer();
    var url = 'https://api.edmunds.com/api/vehicle/v2/' + makeName + '/' + modelName + '/' + year + '?category=Sedan&view=full&fmt=json&api_key=mexvxqeke9qmhhawsfy8j9qd'
    $http.get(url).then(function (response) {
        deferred.resolve(response.data);
    }, function (error) {
        deferred.reject(new Error(JSON.stringify(error)));
    });
    return deferred.promise;
};

});

你可以这样使用它:

function CarCtrl($scope, VehicleService, VehiclePhotoService) {
// init make select
VehicleService.getAllMakes().then(function (value) {
    $scope.makes = value;
});

$scope.getCars = function () {
    VehicleService.getCar($scope.make.niceName, $scope.model.niceName, $scope.year.year)
        .then(function (value) {
        console.log(value);
        $scope.myCars = value;
    })
}
}

这是一个完整的工作 jsfiddle:http://jsfiddle.net/gkLbh8og/

【讨论】:

  • 非常感谢,这真是太棒了!我打算这样做,但不知道如何去做。 +1
  • 我稍微清理了 snies 示例以删除所有不需要的承诺和$q DI,jsfiddle.net/gkLbh8og/1 它仍然以相同的方式工作,只是更清洁和更易于阅读。 (我还删除了 try-catch,因为大多数 JS 编译器无法优化它们,如果可以避免,通常不推荐使用。
  • @TheSharpieOne +1 查看我的代码。我对修改后的小提琴有两个问题jsfiddle.net/gkLbh8og/1:
  • 1) delay += 500 不会在每次调用时让服务变慢吗?和 2) 为什么我可以跳过延迟的内容并仍然在 VehicleService.getAllMakes() 上使用 thenresponse.data.makes 不是承诺,是吗?那么是不是因为 $http 之前的承诺?
  • 1) 是的,这只是一种廉价的方法,可以让通话以 0.5 秒、1 秒、1.5 秒、2 秒……等等进行。 (需要添加一些东西来重置执行新搜索时的延迟)。 2) 在 promise 的 resolve 中返回的内容被传递给 promise 链中的下一个函数。返回的 $http 链接承诺,然后在解决时,函数中返回的内容(不是承诺,认为是 express 中间件)传递给链中的下一个函数。如果需要,您实际上可以更改每个解析之间的数据。这也是 http 拦截器允许您更改数据的工作方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-04
  • 1970-01-01
  • 2016-02-27
  • 2016-04-05
  • 1970-01-01
  • 2019-07-01
  • 2015-11-07
相关资源
最近更新 更多