Utilizing AngularJS to dynamically load images by making REST API requests

Currently, I am in the process of developing an application that requires me to showcase a car inventory. To achieve this, I utilize an API to fetch all cars that match specific search criteria including Car Make, Model, and Year. My objective is to exhibit an image of each car alongside other pertinent information. In addition to obtaining JSON data, there is also a unique ID (StyleID) assigned to each car in the results which prompts me to initiate another API call to procure images for each individual car.

Having explored various articles on the topic, such as the one linked here, it became apparent that implementing a custom directive is necessary in order to retrieve and insert the image of each car at a specified location while iterating through the results.

In my quest for a solution, I came across Jim Lavin's tutorial on creating a custom directive. Despite following the guidelines provided, I seem to have missed a crucial step as my custom directive fails to execute properly, resulting in a lack of display for the car images as intended.

Seeking guidance from others who may be more experienced in this area, I kindly ask for assistance.


To provide further context, here is a link to the Plunker showcasing my code implementation:

Additonally, detailed information regarding the media call to the Edmunds API can be found here.

For those interested, the URL to access the media endpoint has been provided.


Reiterating my code setup:

HTML syntax utilized:

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

or

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

Implementation of the custom directive:

// Custom Directive for fetching the primary image of each car.
  app.directive('firstImageOfMyCar', function() {
    return {
      restrict: "E",
      link: function(scope, elm, attrs) {
        // setting up a watcher to detect changes in the value
        scope.$watch(attrs.styleid, function(value) {
          //elm.text(value);

          // only proceed if the value is not empty or undefined
          if ((value !== null) && (value !== undefined) && (value !== '')) {

            // fetching photos for the specified car using the StyleID
            // returning 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;

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

Answer №1

Angular normalizes the tag and attribute names of an element to determine how directives are matched with elements. Directives are usually referred to using their case-sensitive camelCase normalized name (e.g. ngModel). However, since HTML is case-insensitive, directives in the DOM are referenced in lower-case forms with dash-delimited attributes on DOM elements (e.g. ng-model).

Give it a 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>

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

Additionally, make sure that $http and $scope are defined in your directive. You can simply add $http to the directive function and Dependency Injection (DI) will take care of injecting it. It's recommended to use scope instead of $scope.

The example provided has some issues. Here is a corrected version for reference: http://plnkr.co/edit/re30Xu0bA1XrsM0VZKbX?p=preview

Note that when using $http's .then(), the provided function will receive parameters such as data, status, headers, config. The actual response data will be contained within data (e.g. response.data[0].photoSrcs[0])

Answer №2

Take a look at the response provided by @TheScharpieOne. I also experimented with your code and API, suggesting that incorporating angular services to encapsulate API calls could enhance your code.

Check out this example of 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 can utilize it like this:

function CarCtrl($scope, VehicleService, VehiclePhotoService) {
// initialize make selection
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 an operational jsfiddle showcasing the complete implementation: http://jsfiddle.net/gkLbh8og/

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What are the techniques for implementing an if statement in CSS or resolving it through JavaScript?

Demo available at the bottom of the page Within my code, there is a div called #myDiv that defaults to an opacity of 0. Upon hovering over #myDiv, the opacity changes to 1. See the CSS snippet below: #myDiv { opacity: 0; } #myDiv:hover { opacity: 1 ...

Error 404 - The Web API is missing and needs to be integrated with AngularJS

Here is the controller code snippet: [HttpGet] [ActionName("Email")] public HttpResponseMessage GetByEmail(string email) { Users user = db.Users.Find(email); if (user == null) { throw new HttpResponseExcept ...

Refresh the Pug view using Express

I am working on creating a searchable/filterable listview. Currently, I am able to retrieve data from a database and display it in a listview using Express with Pug. Now, I want to implement the functionality of filtering the displayed listview. To achie ...

What is the best method for effectively integrating a filter into an Angular application?

I'm encountering an issue with my Angular filters and could use some assistance. Would you mind checking out the following link: When I select 'Hitchens' from the dropdown menu, it displays information for both Hitchens and The Others. I am ...

Enable the central bootstrap button to expand and occupy the entire width

Here is a code snippet that I have: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>test</tit ...

Discovering routes in Angular2

I'm attempting to replicate something similar to this example here: AngularJS show div based on url/condition <span id="page-locator" *ngIf="location.path() == '/overview'">test</span> Unfortunately, it's not working as ex ...

How does Code Sandbox, an online in-browser code editor, manage file storage within the browser?

What are the ways in which Code Sandbox and StackBlitz, as online in-browser code editors, store files within the browser? ...

Vue.js computed property fails to initiate

Why is the Vue JS computed property not triggered with this markup? <!-- language: lang-html --> <p>£{{plant_price}}</p> <div v-if="selected.plant.variations.length > 0 "> <select v-model="selected.plant.selected_ ...

Exploring touch events and input focusing on mobile devices using JavaScript

Recently, I integrated a JS touch mapping function into one of my pages sourced from Stack Overflow. This was necessary to enable my jQuery draggables to work on iOS Safari, as drag and drop functionality was not functioning without this mapping. Here is ...

What is the reason for the absence of the Express property "ip" in the list generated by

Check out this code snippet: const express = require('express'); const app = express(); app.get('/', function(request, response) { console.log(Object.keys(request)); console.log(request.ip); }); app.listen(1337); The first log ...

Guide to implementing hapi-auth-jwt2 authorization on a specific route within hapi.js?

I am facing an issue with using an access token in hapi.js. I am struggling to comprehend how to utilize this token for authentication purposes. Currently, I am referring to the article on dwyl/hapi-auth-jwt2. My database setup involves mongodb. However, I ...

Utilizing Ajax to handle and interpret a JSON HttpResponse

After sending an HttpResponse from views.py to an HTML page, I encountered an issue where only the JSON object is displayed instead of the expected details in the HTML format. The current appearance of the page after the request: https://i.sstatic.net/yFe ...

evaluating an object against null

When comparing two objects a and b, it is necessary to ensure that one of them is not null. However, deciphering this can be quite chaotic. {} - null => -0 [] - null => 0 1 - null => 1 "1" - null => 1 true - null ...

What is the significance of the -infinity value in the JavaScript console?

Recently, while learning JavaScript ES6, I came across a strange result of -infinity on my console when running the following code: let numeros = [1, 5, 10, 20, 100, 234]; let max = Math.max.apply(numeros); console.log(max); What does this ...

Discovering the method to access a getter from a different JavaScript file

In a laravel + vuejs project, I am trying to access my currentUser role in my Acces.js file using store.getters.currentUser but encountering an error: Error in render: "TypeError: Cannot read property 'getters' of undefined I have tried mu ...

Custom date formatting with jQuery table sorting

I have been using a jQuery plugin called Tablesorter to sort a table. I am facing an issue with sorting dates in the yyyy MMM dd format, especially because my date inputs are in French. Here is an example of how the dates are formatted: 2014 janv. 05 20 ...

Using C# objects as the main nodes in a JSON structure

I am attempting to send a Json object that I want to retrieve from jquery as, jdata.comType the c# code I am using is as follows, var frontChartList = new List<object>(); frontChartList.Add(new { comType = com ...

What is the best way to deactivate a submit button while an AJAX request is underway, and then reactivate it once a successful AJAX response is

I am working with the following HTML code: <form action="view_rebate_master.php" method="post"> <div class="form-group"> <label for="company_name" class="col-lg-12">Manufacturer</label> <div class="col-lg-12"> ...

Gson throwing an error with an unparsable date format?

I am encountering an issue while attempting to parse JSON data with a Java POJO class. Below is the JSON and POJO structure: JSON: { "startDate": "2018-09-18T12:00:00+0000", "endDate": "2018-09-18T14:00:00+0000", "startDateAsDate": 153 ...

Activating autocomplete outcomes via AJAX using Cucumber/Capybara/Selenium

Whenever I try to run my tests, the autocomplete dropdown menu doesn't appear unless I physically click on the search input field. This is a Cucumber test that utilizes Selenium Webdriver, and the data is sourced from the Crafty Clicks Address Autoco ...