Hi I got a bit stuck at trying to understand how to fetch data of a JSON file.
environment.ts:
export const environment = {
production: false,
urlListBooks: "/assets/list-books.json",
urlGetBooks: "/assets/edit-book.json?:id",
urlGetTags: "/assets/edit-book.json?:tags",
urlPostBooks: "/assets/edit-book.json",
urlListTags: "/assets/list-tags.json",
urlPostTags: "/assets/edit-tag.json"
};
edit-book.json:
"book":{
"id": 1,
"title": "The Shining",
"authorId": 1,
"tags": [{"name":"new"}, {"name":"test"}]
},
"authors":[
{
"id": 1,
"prename": "Stephen",
"surname": "King"
},
{
"id": 3,
"prename": "Algernon",
"surname": "Blackwood"
},
{
"id": 4,
"prename": "Edgar Allan",
"surname": "Poe"
},
{
"id": 5,
"prename": "Howard Phillips",
"surname": "Lovecraft"
}
],
"tags":[
{
"name": "new"
},
{
"name": "Horror"
},
{
"name": "Romance"
}
]
}
service:
getBookTags(n: String) Observable<Tag[]>{
return this.http.get<Tag[]>(environment.urlGetTags.)
}
what I want getBookTags(n: String) to do is returning the tags array of the book with title n defined in the edit-book.json (e.g. "tags": [{"name":"new"}, {"name":"Horror"}] ) so that I can later use the function to check which tags a book has and select them.
Your help would be very appreciated :)
Ok I think I've solved this for you, I'm going to walk through my process with you so you understand what the goal is. You can see my solution here: https://codesandbox.io/s/thirsty-minsky-g6959f?file=/assets/edit-book.json:0-752
First thing is that your JSON you provided doesn't really make much sense, it shows multiple authors and just one "book". I think instead you want multiple books. Secondly, it's gotta be wrapped in a curly brace as shown:
{
"books": [
{
"id": 1,
"title": "The Shining",
"authorId": 1,
"tags": [{ "name": "new" }, { "name": "test" }]
},
{
"id": 2,
"title": "The Wendigo",
"authorId": 2,
"tags": [{ "name": "Horror" }]
}
],
"authors": [
{
"id": 1,
"prename": "Stephen",
"surname": "King"
},
{
"id": 3,
"prename": "Algernon",
"surname": "Blackwood"
},
{
"id": 4,
"prename": "Edgar Allan",
"surname": "Poe"
},
{
"id": 5,
"prename": "Howard Phillips",
"surname": "Lovecraft"
}
],
"tags": [
{
"name": "new"
},
{
"name": "Horror"
},
{
"name": "Romance"
}
]
}
Now, in your Typescript code we want to have typings for the json you're going to fetch. This will make your code more readable, it will give you intellisense, and help you catch some errors before you try to run your code. So we are going to go ahead and type the properties of the JSON as follows:
type Tag = {
name: string;
};
type Book = {
id: number;
title: string;
authorId: number;
tags: Tag[];
};
type Author = {
id: number;
prename: string;
surname: string;
};
type BookData = {
books: Book[];
authors: Author[];
tags: Tag[];
};
Basically what I said is we have bookdata which is made up of books, authors, and tags. Books have properties given under type Book, same thing with Author and Tag.
Now for the actual running code, we are going to use the fetch api to get the json data at the url.
async function getBookTags(n: string): Promise<Book[]> {
return fetch(url)
.then<BookData>((res) => res.json())
.then((data) => data.books)
.then((books) => books.filter((b) => doesBookHaveTag(b, n)));
}
First thing we do is fetch the data from the api, this returns a promise which when resolved (this is what .then does) we take the response and parse it for a json. Then when that promise resolves we get the books in the data. Then when that promise resolves we filter in books that have the matching tag.
doesBookHaveTag is just a little helper function I defined:
function doesBookHaveTag(book: Book, n: string): boolean {
// just return if book has at least one tag matching n
return book.tags.some((t) => t.name.toLowerCase() === n.toLowerCase());
}
If you don't understand promises you should watch some videos on it, but basically the browser sends out an http request and then when it resolves it queues a task to execute the function [see endnote] in .then when it has time. So when we want to call your async function and say log all books with the tag "horror" we do it as shown:
getBookTags("horror").then(console.log); // returns the one book.
I hope this makes sense and you can sort of see how to fetch the data, how to handle the promise it returns, and how to type your response. The only thing I'm not sure on is how Angular changes this for you (I'm a react guy), but this is really just non-library specific Javascript/Typescript.
[endnote] when I say function in .then, what I mean is that .then(data => data.books) is passing a function into the .then function. data => data.books is actually a function the same as:
function(data: BookData): Book[] {
return data.books
}
I have trouble taking data from an API set. The body if viewed in Postman / Insomnia is as follows
{
"responses": {
"log": [
{
"id": 123,
"date": "2022-01-01T01:12:12.000Z",
"type": "online",
"details": [{
"detailId": "123-1",
"note": "success",
}]
},
{
"id": 124,
"date": "2022-01-01T01:12:12.000Z",
"type": "offline",
"details": [{
"detailId": "123-2",
"note": "failed",
}]
}
]
}
}
I want to take all data from log, as well from details. I used
adapt(item: any) {
return {
id: item.id,
date: item.date,
details: {
detailId: item.details.detailId,
note: item.details.note,
},
};
}
this returns id and date just fine. I also have a query to filter it based on type (online or offline), basically adding &type= into the API. It works for the online, but it returns detailId is undefined for offline (I used the same body, adapter and API minus the query for both data)
details is an array of object if you want to adapt it you need to do it iteratively.
adapt(item: any) {
const details = item.details.map(d => {detailId: d.id, note: d.note, …});
return {
id: item.id,
date: item.date,
details
};
}
Found the answer, apparently to make sure that I can get every value is to add ? after the [0], so it should be
details: {
detailId: item.details[0]?.detailId,
note: item.details[0]?.note,
},
I tried to use jqGrid formatter: "actions" for remote json url but it shifts rows because number of column names and actual returned data doesn't match (act column is extra one in column names). I did search online and it looks like all examples are for local data (on page) where json is used as key/value, while url:somepage.php returns a csv kind-of-format of columns(no keys, just values). Also I use id as hidden field, while all examples show id. I use one more hidden column as well.
here is my colmodel:
url: "manager_json",
editurl: "manager_edit",
datatype: "json",
//data: mydata,
width:1000,
//jsonReader: {
// repeatitems : false,
// },
colNames: ["","Id","Uid","Custom Id","Image Name","Coord. X","Coord. Y","Gender","Progress","Status","Created","Updated"],
colModel: [{"name":"act","template":"actions","formatoptions":{"editformbutton":true}},{"name":"id","align":"center","width":33,"editable":false,"hidden":true},{"name":"uid","align":"center","width":33,"editable":true,"hidden":true,"editrules":{"edithidden":false,"required":false}},{"name":"ta_id","align":"center","width":100,"editrules":{"required":true}},{"name":"image","width":150,"template":"text","editrules":{"required":true}},{"name":"x","width":100,"align":"center","template":"integer","editrules":{"required":true}},{"name":"y","width":100,"align":"center","template":"integer","editrules":{"required":true}},{"name":"gender","width":100,"align":"center","formatter":"select","stype":"select","editrules":{"required":true},"edittype":"select","editoptions":{"value":"f:Female;m:Male","defaultValue":"m"},"searchoptions":{"sopt":["eq","ne"],"value":":Any;f:Female;m:Male"}},{"name":"progress","width":120,"align":"center","formatter":"select","stype":"select","editrules":{"required":true},"editable":false,"edittype":"select","editoptions":{"value":"-:New;pf:Process Failed;ps:Process Scheduled;pss:Process Success;p:Processing...;s:Staging;tf:Test Failed;ts:Test Scheduled;tss:Test Success;t:Testing...","defaultValue":"m"},"searchoptions":{"sopt":["eq","ne"],"value":":Any;-:New;pf:Process Failed;ps:Process Scheduled;pss:Process Success;p:Processing...;s:Staging;tf:Test Failed;ts:Test Scheduled;tss:Test Success;t:Testing..."}},{"name":"status","width":100,"align":"center","formatter":"select","stype":"select","edittype":"select","editoptions":{"value":"a:Active;n:New","defaultValue":"m"},"searchoptions":{"sopt":["eq","ne"],"value":":Any;a:Active;n:New"}},{"name":"date_created","width":150,"template":"text","editable":false},{"name":"last_updated","width":150,"template":"text","editable":false}]
And here is my actual data from my server (db) as per jqgrid specification:
{"page":1,"total":1,"records":7,"rows":[{"id":32,"cell":[32,"889daf31ff3e49544f52850258439600","2uu","2ok",2,2,"m","-","a","2017-02-10 18:57:05","2017-02-10 23:37:12"]},{"id":30,"cell":[30,"","11","11",1,1,"m","-","a","2017-02-10 18:01:52","2017-02-10 18:01:52"]},{"id":29,"cell":[29,"aaa","ww222111uu","11",1,1,"m","-","a","2017-02-10 18:00:36","2017-02-10 23:37:08"]},{"id":27,"cell":[27,"","11","1",1,1,"m","-","a","2017-02-10 17:57:41","2017-02-10 17:57:41"]},{"id":25,"cell":[25,"","4tt","4img",4,4,"f","-","n","2017-02-10 17:50:21","2017-02-11 00:26:03"]},{"id":24,"cell":[24,"","1","1",1,1,"m","-","a","2017-02-10 17:49:38","2017-02-10 17:49:38"]},{"id":22,"cell":[22,"","bbb","imam 222",2,22,"f","p","n","2017-02-08 20:14:55","2017-02-10 13:27:57"]}]}
As you can see cell row has less columns than colNames and colModel. Also id and uid columns are hidden. I added on extra fake column from db, but it did not help
i am using jqGrid 4.13.7-pre
I'd recommend you to return objects like
{
"id": 32,
"uid": "889daf31ff3e49544f52850258439600",
"ta_id": "2uu",
"image": "2ok",
"x": 2,
"y": 2,
"gender": "m",
"progress": "-",
"status": "a",
"date_created": "2017-02-10 18:57:05",
"last_updated": "2017-02-10 23:37:12"
}
instead of
{
"id": 32,
"cell": [
32, "889daf31ff3e49544f52850258439600", "2uu", "2ok", 2, 2, "m", "-", "a",
"2017-02-10 18:57:05", "2017-02-10 23:37:12"
]
}
as the server response. It will simplify your code.
If you do need to process the current format of the data, then you will have to force repeatitems: false mode by usage the option
jsonReader: {
repeatitems: false
}
and to use jsonmap property of colModel to inform jqGrid from which element of the item one should read the column data. The jsonmap could be either in the string form like
jsonmap: "cell.1"
or in the function form:
jsonmap: function (item) {
return item.cell[1];
}
To make the code better maintainable you can define an object like
var columnOrder = {
id: 0,
uid: 1,
ta_id: 2,
image: 3,
x: 4,
y: 5,
gender: 6,
progress: 7,
status: 8,
date_created: 9,
last_updated: 10
};
which provides the index in cell array by the column name and to use jsonmap like
jsonmap: function (item) {
return item.cell[columnOrder.uid];
}
The demo https://jsfiddle.net/OlegKi/ozzgnaeh/2/ demonstrates the approach.
Hey guys so I am currently using jqgrid with json data and it currently reads in fine but i am having some difficulties getting an embeded object to read into the grid. So my json data looks something like this:
{"total":1,"page":"1","records":1,"rows":[{"Cell1":1,"Cell2":"stuff","Cell3":{"date":"2013-06-02 10:56:00","timezone_type":3,"timezone":"UTC"}}]}
Does anyone know how i can get jqgrid to read in Cell3 as one piece of data and interpret it to just display the date and time?
my current json reader is as follows:
jsonReader : {
root:"rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
id: "0"
}
Thanks again everyone
First of all the options jsonReader: {repeatitems: false, id: "0"} are incorrect. Integer values of id can be used in case of usage default repeatitems: true setting. In the case the data which represent the row of the grid looks like array ["1", "Cell2"] and not as object with named properties {"Cell1": 1, "Cell2": "stuff"}. You should use jsonReader: {repeatitems: false, id: "Cell1"} if Cell1 contains the value which you want to use as unique id of the row of the grid.
Now back to your main question. I recommend you to change format of the data from
{
"total": 1,
"page": "1",
"records": 1,
"rows": [
{
"Cell1": 1,
"Cell2": "stuff",
"Cell3": {
"date": "2013-06-02 10:56:00",
"timezone_type": 3,
"timezone": "UTC"
}
}
]
}
to
{
"total": 1,
"page": "1",
"records": 1,
"rows": [
{
"Cell1": 1,
"Cell2": "stuff"
}
],
"userdata": {
"1": {
"date": "2013-06-02 10:56:00",
"timezone_type": 3,
"timezone": "UTC"
}
}
}
I want comment my suggestion so that it could be clear for other users too. The column Cell1 contains the id. The structure of userdata which I suggest is the map from rowid (the value of Cell1) and the custom information which you need save as "Cell3" originally.
If you need somewhere in your code to have the "Cell3" value the code will be like below
onSelectRow: function (rowid) {
var cell3 = $(this).jqGrid("getGridParam", "userData")[rowid];
// now you can use cell3 which coniains the object like
// {
// "date": "2013-06-02 10:56:00",
// "timezone_type": 3,
// "timezone": "UTC"
// }
}
I have the following data strucutre outputting form my Schema in a node/express app. I'd like to have the feeds array simply an array of name:key pairs. I don't like the sort of weird numbered object structure going on between "feeds" and the actual feeds data. But i can't figure out how to manually define that in mongoose. any help would be awesome. thanks!
outputted JSON
{
"title": "Testing",
"created_at": "2011-10-05T16:23:26.217Z",
"feeds": [{
"0": {
"name": "twitter",
"key": "person1"
},
"1": {
"name": "twitter",
"key": "person2"
},
"_id": "4e8c847e02edc10035000003"
}]
}
i want this:
{
"title": "Testing",
"created_at": "2011-10-05T16:23:26.217Z",
"feeds": [
{
"name": "twitter",
"key": "person1"
},
{
"name": "twitter",
"key": "person2"
}
],
"_id": "4e8c847e02edc10035000003"
}
this is my schema:
var Feed = new Schema({
name : { type: String }
, key : { type: String }
});
var Page = new Schema({
title : { type: String, required: true, index: { unique: true } }
, feeds : [Feed]
, created_at : { type: Date, required: true, default: Date.now }
});
Ok, a colleague was able to answer this for me. My bad for not posting the relevant code, I didn't realize where the problem actually was. But for those who may encounter this problem:
If you push your embedded docs into the model when saving, you may need to do a forEach loop rather than pushing the embedded docs (in this case Feeds) together. Using forEach, the database saved the feeds directly to the feeds array rather than creating those weird groupings.
This pushed the feeds in properly:
req.body.feed.forEach(function(feed){
page.feeds.push(feed);
});
Let me know if you have the same problem and need more explanation.