I have a JSON:
{
"menus": {
"main": {
"title": "Foo",
"buttons": {
"chooseSphere": "Btn #1",
"searchMaster": "Btn #2",
"balance": "Btn #3",
"settings": "Btn #3",
"help": "Btn #4",
"signUp": "Btn #5"
}
}
}
}
I have a function that should have autocomplete for buttons according to the menu key.
I have created an interface with generic where the type of key name should be the key of the menu buttons
export interface ISubmenu<T> {
name: keyof T;
template: MenuTemplate<Context>;
}
I have created a function that builds a submenu for one of the menus defined in the JSON object
export const createSubmenus = <K extends keyof typeof localeJSON.menus>(
menuKey: K,
options: Array<ISubmenu<typeof localeJSON.menus[K]['buttons']>>
) => {
const menuLocale = createMenuLocale(menuKey);
const submenus = [];
options.forEach((option) => {
submenus.push({
text: (context: Context) => menuLocale.getButton(context, option.name),
action: 'chooseSphere',
template: option.template,
});
});
return submenus;
};
The problem is that it cannot get the keys of specific menu buttons and an error happens in option.name (it should be the keys of main menu buttons)
The interface should take keys of the main menu buttons but it sees the type as a string
How can I improve the generics so it will allow me dynamically take keys for different menu buttons?
I was able to fix this by passing typeof menuKey parameter of the function to pass generic type into interface:
export const createSubmenus = (
menuKey: keyof typeof localeJSON.menus,
options: Array<ISubmenu<typeof localeJSON.menus[typeof menuKey]['buttons']>>
) => {
const menuLocale = createMenuLocale(menuKey);
const submenus = [];
options.forEach((option) => {
submenus.push({
text: (context: Context) => menuLocale.getButton(context, option.name),
action: 'chooseSphere',
template: option.template,
});
});
return submenus;
};
Related
I have an array of objects called "Options", that I use as a prop to a dropdown/select Material-UI component. I want to use the next-i18next library on the labels. I already implemented with success through all the next app just like the documentation explains. I tried using the {t('key')} and it doesn't allow.
import { useTranslation } from 'next-i18next'
const UsersPage = () => {
const { t } = useTranslation('user');
const Options = [
{ value: 'fullName', label: 'Nome' },
{ value: 'cpf', label: 'CPF' },
{ value: 'id', label: 'PadrĂ£o' },
]
...rest of the component
}
export const getStaticProps = async ({ locale }) => ({
props: {
...await serverSideTranslations(locale, ['user', 'home']),
},
})
export default UsersPage;
The msefer answer is right:
`${t("key")}`
inside JSON or string building in props like
const since = `${t('since')}`;
const until = `${t('until')}`;
...
<ListItemText
primary={value.name}
secondary={since + value.beginDate + until + value.endDate}
/>
I'm trying to access object inside an array of a JSONObject and print its values.
I'm able to print the array as JSONObject using console.log. But i fail to access the values inside the array which are again JSONObject format. Following is my my JSONObject
{
"id": 4,
"meta": {
"type": "pagetype",
"title": "Home"
}
},
"title": "Expose data to frontend",
"subtitle": "We will be exposing the content to the frontend",
"content": [
{
"type": "full_richtext",
"value": "<p><b>Bold body</b></p>"
},
{
"type": "button",
"value": {
"button_text": "Google",
"button_url": "https://google.com"
}
}
]
}
I need to access the values inside the array "content" and print values for
"value" -- Bold body --
"button_text"
"button_url"
I have tried it as follows
class App extends React.Component {
constructor() {
super();
this.state = {
'items': []
}
}
componentDidMount() {
fetch('http://localhost:8000/api/v2/pages/4/')
.then(results => results.json())
.then(results => this.setState({ 'items': results }));
}
render() {
var contents_from_wagtail = this.state.items;
var streamfield_content_array = contents_from_wagtail.content;
console.log(streamfield_content_array); //prints array of objects
return (
<React.Fragment>
<p>{this.state.items.subtitle}</p>
<p>{this.state.items.title}</p>
/* print the values for
"value" -- Bold body --
"button_text"
"button_url"
*/
</React.Fragment>
);
}
}
export default App;
When showing an array of items the .map method can be used to create multiple elements:
class App extends React.Component {
constructor() {
super();
this.state = {
'items': {}
}
}
componentDidMount() {
fetch('http://localhost:8000/api/v2/pages/4/')
.then(results => results.json())
.then(results => this.setState({ 'items': results }));
}
render() {
var contents_from_wagtail = this.state.items;
var streamfield_content_array = contents_from_wagtail.content || [];
console.log(streamfield_content_array); //prints array of objects
return (
<React.Fragment>
<p>{this.state.items.subtitle}</p>
<p>{this.state.items.title}</p>
{streamfield_content_array.map((item, index) => {
return <div key={index}>type: {item.type} <p>{item.value}</p></div>
})}
</React.Fragment>
);
}
}
export default App;
More .map examples: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
To access it within the render you have to access it conditional because it is not set for the first render until the fetch call is Executed
That is why you have to provide some fallback until the array is loaded.just check if the item is undefined and return null for example.
Only if the array is filled render the desires output and it should be fine.
Hope this helps. Happy coding.
You could use a combination of .map() and .filter() to iterate over the items within the content array. It looks like you only want to display items that have a type of button. So try something like this:
class App extends React.Component {
constructor() {
super();
this.state = {
'items': []
}
}
componentDidMount() {
fetch('http://localhost:8000/api/v2/pages/4/')
.then(results => results.json())
.then(results => this.setState({ 'items': results }));
}
render() {
var contents_from_wagtail = this.state.items;
var streamfield_content_array = contents_from_wagtail.content;
var buttonContent = this.state.items ? this.state.items.content.filter((item) => item.type == "button") : null
return (
<React.Fragment>
<p>{this.state.items.subtitle}</p>
<p>{this.state.items.title}</p>
{ buttonContent && buttonContent.map(item => (
<div>
<p>{item.button_text}</p>
<p>{item.button_url}</p>
</div>
))}
</React.Fragment>
);
}
}
export default App;
How can I traverse through my data structure and create React components?
{
component: "View",
attributes: {
id: 'main'
},
child: [
{
component: "Text",
content: "Hello World!"
},
{
component: "Link",
attributes: {
href: "#"
},
child: [
{
component: "Text",
content: "Click me!"
}
]
}
]
}
Would output:
<View>
<Text>Hello World!</Text>
<Link>Click me!</Link>
</View>
How can I dynamically achieve this where it works regardless of the number of nested components?
I am able to make the top level component, but traversing through the child elements is where I hit a brick wall.
You can create a function that calls itself.
Sample
parseComponents = (data, key) => {
if (key === undefined || key === null) key = 0;
let Component = null;
switch(data.component) {
case 'View':
Component = View;
break;
case 'Text':
Component = Text;
break;
case 'Link':
Component = Link;
break;
default:
break;
}
if (Component === null) return Component;
return (
<Component key={`${data.component}-${index}`} {...data.attributes}>
{data.child.map((c, index) => this.parseComponents(c, index))}
</Component>
)
}
You can do like sample below:
Let's say your JSON is stored in const json.
getComponent = (json) => {
if (json.component) {
let children;
if (json.children) {
children = json.children.map(child => this.getComponentEquivalent(child));
}
let Container= this.getComponentEquivalent(json);
return (<Container>{children}</Container>); // as this will return a component you can directly put this in render.
}
};
then you may have a function that you could get equivalent component.
getComponentEquivalent = (object) => {
switch(object.component) {
case "Text":
return <Text>{object.content}</Text>
case "Link"":
return <Link>{object.content}</Link>
//......./
default:
//..../
}
};
I'm currently trying to take some JSON data that I've received from an API and put that into a dropdown in a very simple React application.
This is my DropDown component thus far:
import React from 'react';
var values;
fetch('http://localhost:8080/values')
.then(function(res) {
return res.json();
}).then(function(json) {
values = json;
console.log(values);
});
class DropDown extends React.Component {
render(){
return <div className="drop-down">
<p>I would like to render a dropdown here from the values object</p>
</div>;
}
}
export default DropDown;
Any my JSON looks like this:
{
"values":[
{
"id":0,
"name":"Jeff"
},
{
"id":1,
"name":"Joe"
},
{
"id":2,
"name":"John"
},
{
"id":3,
"name":"Billy"
},
{
"id":4,
"name":"Horace"
},
{
"id":5,
"name":"Greg"
}
]
}
I'd like the dropdown options to correspond to the 'name' of each element, and the 'id' to be used as an element identifier when an event is triggered by selecting an option. Any advice on getting this data into a dropdown which responds to user input would be greatly appreciated.
Call the API in componentDidMount lifecycle function of your React component and then save the response in state and then render the Select dropdown
import React from 'react';
class DropDown extends React.Component {
state = {
values: []
}
componentDidMount() {
fetch('http://localhost:8080/values')
.then(function(res) {
return res.json();
}).then((json)=> {
this.setState({
values: json
})
});
}
render(){
return <div className="drop-down">
<p>I would like to render a dropdown here from the values object</p>
<select>{
this.state.values.map((obj) => {
return <option value={obj.id}>{obj.name}</option>
})
}</select>
</div>;
}
}
export default DropDown;
You could do something like this:
import React from 'react';
var values;
class DropDown extends React.Component {
constructor(){
super();
this.state = {
options: []
}
}
componentDidMount(){
this.fetchOptions()
}
fetchOptions(){
fetch('http://localhost:8080/values')
.then((res) => {
return res.json();
}).then((json) => {
values = json;
this.setState({options: values.values})
console.log(values);
});
}
render(){
return <div className="drop-down">
<select>
{ this.state.options.map((option, key) => <option key={key} >{option}</option>) }
</select>
</div>;
}
}
export default DropDown;
Basically you are initializing state and setting options to null.
You are then fetching your options when the component mounts in the browser. These values are set to your state with this.setState().
Note: It is important to make any API calls in componentDidMount() and not componentWillMount(). If you call it in componentWillMount() the request will be made twice.
Then you render these options by mapping them in your render function
JSON FILE: terrifcalculatordata.json
[
{
"id": 1,
"name": "Vigo",
},
{
"id": 2,
"name": "Mercedes",
},
{
"id": 3,
"name": "Lexus",
},
{
"id": 4,
"name": "Buggati",
},
]
CODE:
1st import json file on top:
import calculatorData from "../static/data/terrifcalculatordata.json";
2nd in render method type this code:
<Form>
<FormGroup>
<Input
type="select"
onChange = {this.changeCarmodel}
value={this.state.changeCar}
>
{calculatorData.map((caldata, index) =>
<option
key={index}
value= {caldata.id}
> {caldata.name} </option>
)}
</Input>
</FormGroup>
</Form>
How to render JSON response as dropdown list in React.
export default class ExpenseNew extends Component {
constructor(){
super();
this.state={
PickerSelectedVal : '',
accountnameMain:[],
}
}
componentDidMount(){
var account_nam=[]
fetch('your Url', {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + your token }
})
.then((response) => response.json())
.then((customerselect) => {
// alert(JSON.stringify(customerselect))
global.customerdata = JSON.stringify(customerselect)
var customername = JSON.parse(customerdata);
//alert(JSON.stringify(customername));
for (i = 0; i < customername.cus_data.length; i++) {
var dataa = customername.cus_data[i]["account_name"];
account_nam.push(dataa)
}
this.setState({accountnameMain:account_nam});
})
.done();
}
render() {
return (
<Picker
selectedValue={this.state.PickerSelectedVal}
placeholder="Select your customer"
mode="dropdown"
iosIcon={<Icon name="arrow-down" />}
onValueChange={(itemValue, itemIndex) => this.setState({PickerSelectedVal: itemValue})} >
{this.state.accountnameMain.map((item, key)=>(
<Picker.Item label={item} value={item} key={key}/>)
)}
</Picker>
)
}
}
What I need to do is when i enters text inside textbox , i need to filter result inside li
I need do same as here
but this is done using ajax and i need to do using angular2 with data loading from .json file
my index.html is
<div id="search-container">
<div class="search" id="search-btn"></div>
<input #searchBox id="search" type="text" name="search-input" (keyup)="search(searchBox.value)">
<ul class="data-ctrl">
<li ng-repeat="i in items >i[0].name</li>
</ul>
</div>
My app.component.ts is
constructor(public http: Http,public _dmcService: DmcService) {
this._dmcService.getData('prc').subscribe(
data => { this.listingval= "prc"; this.assignJson(data); }
);
}
assignJson function from app.component.ts:
here i assigned data to heroes which is loaded from json file
assignJson(data: any) {
displayContent= data.teacher[0].libraryItems;
for (var i = 0; i <displayContent.length; i++) {
this.heroes[i] = [
{ id: i, name: data.teacher[0].libraryItems[i].display_title.slice(30)}
];
}
}
dmc.service.ts:
getData(filename: string) {
return this.http.get('assets/data/' + filename + '.json').map((res: Response) => res.json());
}
prc.json:
{
"isbn": "9781328694829",
"teacher": [
{
"component": "Core Resources",
"libraryItems": [
{
"id": "9781328694829-00001",
"display_title": "Practice- Ungroup from the Left or from the Right"
},
{
"id": "9781328694829-00002",
"display_title": "Reteach- Ungroup from the Left or from the Right",
}
]
}
}
search function in app.component.ts:
search(term: string): void {
this.searchTerms.next(term);
}
ngOnInit(): void {
let heroes: Observable<Hero[]>;
this.heroes = this.searchTerms
.debounceTime(300) // wait for 300ms pause in events
.distinctUntilChanged() // ignore if next search term is same as previous
.switchMap(term => term // switch to new observable each time
// return the http search observable
? this.heroSearchService.search(term)
// or the observable of empty heroes if no search term
: Observable.of<Hero[]>([]))
.catch(error => {
// TODO: real error handling
console.log(error);
return Observable.of<Hero[]>([]);
});
}
my heroesSearchService is as
#Injectable()
export class HeroSearchService {
constructor(private http: Http) {}
search(term: string): Observable<Hero[]> {
console.log('term:: ',term);
var str = this.http.get(`app/heroes/?name=${term}`)
.map((r: Response) => r.json().data as Hero[]);
return str;
}
}
export class Hero {
id: number;
name: string;
}
my current code not working, can anyone please help me with this.