Rendering columns of buttons within div - html

I have a list of languages, and I want to render them each as buttons within a column, within a div. I want to be able to render them based on a variable I set, buttonsPerColumn.
For example, if I have 40 languages, and four columns, I will render 10 buttons per column. If I have 36 languages, I will render 10 buttons for the first three, and 6 for the remainder. However, I am at a loss for how to do this. I have console logged my desired output, however, I would like this in button form. How can I create all of the column and button divs I need within my method, and then output them all at once?
css
.languageList {
position: absolute;
height: 35%;
width: 25%;
left: 43%;
top: 15%;
background-color: #b6bbf4;
display: flex;
justify-content: space-between;
}
.languageColumn {
position: relative;
width: 25%;
height: 100%;
background-color: red;
}
languagelist.jsx
class LanguageList extends Component {
render() {
this.renderButtons();
return (
<React.Fragment>
<div className="languageList">
<div className="languageColumn" />
</div>
</React.Fragment>
);
}
renderButtons = () => {
let buttonsPerColumn = 6;
const languages = LanguageList.getLanguages();
const myArray = LanguageList.arrayFromObject(languages);
var i, language;
let column = 0;
for (i = 0; i < myArray.length; i++) {
language = myArray[i];
console.log("Render " + language + " in column " + column);
if (i == buttonsPerColumn) {
column++;
buttonsPerColumn += buttonsPerColumn;
}
}
};
static arrayFromObject = object => {
var myArray = [];
var key;
for (key in object) {
myArray.push(key);
}
return myArray;
};
static getLanguages = () => {
return {
Azerbaijan: "az",
Albanian: "sq",
Amharic: "am",
English: "en",
Arabic: "ar",
Armenian: "hy",
Afrikaans: "af",
Basque: "eu",
German: "de",
Bashkir: "ba",
Nepali: "ne"
};
};
}
Link to code sandbox:
https://codesandbox.io/s/practical-chatelet-bq589

Try this:
import React, { Component } from "react";
class LanguageList extends Component {
render() {
return (
<React.Fragment>
<div className="languageList">{this.renderButtons()}</div>
</React.Fragment>
);
}
renderButtons = () => {
const buttonsPerColumn = 6;
const languages = LanguageList.getLanguages();
const myArray = LanguageList.arrayFromObject(languages);
const columns = [];
for (let i = 0; i < myArray.length; i++) {
const columnIndex = Math.floor(i / buttonsPerColumn);
if (!columns[columnIndex]) columns[columnIndex] = [];
columns[columnIndex].push(
<button className="languageButton">{myArray[i]}</button>
);
}
return columns.map((singleColumn, index) => (
<div key={index} className="languageColumn">
{singleColumn}
</div>
));
};
static arrayFromObject = object => {
var myArray = [];
var key;
for (key in object) {
myArray.push(key);
}
return myArray;
};
static getLanguages = () => {
return {
Azerbaijan: "az",
Albanian: "sq",
Amharic: "am",
English: "en",
Arabic: "ar",
Armenian: "hy",
Afrikaans: "af",
Basque: "eu",
German: "de",
Bashkir: "ba",
Nepali: "ne"
};
};
}
export default LanguageList;

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]));
}
});

setting defaultValue to p-multiselect

my code looks like below
export class LkBoardStatus {
id : number = 0;
descr : string = '';
}
component.ts
//...
lkBoardStatusList: LkBoardStatus[] = [];
selectedStatus: LkBoardStatus = new LkBoardStatus;
ngOnInit():void {
this.loadBoardStatusList();
../
}
loadBoardStatusList(){
this.boardService.loadBoardStatus().subscribe( posts =>{
this.data = posts;
console.log('loadBoardStatusList',this.data);
},
error => {
console.log('loadBoardStatusList - error',error);
this._errorService.handleError(error);
},
() => {
this.lkBoardStatusList = this.data.boardStatusLi;
for(let i=0; i<this.lkBoardStatusList.length; i++){
if(this.lkBoardStatusList[i].id == 70){
this.selectedStatus = this.lkBoardStatusList[i];
}
}
console.log(this.selectedStatus);
});
}
Here I have selectedStatus which is assigned a value of '70' as in for loop.
My comopnent.html is below
<th *ngSwitchCase="'statusObj'" [colSpan] = "2" style="text-align:center">
<p-multiSelect [options]="lkBoardStatusList" optionLabel="descr" [(ngModel)]="selectedStatus" defaultLabel="Select" (onChange)="dt.filter($event.value, col.field, 'in')"></p-multiSelect>
The inspect element gives me the correct object for selectedStatus but onLoad the value is not getting defaulted to 70. Where am I going wrong? Suggestions please.TIA
selectedStatus must be an array.
Try to replace
for(let i=0; i<this.lkBoardStatusList.length; i++){
if(this.lkBoardStatusList[i].id == 70){
this.selectedStatus = this.lkBoardStatusList[i];
}
}
with
this.selectedStatus = this.lkBoardStatusList.filter(item => item.id == 70);

state district json binding react

I want to display display list of districts from the json, receiving the following error
'TypeError: suggestion.districts.slice(...).toLowerCase is not a function'
json file.
How can I get the list of districts details, so that I can perform autocomplete using downshift?
any help appreciated.
json format
{
"states":[
{
"state":"Andhra Pradesh",
"districts":[
"Anantapur",
"Chittoor",
"East Godavari",
]
},
{
"state":"Arunachal Pradesh",
"districts":[
"Tawang",
"West Kameng",
"East Kameng",
]
},
}
component
import React, { Component } from 'react'
import statedist from "./StateDistrict.json";
const suggestions = statedist.states;
/*.... */
function getSuggestions(value, { showEmpty = false } = {}) {
// const StatesSelected=props.StatesSelected;
const inputValue = deburr(value.trim()).toLowerCase();
const inputLength = inputValue.length;
let count = 0;
//console.log(StatesSelected)
return inputLength === 0 && !showEmpty
? []
: suggestions.filter(suggestion => {
const keep =
count < 5 &&
suggestion.districts.slice(0, inputLength).toLowerCase() === inputValue;
if (keep) {
count += 1;
}
return keep;
});
}
function renderSuggestion(suggestionProps) {
const {
suggestion,
index,
itemProps,
highlightedIndex,
selectedItem
} = suggestionProps;
const isHighlighted = highlightedIndex === index;
const isSelected = (selectedItem || "").indexOf(suggestion.districts) > -1;
return (
<MenuItem
{...itemProps}
key={suggestion.districts[0]}
selected={isHighlighted}
component="div"
style={{
fontWeight: isSelected ? 500 : 400
}}
>
{suggestion.districts[0]} -- how can I get all the values instead of one here
</MenuItem>
);
}
class autoCompleteState extends Component {
constructor(props) {
super(props);
this.state = {
SelectedState:'',
}
// this.showProfile = this.showProfile.bind(this)
}
setSelectedDistrict = (newState) => {
this.setState({ SelectedState: newState });
console.log(newState)
this.props.onDistrictSelected(newState);
}
render() {
const { classes, } = this.props;
console.log(this.state.SelectedState)
const StatesSelected=this.props.StateList;
return (
<div>
<DownshiftMultiple
classes={classes}
setSelectedDistrict={this.setSelectedDistrict}
StatesSelected={StatesSelected}
/>
</div>
)
}
}
export default withStyles(Styles)(autoCompleteState);
I want the district details to come as suggestion like state in the below image
Currently, you are doing this:
suggestion.districts.slice(0, inputLength).toLowerCase() === inputValue;
This is throwing an error because .slice is copying inputLength items from your districts array and then trying to call .toLowerCase() on that array.
If I understand correctly, you are trying to filter your districts according to the inputValue. One way of doing this would be to use reduce on the districts array like this:
suggestion.districts.reduce((acc,curr)=>curr.substring(0,inputLength)===inputValue?[...acc,curr.substring(0,inputLength)]:acc, [])
If you only want the first 5 then you can slice the result of this:
suggestion.districts.reduce((acc,curr,index)=>index<5&&curr.substring(0,inputLength)===inputValue?[...acc,curr.substring(0,inputLength)]:acc, [])

Display only the first elements of Object.keys

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]);
}
});

Parsing JSON multi-level array

I want to search in json data with multiple levels of array. My search list return names of my objects but just from the first level. How could i do return all my object's names regardless their levels ?
In this example : OST, OST details, Apocalpse Now, Arizona Dream, Dexter
Data
<script type="application/json" id="dataMusic">
{
"name":"Music",
"level":"1",
"size":36184,
"children":[
{
"name":"OST",
"level":"2",
"size":1416,
"children":[
{
"name":"OST details",
"level":"3",
"size":1416,
"children":[
{
"name":"Apocalypse Now",
"size":15
},
{
"name":"Arizona Dream",
"size":19
},
{
"name":"Dexter",
"size":20
}
]
}
]
}
]
}
</script>
Function
var dataMusic = document.getElementById('dataMusic').innerHTML;
var dataTree = JSON.parse(dataMusic);
var optArray = [];
for (var i = 0; i < dataTree.children.length - 1; i++) {
optArray.push(dataTree.children[i].name);
}
optArray = optArray.sort();
I try this method Parsing Nested Objects in a Json using JS without success
Function
var optArray = [], Music, OST, OST details;
for (Music in dataTree) {
for (OST in dataTree[Music]) {
for (OST details in dataTree[Music][OST]) {
if (OST details in optArray) {
optArray[OST details].push(dataTree[Music][OST][OST details].name)
} else {
optArray[OST details] = [dataTree[Music][OST][OST details].name]
}
}
}
}
You must use nested loops
for Music.children.length
for OST.children.length
for OST details.children.length
Edit : Function
var optArray = [], Music, OST, OST_details;
for (Music in dataTree) {
for (OST in dataTree[Music]) {
for (OST_details in dataTree[Music][OST]) {
if (OST_details in optArray) {
optArray[OST_details].push(dataTree[Music][OST][OST_details].name)
} else {
optArray[OST_details] = [dataTree[Music][OST][OST_details].name]
}
}
}
}
I got it
var dataMusic = document.getElementById('dataMusic').innerHTML;
var dataTree = JSON.parse(dataMusic);
var result = [];
function getAll( input, target ) {
function parseData( input, target ) {
$.each( input, function ( index, obj ) {
if ( index == target ) {
result.push( obj );
}
else {
switch ( $.type( obj ).toLowerCase() ) {
case "object":
case "array":
parseData( obj, target );
break;
}
}
});
}
parseData( dataTree, "name" );
result = result.sort();
return result;
}
alert(JSON.stringify( getAll( dataTree, "name" )));
Thanks to this post :
Parsing multi-level json ; Demo