Why React example does not use Async call to fetch json of requested page - aem

I am following this tutorials: https://github.com/adobe/aem-sample-we-retail-journal
Here, all the child pages JSON is stored into INITIAL_STATE id. 
https://github.com/adobe/aem-sample-we-retail-journal/blob/master/react-app/src/index.js#L34
document.addEventListener('DOMContentLoaded', () => {
let jsonScript = document.getElementById("__INITIAL_STATE__");
let initialState = null;
if (jsonScript) {
initialState = JSON.parse(jsonScript.innerText);
// Remove the script element from the DOM
jsonScript.remove();
}
I want to know why it is done in this way, can someone please explain?
Instead what if I navigate on different links and then on click of each links if I call model json of that page via Async fetch and then accordingly set INITIAL_STATE id. What problem in this approach? 

Related

Firebase Functions logs working, but Flutter returns null

I'm trying to display Firestore data in a Flutter app. To do that, I created a Firebase function like the following:
exports.getHouses = functions.https.onCall((data, context) => {
let pathBeginning = "users/";
console.log(data.userID);
let path = pathBeginning.concat(data.userID, "/houses");
let houses = [];
admin.firestore().collection(path).get().then(snapshot => {
console.log("COLECTION WHERE DOCUMENTS ARE RETREIVED:");
console.log(path);
snapshot.forEach(doc => {
let newHouse = {
"id": doc.id,
"address": doc.data().address
}
houses = houses.concat(newHouse);
});
console.log("THE FOLLOWING LOG SHOULD RETURN THE FULL LIST OF HOUSES:")
console.log(houses);
return houses;
}).catch(reason => {
response.send(reason);
});
});
I think this part works properly, because logs in Firebase look exactly as expected:
Firebase logs
The problem happens when I try to print this data in my Flutter app. To do so, I use the following code:
Future<void> listHouses() async {
var parameters = {
"userID": "1"
};
HttpsCallable getHouses = FirebaseFunctions.instance.httpsCallable("getHouses");
await getHouses.call(parameters).then((HttpsCallableResult response) {
print(response.data);
});
}
When called the funtion, it always returns null, even when Firebase log displays everything properly.
I would appreciate if anyone can help me solving this issue. Thank you in advance.
You're missing a return in front of your get() call. Without that, the Cloud Functions container doesn't know about the asynchronous get() operation and thus will/may terminate the function before loading the data completes.
To fix this, add return:
return admin.firestore().collection(path).get().then(snapshot => {
...
This is an extremely common problem within Cloud Functions and when dealing with asynchronous APIs in general, so I recommend taking a moment to read the Firebase documentation on terminating functions and watching the video series linked in there.

What is the proper way to run fetch calls which use reactive components from a store?

I am getting two reactive variables I need from a store to use for my fetch calls. I need these fetch calls to rerun when the data in these store values change. I am able to make this work however when I reload the page it causes my app to crash because there are no values that are getting from the store. I am able to make it work if I disable ssr on the +page.js file.
I also believe it is relevant to mention that I am using a relative URL (/api) to make the fetch call because I have a proxy server to bypass CORS
What is the proper way to get this data by rerunning the fetch calls using a reactive component from a store without disabling ssr? Or is this the best/only solution?
+page.svelte
<script>
import { dateStore, shiftStore } from '../../../lib/store';
$: shift = $shiftStore
$: date = $dateStore
/**
* #type {any[]}
*/
export let comments = []
/**
* #type {any[]}
*/
let areas = []
//console.log(date)
async function getComments() {
const response = await fetch(`/api/${date.toISOString().split('T')[0]}/${shift}/1`)
comments = await response.json()
console.log(comments)
}
async function getAreas() {
const response = await fetch(`/api/api/TurnReportArea/1/${date.toISOString().split('T')[0]}/${shift}`)
areas = await response.json()
console.log(areas)
}
// both of these call function if date or shift value changes
$: date && shift && getAreas()
$: date , shift , getComments()
</script>
I tried to use the +page.js file for my fetch calls, however I cannot use the reactive values in the store in the +page.js file. Below the date variable is set as a 'Writble(Date)' When I try to add the $ in front of the value let dare = $dateStore, I get the error 'Cannot find name '$dateSrote'' If i put the $ in the fetch call I get the error 'Cannot find $date'. Even if I were able to make this work, I do not understand how my page would know to rerender if these fetch calls were ran so I do not think this is the solution. As I mentioned, the only solution I have found is to disable ssr on the +page.js, which I do not think is the best way to fix this issue.
import { dateStore, shiftStore } from "../../../lib/store"
export const load = async ({ }) => {
let shift = shiftStore
let date = dateStore
const getComments = async() => {
const commentRes = await fetch(`/api/${date.toISOString().split('T')[0]}/${shift}/1`)
const comments = await commentRes.json()
console.log(comments)
}
const getAreas = async () => {
const areasRes = await fetch(`/api/api/TurnReportArea/1/${date.toISOString().split('T')[0]}/${shift}`)
const areas = await areasRes.json()
console.log(areas)
}
return {
comments: getComments(),
areas: getAreas()
}
}

ReferenceInput Select Input for Filter component Form

I built a custom Filter component for my List View and Im having trouble populating a Select Input of ALL available options for a property. for instance
<Form onSubmit={onSubmit} initialValues={filterValues} >
{({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<ReferenceInput label="Ring Id" source="ringid" reference="candidates">
<SelectInput optionText="ringid" />
</ReferenceInput>
</form>
)}
</Form>
Without building a "getMany" dataProvider Im told that I can access all of the (2,000+ ids) "ringid"s pulled in from the "getList" provider and list every ID into the SelectInput field and search in my custom Filter component.
Issues presented:
I have to hard code amount of results I can have (Default 25)
When I submit the form to Search through the filter component "Associated reference no longer appears to be available." appears and the search fails.
The "getMany" component is only half way built but it seems that ReferenceInput only wants to use "getMany"(Im told that building the backend and building code to use getMany is not an priority to build so I cant build it myself)
25 Populated IDs Screenshot
Form Error when Filter is submitted ScreenShot
So I would like some help in the right direction to populate a SelectInput of all available ids in the getList dataProvider and be sure that I can even use this input in my Filter form component. Thank you in advance for any feedback.
1: Yes, i think there's no option to add pagination to ReferenceInput, you must hardcode it, but, if your backend already supports text search, you can use an AutocompleteInput as child, allowing users to filter results:
<ReferenceInput
label="Ring Id"
source="ringid"
reference="candidates"
filterToQuery={searchText => ({ paramNameThatYourBackendExpects: searchText })}
>
<AutocompleteInput optionText="ringid" />
</ReferenceInput>
2 & 3: 2 happens because of 3. ReferenceInput only "wants" to use getMany because it also support SelectManyInput as child, for such case, it's better to get all selected options at once, than calling one by one, so, to make code simpler, ReferenceInput always use getMany. If you can't implement backend part of getMany, but can add code to your dataProvider, you can implement getMany by making multiple getOne calls:
Assuming a v3 dataProvider:
this.getMany = async (resource, params) => {
const response = {data: []}
for (const id of params.id) {
response.data.push(await this.getOne(resource, {id}))
}
return response
}
v2 is implementation-dependant, just follow the same principle.
If you can't change the dataProvider, e.g, a third-party available dataProvider, you can wrap it:
v3
const fakeGetManyDataProvider = dataProvider => ({
...dataProvider,
getMany: async (resource, params) => {
const response = {data: []}
for (const id of params.id) {
response.data.push(await dataProvider.getOne(resource, {id}))
}
return response
}
})
v2
import { GET_MANY, GET_ONE } from 'react-admin'
const fakeGetManyDataProvider = dataProvider => async (verb, resource, params) => {
if (verb === GET_MANY) {
const response = {data: []}
for (const id of params.id) {
response.data.push(await dataProvider(GET_ONE, resource, {id}))
}
return response
}
return dataProvider(verb, resource, params)
}
Please note that error handling is omitted for simplicity, react admin expects rejecteds promise instead of unhandled expections, so you must handle errors.

parse response received from rememberCustomViewAsync from tableau javascript api

I am trying to save custom views using rememberCustomViewAsync and displaying the saved view using showCustomViewAsync, I want to parse the response received from executing rememberCustomViewAsync, it returns various details including the url of the view.
here is the code i am trying
$(document).on('click', '.new_dashboard_preference > [type="button"]', function() {
tableauViz.getWorkbook().rememberCustomViewAsync($('#dashboard_preference_name').val()).then(function(customView) {
console.log(customView.url); //this is what i am trying to access
jQuery(this).parent('form')[0].submit();
}).otherwise(function (err) {
console.log(err.message);
});
});
Can any please guide as to how the response received from rememberCustomViewAsync be parsed in javascript. Thanks.
If it is a JSON object you can use:
responseVariable = JSON.parse(responseVariable)
You can then use accessors like responseVariable.ItemYouWantToSee or array index accessors such as responseVariable[0].
To take this out of the 'click' event listener and make it a global object you can push the result to an array.

Posting multiple images to tumblr using tumblr.js api

I am trying to creating a app which can send posts to tumblr using tumblr.js api.
I could send single image using the createPhotoPost method, but I have to send multiple image in a single post via this method.
From the documentation it says that createPhotoPost method has a "data" parameter which can be an array with "URL-encoded binary contents"
When ever I try to send something in the data Array it returns "[Error: form-data: Arrays are not supported.]".
Can someone please help to solve this issue and please explain what should we pass in the array (Really I am not getting what is URL-encoded binary contents)?
Thanks in advance
There is an error in tumblr.js
https://tumblr.github.io/tumblr.js/tumblr.js.html#line504
The documentation at https://www.tumblr.com/docs/en/api/v2#posting is correct.
Basically the issue is that its not supposed to be
data = [ one , two ] its litterally params['data[0]'] = one ; params['data[1]'] = two; (?A PHP Convention)
var request = require('request')// already a tumblr.js dependency
var currentRequest = request({
url:'https://api.tumblr.com/v2/blog/someblog.tumblr.com/post',
oauth:keys,
},function(err,response,body){
currentRequest//
debugger
cb()
})
var params = {
'type' :'photo',
'caption':'Click To Verify You Are A Robot',
}
var params_images = [
fs.createReadStream('image'),
fs.createReadStream('image')
]
// Sign it with the non-data parameters
currentRequest.form(params)
currentRequest.oauth(keys);
// Clear the side effects from form(param)
delete currentRequest.headers['content-type'];
delete currentRequest.body;
// And then add the full body
var form = currentRequest.form();
//###add params_images to params keys 'data[0]' 'data[1]' 'data[2]' ....
params_images.forEach(function(image,index){
params['data['+index+']']
})
for (var key in params) {
form.append(key, params[key]);
}
// Add the form header back
var form_headers = form.getHeaders()
for(var key in form_headers){
currentRequest[key] = form_headers[key]
}