I have an array of objects. I need to render an information from the last item of the array and I try this:
<p>{leg.segments[leg.segments.length - 1].arrivalCity.caption}, </p>
but it keeps giving an error
Cannot read property 'caption' of undefined.
It seems that I can get items from arrays with length of 2 and more (or when specifically get leg.segments[0].arrivalCity.caption but get an error when try to render array with only one item. I can't understand what the problem is since it should just return leg.segments[leg.segment[0]] when array has just one item and be fine with it.
All objects have 'caption'-key, the only question is to get it from [0] or [1] index.
The array is a part of parsed JSON, here's one element I map through for an example:
"legs" :
[
{
"segments" :
[
{
"arrivalCity" :
{
"uid" : "LED",
"caption" : "ST PETERSBURG"
}
},
{
"arrivalCity" :
{
"uid" : "LON",
"caption" : "LONDON"
}
}
]
},
{
"segments" :
[
{
"arrivalCity" :
{
"uid" : "MOW",
"caption" : "MOSCOW"
}
}
]
}
]
I need to render LONDON in the first case and MOSCOW in the second. But I can get ST PETERSBURG and MOSCOW with <p>{leg.segments[0].arrivalCity.caption}</p> or an error with <p>{leg.segments[leg.segments.length - 1].arrivalCity.caption}</p>
It is unable to reproduce your problem. Please show us your array.
Assuming your array is,
var leg={segments:[{arrivalCity:{caption:"cap1"}}]};
Then if you run;
leg.segments[leg.segments.length - 1].arrivalCity.caption
You will see the expected output as 'cap1'
... quoting the OP ...
... <p>{leg.segments[0].arrivalCity.caption}</p> or ... <p>{leg.segments[leg.segments.length - 1].arrivalCity.caption}</p>
The misunderstanding might be due to not treating legs like an array. Thus, in order to always access the last arrivalCity item of each of a segments array, one has to iterate the legs array in first place.
Using the OP's sample data and implementing a basic render function which does iterate the legs array first and only with each iteration does access always the last item of the current segments array via e.g segmentList[segmentList.length - 1], as already done correctly by the OP, nothing will fail but the expected result will render ...
LONDON
MOSCOW
... example ...
function renderListOfLastArrivalCities(dataList) {
const listNode = document.querySelector('.last-arrivals');
dataList.forEach(({ segments: segmentList }) => {
//const lastSegmentItem = segmentList[segmentList.length - 1];
//const arrivalCity = lastSegmentItem && lastSegmentItem.arrivalCity;
const arrivalCity = segmentList[segmentList.length - 1]?.arrivalCity;
if (arrivalCity) {
const itemNode = document.createElement('li');
itemNode.textContent = arrivalCity.caption || '';
listNode.appendChild(itemNode);
}
})
}
const legs = [{
"segments": [{
"arrivalCity": {
"uid":"LED",
"caption":"ST PETERSBURG"
}
}, {
"arrivalCity": {
"uid":"LON",
"caption":"LONDON"
}
}]
}, {
"segments": [{
"arrivalCity": {
"uid":"MOW",
"caption":"MOSCOW"
}
}]
}];
renderListOfLastArrivalCities(legs);
<ul class="last-arrivals"></ul>
Seems like your leg.segments[leg.segments.length - 1] which i assume be as object that doesn't have arrivalCity property. If it has then you must be doing any typo or maybe your data shape is different.
Could you share your array with us to take a look over it.
I have a 10MB JSON file of the following structure (10k entries):
{
entry_1: {
description: "...",
offset: "...",
value: "...",
fields: {
field_1: {
offset: "...",
description: "...",
},
field_2: {
offset: "...",
description: "...",
}
}
},
entry_2:
...
...
...
}
I want to implement an autocomplete input field that will fetch suggestions from this file, as fast as possible while searching multiple attributes.
For example, finding all entry names,field names and descriptions that contain some substring.
Method 1:
I tried to flatten the nesting into an array of strings:
"entry_1|descrption|offset|value|field1|offset|description",
"entry_1|descrption|offset|value|field2|offset|description",
"entry2|..."
and perform case insensitive partial string match, query took about 900ms.
Method 2
I tried Xpath-based JSON querying (using defiant.js).
var snapshot = Defiant.getSnapshot(DATA);
found = JSON.search(snapshot, '//*[contains(fields, "substring")]');
query took about 600ms (just for a single attribute, fields).
Are there other options that will get me to sub 100ms? I have control of the file format so I can turn it into XML or any other format, the only requirement is speed.
Since you are trying to search for a substring of values it is not a good idea to use indexeddb as suggested. You can try flattening the values of the fields to text where fields seperated by :: and each key in the object is a line in the text file:
{
key1:{
one:"one",
two:"two",
three:"three"
},
key2:{
one:"one 2",
two:"two 2",
three:"three 2"
}
}
Will be:
key1::one::two::three
key2::one 2::two 2::three
Then use regexp to search for text after the keyN:: part and store all keys that match. Then map all those keys to the objects. So if key1 is the only match you'd return [data.key1]
Here is an example with sample data of 10000 keys (search on laptop takes couple of milliseconds but have not tested when throttling to mobile):
//array of words, used as value for data.rowN
const wordArray = ["actions","also","amd","analytics","and","angularjs","another","any","api","apis","application","applications","are","arrays","assertion","asynchronous","authentication","available","babel","beautiful","been","between","both","browser","build","building","but","calls","can","chakra","clean","client","clone","closure","code","coherent","collection","common","compiler","compiles","concept","cordova","could","created","creating","creation","currying","data","dates","definition","design","determined","developed","developers","development","difference","direct","dispatches","distinct","documentations","dynamic","easy","ecmascript","ecosystem","efficient","encapsulates","engine","engineered","engines","errors","eslint","eventually","extend","extension","falcor","fast","feature","featured","fetching","for","format","framework","fully","function","functional","functionality","functions","furthermore","game","glossary","graphics","grunt","hapi","has","having","help","helps","hoisting","host","how","html","http","hybrid","imperative","include","incomplete","individual","interact","interactive","interchange","interface","interpreter","into","its","javascript","jquery","jscs","json","kept","known","language","languages","library","lightweight","like","linked","loads","logic","majority","management","middleware","mobile","modular","module","moment","most","multi","multiple","mvc","native","neutral","new","newer","nightmare","node","not","number","object","objects","only","optimizer","oriented","outside","own","page","paradigm","part","patterns","personalization","plugins","popular","powerful","practical","private","problem","produce","programming","promise","pure","refresh","replace","representing","requests","resolved","resources","retaining","rhino","rich","run","rxjs","services","side","simple","software","specification","specifying","standardized","styles","such","support","supporting","syntax","text","that","the","their","they","toolkit","top","tracking","transformation","type","underlying","universal","until","use","used","user","using","value","vuejs","was","way","web","when","which","while","wide","will","with","within","without","writing","xml","yandex"];
//get random number
const rand = (min,max) =>
Math.floor(
(Math.random()*(max-min))+min
)
;
//return object: {one:"one random word from wordArray",two:"one rand...",three,"one r..."}
const threeMembers = () =>
["one","two","three"].reduce(
(acc,item)=>{
acc[item] = wordArray[rand(0,wordArray.length)];
return acc;
}
,{}
)
;
var i = -1;
data = {};
//create data: {row0:threeMembers(),row1:threeMembers()...row9999:threeMembers()}
while(++i<10000){
data[`row${i}`] = threeMembers();
}
//convert the data object to string "row0::word::word::word\nrow1::...\nrow9999..."
const dataText = Object.keys(data)
.map(x=>`${x}::${data[x].one}::${data[x].two}::${data[x].three}`)
.join("\n")
;
//search for someting (example searching for "script" will match javascript and ecmascript)
// i in the regexp "igm" means case insensitive
//return array of data[matched key]
window.searchFor = search => {
const r = new RegExp(`(^[^:]*).*${search}`,"igm")
,ret=[];
var result = r.exec(dataText);
while(result !== null){
ret.push(result[1]);
result = r.exec(dataText);
}
return ret.map(x=>data[x]);
};
//example search for "script"
console.log(searchFor("script"));
For instance I have some JSON data like below (The JSON data is just an example, I just want to give out some fake, make up and wrong format JSON as example)
cata :[{
name:test1,
data:['abc1, abc2' , 'abc3,abc4']
}
name:test2,
data:['abc5, abc6' , 'abc7,abc8']
}]
And indeed I need to render it to frontend, therefore I made a new object and try to push data into it
var name = "";
var key= [];
for(var i=0;i<2;i++){
name .push(cata[i].name)
key.push(cata[i].data.join(' + '));
}
var rehandle = {
name : name,
key : key
}
The above is just how i do it now, and which do no provide the desire result, i want to know how could i restore it so i can change the format from
['abc5, abc6' , 'abc7,abc8']
to
abc5+abc6 , abc7+abc8
UPDATE version of the question:
I think i better explain it step by step:
I have some raw data
I have a row of "data" in each set of data
(E.g:data:['abc1, abc2' , 'abc3,abc4'])
I want to change it's format to abc1+abc2 , abc3+abc4 and store it to another variable
I will pass the variable store abc1+abc2 , abc3+abc4 to an object
5.Render it one by one in a table
UPDATE 2
I have seen #pill's answer, am i able to render the data like
for(var i=0;i<cata.length;i++){
var trythis = trythis + '<td>'+name[i]+'</td>' + '<td>'+data[i]+'</td>'
}
To format your data from
['abc5, abc6' , 'abc7,abc8']
to
abc5+abc6 , abc7+abc8
you'd simply use
data.map(k => k.split(/,\s*/).join('+')).join(' , ')
or the ES5 version
data.map(function(k) {
return k.split(/,\s*/).join('+');
}).join(' , ');
For example...
var cata = [{"name":"test1","data":["abc1, abc2","abc3,abc4"]},{"name":"test2","data":["abc5, abc6","abc7,abc8"]}];
var rehandle = cata.reduce(function(o, d) {
o.name.push(d.name);
o.key.push(d.data.map(function(k) {
return k.split(/,\s*/).join('+');
}).join(' , '));
return o;
}, {
name: [],
key: []
});
console.log('rehandle:', rehandle);
Note that I had to fix up your data formatting
I have some good practice with using php and mysql, and am now starting with JSON.
I've made a simple json index containing paths to folders, and items inside them:
{ "foldery" : [
{
"foName": "website/img/bg",
"files" : [
"website/img/bg/bg1.jpeg",
"website/img/bg/bg2.jpg",
"website/img/bg/bg3.jpg",
"website/img/bg/bg4.jpeg"
]
},
{
"foName": "website/img/post1",
"files" : [
"website/img/post1/a.jpeg",
"website/img/post1/b.jpg",
"website/img/post1/c.jpeg",
"website/img/post1/d.jpg"
]
}
]
}
Now here is my jquery, for now returning a big mess of data, somewhere including the info about the contents inside:
$.getJSON("nameindex.json", function(data) {
console.log(data);
});
What I would like it to do, in mySql looks like this:
SELECT files FROM foldery WHERE foName = "website/img/post1"
Thus the result, would be an array containing all the files inside post1.
Unfortunately tho, after 2 hours of attempts I have nothing more than the simple console.log code.
Any help would be gladly appreciated
You need to iterate over your array and check forName to equality
function select(o, foName) {
var length = o.foldery.length;
for(var i = 0; i < length; i++){
if (o.foldery[i].foName == foName) {
return o.foldery[i].files;
}
}
}
var result = select(o, "website/img/post1")
console.log(result);
Result
[ 'website/img/post1/a.jpeg',
'website/img/post1/b.jpg',
'website/img/post1/c.jpeg',
'website/img/post1/d.jpg' ]
I am very new to programming as I have only started programming last week.
Code Part -
var office = document.getElementById('start').value;
var pickup = document.getElementById('start').value;
$.get("https://maps.googleapis.com/maps/api/distancematrix/json?origins="+office+"&destinations="+pickup+"&mode=drivinging&language=en&sensor=false",function(data){
alert(data['status']);
Data returned -
http://maps.googleapis.com/maps/api/distancematrix/json?origins=edingbourgh&destinations=london&mode=drivinging&language=en&sensor=false
I can access and display "destination_addresses", "status" and "origin_addresses" using data['status'] or data.status but unable to access anything inside rows[] I have tried every method I possibly know.
I thought that I could just do data.row.distance.text but nothing happens.
any help would be much appreciated
rows is an array, as well as elements, you need to access it like this:
var text = data.rows[0].elements[0].distance.text;
// this yields "652 km"
You want to return the first element of the array, because it has only one. rows[] doesn't access anything. You need a number within the brackets. There might be multiple objects rows or elements. Fill in the array index you want:
var text = data.rows[2].elements[5].distance.text;
// this yields text from the sixth element of the third row.
Original response:
{
"destination_addresses" : [ "London, UK" ],
"origin_addresses" : [ "Edinburgh, City of Edinburgh, UK" ],
"rows" : [
{
"elements" : [
{
"distance" : {
"text" : "652 km",
"value" : 652135
},
"duration" : {
"text" : "6 hours 44 mins",
"value" : 24247
},
"status" : "OK"
}
]
}
],
"status" : "OK"
}
try
alert(data['rows'][0].elements[0].distance.text);
output 625km
Include jquery and try to parse the json data returned using JSON.parse which would give you a javascript array object
var dataArray = JSON.parse(data['status']);
alert(dataArray['status']);
Hope this helps
first parse the json into a real object:
try {
var realObject = JSON.parse(jsonString);
} catch (err) {
console.log("error parsing json string");
}
and than you should be able to access via:
var text = data.rows[0].elements[0].distance.text;