skolte
skolte

Reputation: 367

AngularJS - load images using REST API calls

I am writing an application where I need to display car inventory. I ping an API to get all cars matching search criteria such as Car Make, Model and Year. I need to display an image of each car along with the other information. Once the JSON data is available, it also has an ID (StyleID) for each car in my results that I need to use to make another API call to request images for that car.

After reading a few articles (such as this one) I figured I need to use a custom directive in order to query and insert each car's image in a specific spot when looping over the results.

I read this custom directive tutorial by Jim Lavin to create my sample. I was hoping that this approach will work however I must be missing something as it simply doesn't execute my custom directive and display the car image as I want it to.

Can someone please help?


Here's the plunker that shows my code: http://plnkr.co/edit/5DqAspT92RUPd1UmCIpn?p=preview

Here's the information about the specific media call to Edmunds API that I am trying to use.

And here's the URL to the media endpoint


Repeating my code :

My HTML code :

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

or

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

And here's my custom directive:

// 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);
            });
          } 
        });
      }
    }; 
  });

Upvotes: 0

Views: 5758

Answers (2)

snies
snies

Reputation: 3521

Please look at the answer by @TheScharpieOne. But i also played around with your code and api. And I would like to add, that your code might benefit from using angular services to wrap the api calls.

Here is an Example for a service:

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;
};

});

You could use it like this:

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;
    })
}
}

Here is a complete working jsfiddle: http://jsfiddle.net/gkLbh8og/

Upvotes: 2

TheSharpieOne
TheSharpieOne

Reputation: 25736

Angular normalizes an element's tag and attribute name to determine which elements match which directives. We typically refer to directives by their case-sensitive camelCase normalized name (e.g. ngModel). However, since HTML is case-insensitive, we refer to directives in the DOM by lower-case forms, typically using dash-delimited attributes on DOM elements (e.g. ng-model).

Try

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

or

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

Note: if you use the first, with the attribute, you will need to change the restrict in the directive to restrict: "A", (or "AE" to cover both cases)

Also, $http, and$scope are not defined in your directive. You can simply add $http to the directive function and DI will inject it. You probably want to use scope instead of $scope.

There were also some other things wrong with the example provided. Here is a working version: http://plnkr.co/edit/re30Xu0bA1XrsM0VZKbX?p=preview

Note that $http's .then() will call the provided function with data, status, headers, config, data will have the response you are looking for. (response.data[0].photoSrcs[0])

Upvotes: 3

Related Questions