1

I have been trying to fetch a section of the response json data from an API call in my angular application.

I have tried various combinations but I am only able to fetch the last record and not both the records.

Here is my html

<div ng-controller="MyCtrl">
<li ng-repeat="x in textvalues">
       {{ x.event.description }}
</li>
</div>

and the controller code

var myApp = angular.module('myApp', []);

function MyCtrl($scope, $http) {

    $http.get('http://www.vizgr.org/historical-events/search.php?', {params: {format: 'json', query:'India', limit:'2'}}).then(function(response) {
            $scope.textvalues = response.data;
            console.log($scope.textvalues);
        });

}

The response from the API call is as follows:

{
  "result": {
    "count": "2",
    "event": {
      "date": "-293",
      "description": "When an invasion of",
      "lang": "en",
      "category1": "By place",
      "category2": "Persia",
      "granularity": "year"
    },
    "event": {
      "date": "-250",
      "description": "The Mauryan s",
      "lang": "en",
      "category1": "By place",
      "category2": "India",
      "granularity": "year"
    }
  }
}

And I am trying to print the event description in loop on the UI

Here is my fiddle - http://jsfiddle.net/nirajupadhyay/Jd2Hw/105/

I have tried various combination of the response data but unable to get to both the descriptions.

Kindly help.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
Niraj
  • 333
  • 1
  • 5
  • 23
  • Can you please give code for the API http://www.vizgr.org/historical-events/search.php, where you are creating the final object that is being returned. – Nandita Sharma Jun 02 '18 at 17:20
  • @NanditaAroraSharma It is a freely available public API - here it is http://www.vizgr.org/historical-events/ – Niraj Jun 02 '18 at 17:32

4 Answers4

2

I feel this API is somehow massively wrong. A JSON object can never have 2 identical keys with different values in them. If you check the network tab, then you will see that the response has only 1 event key in the object its value is the last value that is returned by the object. So although it might show 2 events in stringified version but it will never hold 2 values to same key in a JSON object.

Read Does JSON syntax allow duplicate keys in an object?

Instead of passing format: json to API, do not pass any param for format. It will give the result in xml format. Then convert this xml format to json format either by some library or the code as shown below.

var myApp = angular.module('myApp', []);

function MyCtrl($scope, $http) {

  $http.get('http://www.vizgr.org/historical-events/search.php?', {
    params: {
      /* format: 'json', */
      query: 'India',
      limit: '2'
    }
  }).then(function(response) {
    console.log(response.data);
    var dom = parseXml(response.data);
    var json = xml2json(dom)
    console.log(json)
    $scope.events = json.result.event;
  });

  function parseXml(xml) {
   var dom = null;
   if (window.DOMParser) {
      try { 
         dom = (new DOMParser()).parseFromString(xml, "text/xml"); 
      } 
      catch (e) { dom = null; }
   }
   else if (window.ActiveXObject) {
      try {
         dom = new ActiveXObject('Microsoft.XMLDOM');
         dom.async = false;
         if (!dom.loadXML(xml)) // parse error ..

            window.alert(dom.parseError.reason + dom.parseError.srcText);
      } 
      catch (e) { dom = null; }
   }
   else
      alert("cannot parse xml string!");
   return dom;
}

function xml2json(xml) {
  try {
    var obj = {};
    if (xml.children.length > 0) {
      for (var i = 0; i < xml.children.length; i++) {
        var item = xml.children.item(i);
        var nodeName = item.nodeName;

        if (typeof (obj[nodeName]) == "undefined") {
          obj[nodeName] = xml2json(item);
        } else {
          if (typeof (obj[nodeName].push) == "undefined") {
            var old = obj[nodeName];

            obj[nodeName] = [];
            obj[nodeName].push(old);
          }
          obj[nodeName].push(xml2json(item));
        }
      }
    } else {
      obj = xml.textContent;
    }
    return obj;
  } catch (e) {
      console.log(e.message);
  }
}
}

Check js fiddle here.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
Nandita Sharma
  • 13,287
  • 2
  • 22
  • 35
  • Good Answer using vanilla JavaScript. The jQuery library can be used to simplify the task of extracting data from XML. – georgeawg Jun 02 '18 at 22:40
2

As Nandita Arora Sharma answered the API response is wrong.

RFC-7159, standard for JSON published by (IETF), states:

" 4. Objects

... single colon comes after each name, separating the name
from the value. A single comma separates a value from a following
name. The names within an object SHOULD be unique."

API Test with Postman. Which renders the JSON and as mentioned and there is only one event. This is possibly the reason why angular can only repeat 1 time

prettyfied response data

Postman RAW response data within the raw data has all event object with duplicated keys.

Community
  • 1
  • 1
Michael
  • 556
  • 2
  • 8
0

You need to pass $http as a parameter to your controller , you can see the particular error says "$http is not defined" in controller

function MyCtrl($scope,$http) {

WORKING FIDDLE

To answer your actual question, your service returns an object not an array . iT returns an object of object. so you cannot use ng-repeat in this case. it returns on

{"result":{"count":"3","event":{"date":"-250","description":"The Mauryan ''Lion Capital of Asoka'', is erected as part of a pillar at Sarnath, Uttar Pradesh in India (approximate date). It is now preserved at the Sarnath Museum in Sarnath.","lang":"en","category1":"By place","category2":"India","granularity":"year"}}}

inorder to access event you can just use

   {{textvalues.result.event.description}}

DEMO

Sajeetharan
  • 216,225
  • 63
  • 350
  • 396
  • Thank you @sajeetharan I corrected the typo. But the problem still persists. There are two event descriptions and I want to be able to print both – Niraj Jun 02 '18 at 16:33
  • Check the updated answer – Sajeetharan Jun 02 '18 at 16:40
  • Thanks again Sajeetharan. So, this prints only one of the event descriptions on the UI. If you look at the developer tools -> network -> response, there are 3 events objects. I am trying to get all of them and show them as a list on my UI – Niraj Jun 02 '18 at 16:47
  • that is very strange, because even though it shows 3 objects in code it gets only 1. let me check – Sajeetharan Jun 02 '18 at 16:49
0

The object structure that you are referring to can never exist

{
  "result": {
    "count": "2",
    "event": {
      "date": "-293",
      "description": "When an invasion of",
      "lang": "en",
      "category1": "By place",
      "category2": "Persia",
      "granularity": "year"
    },
    "event": {
      "date": "-250",
      "description": "The Mauryan s",
      "lang": "en",
      "category1": "By place",
      "category2": "India",
      "granularity": "year"
    }
  }
}

If any key is repeated in an object, it overrides the previous set value in the JSON object key value pair. What the API should return should be something like given below, then only you can get all event objects.

{
  "result": {
    "count": "3",
    "event": [{
      "date": "-250",
      "description": "The Mauryan ''Lion Capital of Asoka'', is erected as part of a pillar at Sarnath, Uttar Pradesh in India (approximate date). It is now preserved at the Sarnath Museum in Sarnath.",
      "lang": "en",
      "category1": "By place",
      "category2": "India",
      "granularity": "year"
    },
    {
      "date": "-250",
      "description": "The Mauryan ''Lion Capital of Asoka'', is erected as part of a pillar at Sarnath, Uttar Pradesh in India (approximate date). It is now preserved at the Sarnath Museum in Sarnath.",
      "lang": "en",
      "category1": "By place",
      "category2": "India",
      "granularity": "year"
    },
    {
      "date": "-250",
      "description": "The Mauryan ''Lion Capital of Asoka'', is erected as part of a pillar at Sarnath, Uttar Pradesh in India (approximate date). It is now preserved at the Sarnath Museum in Sarnath.",
      "lang": "en",
      "category1": "By place",
      "category2": "India",
      "granularity": "year"
    }]
  }
}
Nandita Sharma
  • 13,287
  • 2
  • 22
  • 35
  • Here is the API - http://www.vizgr.org/historical-events/ – Niraj Jun 02 '18 at 17:33
  • 2
    I feel this API is somehow massively wrong. A JSON object can never have 2 identical keys with different values in them. If you check the network tab, then you will see that the response has only 1 event key in the object its value is the last value that is returned by the object. So although it might show 2 events in stringified version but it will never hold 2 values to same key in a JSON object. – Nandita Sharma Jun 02 '18 at 17:47
  • Read this https://stackoverflow.com/questions/21832701/does-json-syntax-allow-duplicate-keys-in-an-object?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – Nandita Sharma Jun 02 '18 at 17:52
  • @Niraj I have added another answer. Please have a look at that. This cant be achieved by the way you are doing because this public API seems to be faulty to me ! – Nandita Sharma Jun 02 '18 at 18:52