How to get nested json with dynamic value - json

I want to access json with a value in input.
My function and json
import pet3 from '../../utils/pet3' //my json file
const getValueFromJson = (value) => {
const data = pet3
console.log(data.components) //it works fine
console.log(data.value) // it is undefined
}
getValueFromJson("components")

You can access the object keys dynamically by using the square brackets:
import pet3 from "../../utils/pet3"; //my json file
const getValueFromJson = (value) => {
const data = pet3;
console.log(data[value]);
};
getValueFromJson("components");
Edit:
Alternately, you can install and use a 3rd party library like lodash which provides the _.get() method that can be used like this:
import get from "lodash/get"; // if not installed, run `npm install lodash --save-dev`
const getValueFromJson = (value) => {
const data = pet3;
console.log(get(data, value, "default value")); /* returns "default value" if key is undefined. */
};
getValueFromJson("components.filename");

Related

Firestore data() method does not exist on JSON parsed document after JSON stringified

I am building a FlashCard website using NextJs and firebase. I have a homepage which I want to render server side and so I am using getServerSideProps. InsidegetServerSideProps function, I am fetching all the documents of the current user from firestore and is stored in an array and is returned as props as below:
export const getServerSideProps = async(ctx: GetServerSidePropsContext) {
let notes: DocumentData[];
// fetch documents here and populate notes array like so [doc,doc,doc,..]
// data() method works here and returns document fields
console.log(notes[0].data());
// NextJs throws error "`object` ("[object Object]") cannot be serialized as JSON. Please only return JSON serializable data types.", so I have to JSON.stringify() the notes
return {
props: {
notes: JSON.stringify(notes),
}
}
}
Below, I have my homepage where I parse the JSON string and have access to the notes, but now the data() method on the document does not exist/works and throws method does not exist errors. If I have to access the document fields, I have to use the dot operator on every property of the document till I reach the fields property which is nested deep down in the object as follows:
export default function Home({ notes }) {
let docs = JSON.parse(notes); // can access notes
// data() method throws function does not exist error
console.log(docs[0].data());
// I am only able to access document fields as below
console.log(docs[0]._document.data.value.mapValue.fields);
return (
<Layout>
<HomeContent notes={docs}/>
</Layout>
);
}
I have searched everywhere and found nothing that helped me why data() method won't work. If I directly fetch the documents inside the page component on client side, the data() method on the document returns its' fields. I don't know how using JSON serializations affect it. I would always prefer to use data() method to access fields than to go that deep plus I am planning to fetch data on server on other pages as well.
I would really appreciate if you can shed some light on it. It took all of my days time.
EDIT: The code that gets notes from firestore:
// inside getServerSideProps
let notes: DocumentData[] = null;
const getNotes = async(ref: DocumentReference < DocumentData > , uid: string) => {
let tempNotes = [];
const categoriesSnapshot = await getDoc < DocumentData > (ref);
const categoriesObject = categoriesSnapshot.data();
// return if user doesn't have any documents
if (!categoriesObject) {
return;
}
const promises: [] = categoriesObject.categories.map((category: string) => {
const userCategoriesRef = collection(database, 'CategoryCollection', uid, category);
return getDocs(userCategoriesRef); // returns a promise
});
const allQuerySnapshots = await Promise.all < DocumentData > (promises);
allQuerySnapshots.forEach((querySnapshot) => {
tempNotes.push(...querySnapshot.docs);
});
notes = tempNotes;
}
const categoryDocRef = doc(database, "CategoryCollection", uid);
await getNotes(categoryDocRef, uid);

fetch the text of my application from the server

I want to change all the static text in my app with a text from a server so I have to fetch this text in LoadingScreen and then export it to use it in other screens
<Text>My products</Text> to <Text>{constants.myProduct}</Text> after import constant from LoadingScreen
How to export the json response from LoadingScreen to all the other Screen ?
there is another approach ?
PS. I don't use Redux
The simplest way, but not the best, is just create and export variable with all text keys. For example:
// text.utils.js
let _textData;
export const loadTextData = () => fetch(YOUR_SERVER)
.then((r) => r.json())
.then(r => _textData = r);
export const getTextData = (key, defaultValue) => _textData[key] || defaultValue;
// init inside App or something else
import {loadTextData} from 'text.utils.js';
componentDidMount() {
loadTextData();
}
// inside components
import {getTextData} from 'text.utils.js';
const myProductText = getTextData('myProduct', 'This is product text');
const myProductCountText = getTextData('myProductCount', 'This is product count text');
<Text>{myProductText}</Text>
<Text>{myProductCountText}</Text>
P.S. It's not a good solution for react. The best choice is create a context or hook, that will provide strings to your components. Also if your string object has nested objects, you may reorganise getTextData function

Angular 8 - copy to clipboard a JSON Object

I have a JSON response I get from backend which I'm displaying as {{ response | json }}. There's a copy to clipboard option where i need to copy the contents of response. I have the following code
copy(response){
let val = response;
const selBox = document.createElement('textarea');
selBox.style.position = 'fixed';
selBox.style.left = '0';
selBox.style.top = '0';
selBox.style.opacity = '0';
selBox.value = val;
document.body.appendChild(selBox);
selBox.focus();
selBox.select();
document.execCommand('copy');
document.body.removeChild(selBox);}
This copies as [object object] since response is an object. I can copy it converting the response to a string as let val = JSON.stringyfy(response) . But this does not copy it in a formatted way I display it, instead copies the json in one single line like a string. So how to copy to clipboard a JSON object in a proper formatted way?
There is a built-in Clipboard class in the angular cdk that makes this a little easier to do. You should also use the space parameter with your JSON.stringify
First npm install the #angular/cdk package if you don't have it already.
In your #NgModule import ClipboardModule
import { ClipboardModule } from '#angular/cdk/clipboard';
#NgModule({
imports: [
ClipboardModule
],
})
In your component's typescript file import the Clipboard class
import { Clipboard } from '#angular/cdk/clipboard';
#Component({ /* ... */ })
export class MyComponent {
constructor(private clipboard: Clipboard) { }
public copy() {
// replace this object with your data
const object = {abc:'abc',xy:{x:'1',y:'2'}}
// Note the parameters
this.clipboard.copy(JSON.stringify(object, null, 2));
}
}
In your component's template
<button (click)="copy()">
Copy Data
</button>
The result of stringifying {abc:'abc',xy:{x:'1',y:'2'}} when pasted:
{
"abc": "abc",
"xy": {
"x": "1",
"y": "2"
}
}
With reference to the answer linked by x4rf41, you can make your stringify function whitespace your JSON with let val = JSON.stringify(response,null,2). If you want syntax highlighting, you can use user123444555621's function.
A much neater way to copy text is to add an event listener for the copy event, and set the clipboardData dataTransfer object:
window.addEventListener('copy', (event) => {
if(copying){
let val = JSON.stringify(response,null,2);
event.preventDefault(); //stop the browser overwriting the string
event.clipboardData.setData("text/plain",val); //encode the appropriate string with MIME type "text/plain"
copying = false;}
});
copy = function (){
copying = true;
document.execCommand('copy');}
If you are using the afore-mentioned syntax highlighting function, you probably want to specify MIME type "text/html". Hopefully the formatting options in the linked answer suit your needs.

React constant with parameters using square brackets

I'm new to React.
I have the code below with a function, but when I run it, it returns an error:
TypeError: renderJson[item.node] is not a function.
How can I fix the renderJson function?
export const readItem = item => {
printlog(item);
return renderJson[item.node](item);
};
const renderJson = {
"heading": item => <h1>{item.map(item => readItem(item))}</h1>
};
If you're trying to create a single React functional component that takes a JSON, and outputs the items in the JSON as a header, it would be more like this:
// If you're getting this JSON from an external source using something like a GET request, put the request inside a "useEffect()" hook
const myJson = {
"heading": ["My First Header", "My Second Header"]
};
export const Header = () => {
console.log(myJson);
return <h1>{myJson.heading.map(header => header}</h1>
};
I apologize if this is a misinterpretation of your question. If it is, any additional details would be helpful.

Iterate through Vue component fields

I have a Vue component with lots of properties (> 40). It is a form for editing some business entity. The flow is the following:
On mounted() load the data as json from server and initialize component properties
Edit the data as required
Put all the properties into json structure and send back to server to update data
The properties in my component are named exactly the same as in json structure. I want to iterate through properties in my component and create json structure with 1 line of code instead of doing something like this:
var data = {
field1 = this.field1,
field2 = this.field2,
field3 = this.field3
...
field40 = this.field40
}
I use TS and vue-class-component, so the component code looks like this:
import Vue from 'vue'
import Component from 'vue-class-component'
#Component({
template: ...
})
export default class MyComponent extends Vue {
field1: Number = null;
field2: Date = null;
field3: String = null;
...
field40: Number = null;
mounted() {
axios.get(..., response => {
this.field1 = response.data.field1
this.field2 = response.data.field2
this.field3 = response.data.field3
...
this.field40 = response.data.field40
}
}
submit() {
const data = {
field1 = this.field1,
field2 = this.field2,
field3 = this.field3,
...
field40 = this.field40,
};
axios.put(..., data);
}
}
You could wrap your fields in a model field in your data:
data:{ model:{}}
Then on mounted you could set reactive props in your model
mounted(){
for(let field in YOUR_JSON_OBJ){
Vue.set(this.model, field , YOUR_JSON_OBJ[field])
}
}
Then when you need to submit form, just pass your vue model prop
YOUR_SUBMIT_METHOD(JSON.stringify(this.model))
I can see two ways to do this.
Provide a list of properties in an array, if you know it in advance (this is better practice as the data property gets initiated in the right way):
const props=['field1','field2', ...];
export default {
async mounted(){
//load the data and ensure only the expected properties are mounted
//this avoids any unexpected behaviour.
const result = await loadMyData();
for(let prop of props) this[prop]=result[prop];
}
data(){
//instantiate the data object to ensure all the properties are reactive
const data={};
for(let prop of props) data[prop]=null;
return data;
}
methods:{
async updateServer(){
//build the data object to send back to the server then send it.
const data={};
for(let prop of props) data[prop]=this[prop];
await sendUpdate(data);
}
}
}
The second way is to store a list of properties when you load the data from the server using Object.keys() and store this as a data property. You will then need to use vm.$set to ensure all of the properties have the correct reactivity, and you will not be able to have the properties at the root level, instead you will need to nest them (see the vue docs). However I assume that if your view object is designed to react to these properties then you must know them in advance.