Display only the first elements of Object.keys - json

I have made a JSON Request so i can bring the Objects in Angular2. But I want to display only the first 15 elements and then if it works repeat the same process on InfiniteScroll. So this is one of my code.
setList(informes) {
if (informes) {
for (let id of Object.keys(informes)){
this.count = 0;
for (let i = 0; i < 15; i++) {
let node = informes[id];
this.informes.push(node[this.count]);
console.log (id);
this.count++;
}
}
}
}
Obviously It doesn't work, it keeps giving me all elements like 15 times each. I know that but on the other hand if i make the opposite.
setList(informes) {
if (informes) {
for (let i = 0; i < 15; i++) {
for (let id of Object.keys(informes)){
let node = informes[id];
this.informes.push(node[this.count]);
console.log (id);
}
this.count++
}
}
}
It counts the number of nodes in total.
What i want is to display only the first 15 elements. And then repeat the code in my other function infiniteScroll (I will do that by myself, it works).
Any suggestion will be appreciated.
UPDATE:
Here's the constructor:
constructor(public navCtrl: NavController, public navParams: NavParams, public nav: NavController, public http: Http, public sanitizer: DomSanitizer) {
this.dataUrl = 'https://myurl.com/ionic/'; //example
if (this.dataUrl) {
this.http.get(this.dataUrl)
.map(res => res.json())
.subscribe(informes => this.setList(informes));
}
}
UPDATE 2:
The code works well.
I had to modify some things to make it work. I will update the script so if it could help someone.
setList(informes) {
if (informes) {
let ids = Object.keys(informes);
ids.forEach((id, index) => {
if(index < 15){
let node = informes[id];
this.informes.push(node);
this.count++;
console.log(this.count);
}
});
}
}
goToNodeInformes(node){
this.navCtrl.push(NodeInformesPage, {'node':node.nid});
}
doInfinite(infiniteScroll, informes) {
informes = this.informes;
setTimeout(() => {
let ids = Object.keys(informes);
ids.forEach((id, index) => {
if(index < 15){
let node = informes[id];
this.informes.push(node);
this.count++;
console.log(this.count);
}
});
infiniteScroll.complete();
}, 500);
}
}
I will figure what i have to do for not repeating the same nodes (will update) but the counter works!!!

I think you are looking for something like this :
let keys = Object.keys(informes);
keys.foreach((key, index) => {
if(index < 15){
let node = informes[key];
this.informes.push(node);
console.log(informes[key]);
}
});

Related

How do I do a recursion over objects of unknown depth in Typescript?

I have a JSON file with a category structure of unknown depth. I want to make sure all pages can be accessed. I established three nested calls, but I think it would be better to recursion here. Unfortunately, I have no experience with Typescript regarding recursion. Can someone be so kind as to help me put the logic into a function I can call?
test.setTimeout(28800000); // 8 hours max.
// console.log(ofcJSON)
for (let i = 0; i < ofcJSON.items.length; i++) {
let currentPage = ofcJSON.items[i].link
console.log(currentPage)
if (!currentPage.startsWith("http")) await page.goto(currentPage)
if (ofcJSON.items[i].items != null) {
for (let j = 0; j < ofcJSON.items[i].items!.length; j++) {
let currentPage1 = ofcJSON.items[i].items![j].link
console.log(currentPage1)
if (!currentPage1.startsWith("http")) await page.goto(currentPage1)
if (ofcJSON.items[i].items![j].items != null) {
for(let k = 0; k < ofcJSON.items[i].items![j].items!.length; k++) {
let currentPage2 = ofcJSON.items[i].items![j].items![k].link
console.log(currentPage2)
if (!currentPage2.startsWith("http")) await page.goto(currentPage2)
if (ofcJSON.items![i].items![j].items![k].items != null) {
for(let l = 0; l < ofcJSON.items[i].items![j].items![k].items!.length; l++) {
let currentPage3 = ofcJSON.items[i].items![j].items![k].items![l].link
console.log(currentPage3)
if (!currentPage3.startsWith("http")) await page.goto(currentPage3)
}
}
}
}
}
}
}
});
The JSON has 1 items object, which in turn can have 1 items object. This is optional. I don't know the depth.
I sketched an implementation which compiles and runs in the typescript playground as below (click on Run top left in the playground)...
type HttpLink = `http{'s'|''}://${string}`;
function isHttpLink(link: string): link is HttpLink {
return !!link.match(/^https?:\/\//);
}
type Link = HttpLink | string;
interface Item {
link: Link;
items?: Item[];
}
async function goto(link: HttpLink) {
console.log(`Ran goto on ${link}`);
}
async function visitItemAndDescendants(ancestor: Item) {
const { link, items } = ancestor;
if (isHttpLink(link)) {
await goto(link);
}
if (items) {
for (const item of items) {
visitItemAndDescendants(item);
}
}
}
{
const exampleItem: Item = {
link: "https://my.url",
items: [
{
link: "not http",
items: [
{
link:"http://insecure.url"
},
{
link:"https://another.url"
}
],
},
],
};
visitItemAndDescendants(exampleItem)
}
Thanks to your help and the help of a colleague I have solved the problem as follows:
import { Page, test } from '#playwright/test';
import fetch from "node-fetch";
test.use({
baseURL: "https://www.myUrl.de/"
})
const links: string[] = [];
interface Item {
link: string;
items?: Item[];
}
async function getLinks(item: Item): Promise<void> {
if (item.items && item.items.length > 0) {
for (let i = 0; i < item.items.length; i++) {
let currentItem = item.items[i];
if (currentItem.link && currentItem.link.length > 0) {
links.push(currentItem.link);
if (currentItem.items && currentItem.items.length > 0)
getLinks(currentItem);
}
}
}
}
test('test', async ({ page }) => {
test.setTimeout(1560000); // 26 minutes max.
const ofcJSON = await fetch('https://www.myUrl.de/ofcJSON')
.then((response) => response.json())
.then((item) => {
return item.items
})
// console.log(ofcJSON);
ofcJSON.forEach(element => {
getLinks(element);
});
var maximumNumberOfLinksToCheck = 10;
var delta = Math.floor(links.length / maximumNumberOfLinksToCheck);
for (let i = 0; i < links.length; i = i + delta) {
console.log("Checking page: " + links[i])
await (page.goto(links[i]));
}
});

I'm trying to create a memory game where an expanding list of numbers is shown in ionic and angular and the user has to type in the answer

The way that I am doing it is that I want each of the numbers to appear then disappear. I have tried a lot of options but only the last number ends up showing when there are two or more numbers in the array. I suspect it has something to do with the for loop, but there does not seem to be a way around it.
Here is my typescript code for the generate numbers function:
generateNumbers() {
let numbersArray = new Promise<number[]>((resolve, reject) => {
let numberArray: number[] = []
for (let i = 0; i < this.level; i++) {
this.animationCtrl.create()
.addElement(this.currentNum.nativeElement)
.duration(500)
.iterations(1)
.fromTo('opacity', '1', '0.05').play()
.then(func => {
let randomnum = Math.floor(Math.random() * 9)
numberArray.push(randomnum)
this.currentIndex = i
this.currentNumber = randomnum
this.parsedCurrentNumber = JSON.parse(JSON.stringify(this.currentNumber))
}).then(func => {
this.animationCtrl.create()
.addElement(this.currentNum.nativeElement)
.duration(500)
.iterations(1)
.fromTo('opacity', '0.05', '1').play()
}).then(func => {
if (i === this.level - 1) {
resolve(numberArray)
}
})
}
})
return numbersArray
}
Here are my variable declarations and injections:
#ViewChild('currentNumber', { read: ElementRef, static: true}) currentNum: ElementRef;
level: number = 1;
levelExp: number = 1;
gameHasBegun = false;
paused = false;
numbersArray: number[] = [];
answer: string;
wrongcount: number = 0;
wrong = false;
lost = false;
currentIndex: number = 0
currentNumber: number;
parsedCurrentNumber: string;
constructor(
private router: Router,
private menu: MenuController,
private animationCtrl: AnimationController ) { }
Here is how I call my generate function:
this.generateNumbers().then(
(val) => this.numbersArray = val
)
Here is my HTML Code for the part where the numbers should be shown, but instead only one number is shown when I have two or more numbers in my array:
<ion-content #currentNumber>
<ion-label class="ion-text-center" >
<h1>{{ parsedCurrentNumber }}</h1>
</ion-label>
</ion-content>
Look at the following stackblitz.
https://stackblitz.com/edit/ionic-79e1rn
You basically need to loop through your array with a timeout.
ionViewDidEnter(){
this.runSeries(0);
}
runSeries(i){
if(i < this.nums.length){
setTimeout(() => {
this.lastNum = this.nums[i];
i++;
this.runSeries(i);
}, 1000)
}
}
and bind lastNum in your template.

Fetch URI from Post Data through Get Data

Show 1 textfield with 2 buttons - Post, Get. Take a number as input in a text field. On clicking Post, create an array of the numbers from 1 to that number. Post this array at the URL. Display the response from the Post.On clicking Get, fetch data from the URL returned by the Post and display it.
urlPost = 'https://api.myjson.com/bins';
clist: number[] = [];
strData: string = '';
S1: String = '';
ntext: number;
constructor(private netService: NetService) {}
postData() {
for (var i = 1; i <= this.ntext; i++) {
this.clist.push(i);
}
this.netService.postData(this.urlPost, this.clist)
.subscribe(postresp => {
this.strData = JSON.stringify(postresp);
});
}
getData() {
this.netService.getData(this.strData.Uri)
.subscribe(resp => {
this.strData = JSON.stringify(resp);
});
}
this line need to be improved.
this.netService.getData(this.strData.Uri)
As I understand your question, you simply have a problem with parsing a response from your postData(). So, just refer to the following -
postData() {
for (var i = 1; i <= this.ntext; i++) {
this.clist.push(i);
}
this.netService.postData(this.urlPost, this.clist)
.subscribe(postresp => {
this.S1 = postresp['uri']; // get URL here
});
}
getData() {
this.netService.getData(this.S1) // use it here
.subscribe(resp => {
this.strData = JSON.stringify(resp);
});
}
See it working here.

How to wait to finish subscribe before moving to next index in for loop in Angular 6

I'm using Angular 6.
I have an array of links and a variable to store fetched information in same order as of array one by one.
Here is what I'm trying to do using for loop.
products: any;
processedItems: Array<any> = [];
private _processItem() {
for (let i = 0; i < this.products.length; i++) {
this.scraperService.scrapSingle(this.products[i].url).subscribe(
res => {
if (res.status.http_code === 200) {
const properties = this.scraperService.processSingleProduct(res.contents);
const p_item = {};
p_item['info'] = this.products[i];
p_item['properties'] = properties;
this.processedItems.push(p_item);
}
console.log(res);
}
);
}
console.log(this.products.length);
}
But how to wait for subscribe before moving to next index in the loop?
Just splice the p_item into your array at the required index given i.
For example instead of doing,
this.processedItems.push(p_item);
do this,
this.processedItems.splice(p_item, 0, i);
That solves your problem :)
Use promises instead of rx.js subscriptions via using toPromise method. You might need to map the res to json. res.map(item => item.json());
products: any;
processedItems: Array < any > =[];
private _processItem() {
this.products.array.forEach(async (element) => {
const res = await this.scraperService.scrapSingle(element.url).toPromise();
if (res.status.http_code === 200) {
const properties = this.scraperService.processSingleProduct(res.contents);
const p_item = {};
p_item['info'] = element
p_item['properties'] = properties;
this.processedItems.push(p_item);
}
console.log(res);
});
console.log(this.products.length);
}

Filtering an observable in Angular/Nativescript

Currently, I'm trying to build an app which retrieves an obserable, which you can then sort and/or filter in some predefined ways.
Retrieving and sorting the data works fine:
sort.service.ts
import { Injectable } from "#angular/core"
import { HttpClient, HttpErrorResponse } from "#angular/common/http"
import { Observable } from "rxjs/Observable";
import { Subscriber } from "rxjs";
import "rxjs/add/operator/catch";
import "rxjs/add/operator/do";
import "rxjs/add/operator/map";
import { Property } from "../property/property.model";
import { UserSettings } from "../../data/usersettings/usersettings.service"
export class SortService {
url = "/path/to/file.json";
constructor(private http:HttpClient) {}
getProperties(): Observable<Property[]> {
return this.http.get<Property[]>(this.url);
}
sortAllProperties() {
let count = 0;
return this.getProperties()
.map((data) => {
data.sort((a: Property, b: Property) => {
const aP = a.price;
const bP = b.price;
const aS = a.areaSize;
const bS = b.areaSize;
const aR = a.numberOfRooms;
const bR = b.numberOfRooms;
const aB = a.numberOfBedrooms;
const bB = b.numberOfBedrooms;
/*if(this.userSettings.getAppSetting("filterMinPrice", "number") >= a.price)
console.log(a.price + " is smaller than " + this.userSettings.getAppSetting("filterMinPrice", "number"));*/
const aID = a.ID;
const bID = b.ID;
//Price sort (primary)
const priceSort = this.userSettings.getAppSetting("sortByPrice", "string");
if(priceSort == "asc") {
if (aP > bP) return 1;
if (aP < bP) return -1;
} else if (priceSort == "desc") {
if (aP < bP) return 1;
if (aP > bP) return -1;
} else {
count++;
}
//Areasize sort (secondary)
const sizeSort = this.userSettings.getAppSetting("sortBySize", "string");
if(sizeSort == "asc") {
if (aS > bS) return 1;
if (aS < bS) return -1;
} else if (sizeSort == "desc") {
if (aS < bS) return 1;
if (aS > bS) return -1;
} else {
count++;
}
//Rooms sort (tertiary)
const roomSort = this.userSettings.getAppSetting("sortByRooms", "string");
if(roomSort == "asc") {
if (aR > bR) return 1;
if (aR < bR) return -1;
} else if (roomSort == "desc") {
if (aR < bR) return 1;
if (aR > bR) return -1;
} else {
count++;
}
//Bedrooms sort (quaternary)
const bedroomSort = this.userSettings.getAppSetting("sortByBedrooms", "string");
if(bedroomSort == "asc") {
if (aB > bB) return 1;
if (aB < bB) return -1;
} else if (bedroomSort == "desc") {
if (aB < bB) return 1;
if (aB > bB) return -1;
} else {
count++;
}
if(count = 4) {
return aID > bID ? 1 : -1;
}
})
return data;
})
}
}
The data being retrieved here, looks like this:
file.json
[
{
"ID": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing ...",
"price": 800.25,
"agreementType": "unknown",
"streetName": "street1",
"houseNumber": 249,
"postCode": "postcode",
"place": "New Orlands",
"status": "status",
"constructionYear": 1999,
"areaSize": 5540,
"numberOfRooms": 545,
"numberOfBedrooms": 21,
"garageType": "",
"garageCapacity": 0
},
{
//...
}
]
and the property model, which the JSON format "adheres" to, looks as follows...
property.model.ts
export class Property {
ID: number;
description: string;
price: number;
agreementType: string;
streetName: string;
houseNumber: number;
postCode: string;
place: string;
status: string;
constructionYear: number;
areaSize: number;
numberOfRooms: number;
numberOfBedrooms: number;
garageType: string;
garageCapacity: number;
}
I'm displaying my data in the property component simply using an async pipe, which works just fine: *ngFor="let item of propertyData | async". The sorting works as well. It's the filtering I have an issue with.
For now, I'm simply trying to apply a static filter inside the sortAllProperties() method. Making it dynamic and giving it its own class, methods etc can come later.
It's also hard finding the exact right information for this, because most of it is outdated and uses http rather than httpClient, which is of course slighty different.
Every attempt I've made so far (all copied from internet examples and slightly adjusted to fit my use-case) resulted in an error. The closest I got so far is .filter((property) => property.price > 800) which I tried placing in front of, and later after the .map() function, both resulting in the same error:
[ts] Property 'price' does not exist on type 'Property[]'.
Could it be that I'm missing some functions I should use on the observable before filtering? I'm really at a loss right now.
Thank you in advance.
With the help of another programmer, I finally managed to get the solution. As usual, it turned out to be pretty simple:
return this.getProperties()
.map(properties => properties.filter(property=> property.price > 810)
.sort((a: Property, b: Property) => {
//sorting stuff
})
That's for one filter. If you want to apply multiple filters, you could probably do something like
return this.getProperties()
.map(properties => properties.filter((property) => {
//filter coniditions, arrays etc
return property;
})
.sort((a: Property, b: Property) => {
//sorting stuff
})