How to add custom data with Ju99ernaut/grapesjs-tailwind plugin? - javascript

In laravel 8 app "jd-dotlogics/laravel-grapesjs": "^3" is used and
https://github.com/Ju99ernaut/grapesjs-tailwind plugin is used to add custom block at grapejs editor, which
looks like https://prnt.sc/cITyK6U2AKzM
I need to add custom blocks based on data of our app at this area.
Reading https://github.com/Ju99ernaut/grapesjs-tailwind page I did not find any possibility to add custom blocks in sinilar way.
So in file config/laravel-grapesjs.php I replaced path to grapesjs-tailwind file :
[
'name' => 'grapesjs-tailwind',
'options' => [],
'scripts' => [
// 'https://unpkg.com/grapesjs-tailwind'
'js/custom-grapesjs-tailwind.min.js'
]
]
I saved file as public/js/custom-grapesjs-tailwind.min.js and unpacking it try to this file manually.
All these items are filled in big array like : https://prnt.sc/VihL339Z2-g1
I try to run request with axios, but I have a problem that I can not to import axios in plain js file:
window.axios = require('axios');
window.axios.get('pages/{page_id}/get-custom-blocks')
.then(({data}) => {
I got error :
ReferenceError: require is not defined
With line :
import { axios } from 'axios'
I got error :
Uncaught SyntaxError: Cannot use import statement outside a module
If there is a way to use axios in public/js/custom-grapesjs-tailwind.min.js ?
Are there some other similar decisions with grapesjs compatible with "jd-dotlogics/laravel-grapesjs" ?
UPDTATED BLOCK :
Looking at doc https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
I do it as next :
c = retrieveGetData('/pages/4/get-custom-blocks', {})
.then(data => {
console.log('retrieveGetData data::')
console.log(data); // JSON data parsed by `data.json()` call
});
...
async function retrieveGetData(url = '', data = {}) {
const response = await fetch(url, data = {}, {
method: 'GET', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
let retArray = response.json()
console.log('retArray::')
console.log(retArray)
console.log('retrieveGetData retArray.customBlocks::')
console.log(retArray.customBlocks)
console.log('retrieveGetData retArray.Promise::')
console.log(retArray.Promise)
console.log('retrieveGetData retArray.PromiseResult::')
console.log(retArray.PromiseResult)
console.log('retrieveGetData retArray.PromiseResult.customBlocks::')
console.log(retArray.PromiseResult.customBlocks)
return retArray.customBlocks;
}
In browser's console I see that I got returned data : https://prnt.sc/2llG-UG8fnRD
I expected with response.json() to get valid array of data, but looks like my request is not valid ?
UPDATED BLOCK # 2 :
I remade function retrieveGetData so that it returns response object:
async function retrieveGetData(url = '', data = {}) {
console.log('retrieveGetData url::')
console.log(url)
const response = await fetch(url, data = {}, {
method: 'GET', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
return response
}
and calling this method :
retrieveGetData('/pages/4/get-custom-blocks', {})
.then(data => { // get data from server - got Response object
console.log('retrieveGetData data::')
console.log(data);
let json_data =data.json() // I got Promise pending object
console.log('get-custom-blocks json_data::')
console.log(json_data)
let c = json_data.customBlocks // get custom data - I got undefined data
console.log('get-custom-blocks c::')
console.log(c)
c.forEach((function (t) { // run circle for custom data
e.add(t.id, {
label: t.label,
attributes: {class: t.class},
content: t.content,
category: {label: t.category, open: 'Blog' === t.category}
})
}))
});
I see in browser's console : https://prnt.sc/VuYb-IyK1LNf
What is wrong in my code ?
UPDATED BLOCK # 3 :
Yes, declaration of retrieveGetData has async and await calling of axios :
async function retrieveGetData(url = '', data = {}) {
const response = await fetch(url, data = {}, {
method: 'GET', // *GET, POST, PUT, DELETE, etc.
...
});
return response
}
and calling it :
await retrieveGetData('/pages/4/get-custom-blocks', {})
.then(data => { // get data from server
console.log('retrieveGetData data::')
console.log(data); // JSON data parsed by `data.json()` call
let json_data =data.json()
console.log('get-custom-blocks json_data::')
console.log(json_data)
let c = json_data.customBlocks // get custom data
console.log('get-custom-blocks c::')
console.log(c)
c.forEach((function (t) { // run circle for custom data
e.add(t.id, {
label: t.label,
attributes: {class: t.class},
content: t.content,
category: {label: t.category, open: 'Blog' === t.category}
})
}))
});
But in this case I got error :
Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules (at custom-grapesjs-tailwind.min.js:504:9)
#matiaslauriti, your code in answer is not clear.
I do not see where from “data” var ?
What kind of code is it
retrievedData = await retrieveGetData
?
Please write this block in details...
My webpack.mix.js has :
const mix = require('laravel-mix');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel application. By default, we are compiling the Sass
| file for the application as well as bundling up all the JS files.
|
*/
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.sourceMaps();
mix.js('resources/js/editor-modules.js', 'public/js')
.sass('resources/sass/pages.scss', 'public/css');
mix.js('resources/js/editor-config.js', 'public/vendor/laravel-grapesjs/assets')
.sass('resources/sass/grapesjs-editor.scss', 'public/css');
Thanks!

Based on your new code, the issue would be that you are missing an await:
retrievedData = await retrieveGetData('/pages/4/get-custom-blocks', {});
c = data.json();
Remember that the function having this code must also have async defined.
EDIT:
So, let me update the code:
const retrievedData = await retrieveGetData('/pages/4/get-custom-blocks', {});
const c = data.json();
What I am saying on my answer is that you need to use await, so c is not a promise that you pass (check your original question) but real data.
So your code needs to be wrapped in an async function like this:
async function xxxx() {
const retrievedData = await retrieveGetData('/pages/4/get-custom-blocks', {});
return data.json(); // Return that or store it on variable c as you did
}

As your original question was related to the laravel-grapesjs package. So I wrote the answer here. Copying it here for your reference.
You can add it below way -- And the axios global variable will be available in your custom-grapesjs-tailwind.min.js file
[
'name' => 'grapesjs-tailwind',
'options' => [],
'scripts' => [
'https://unpkg.com/axios',
'js/custom-grapesjs-tailwind.min.js'
]
]

Related

Fetch vs Axios review?

I'm currently learning how to use axios and fetch api. I'm trying to make a request using a fetch api like this:
let response = await fetch('https://online.yoco.com/v1/charges/', {
method: 'POST',
headers: {
'X-Auth-Secret-Key': process.env.SECRET_KEY,
},
body: {
token: paymentToken,
amountInCents: 2799,
currency: 'ZAR'
}
});
let responseData = await response.json()
And an axios post request like this:
axios.post(
'https://online.yoco.com/v1/charges/',
{
token: 'tok_test_DjaqoUgmzwYkwesr3euMxyUV4g',
amountInCents: 2799,
currency: 'ZAR',
},
{
headers: {
'X-Auth-Secret-Key': SECRET_KEY,
},
},
)
.then(res => {
//code
})
.catch(error => {
// handle errors
})
Is the request the same or not?
Cause the fetch returns an error
No, those aren't the same, in two ways:
If you look at MDN's documentation for fetch, you'll see that it says this about body:
body
Any body that you want to add to your request: this can be a Blob, an ArrayBuffer, a TypedArray, a DataView, a FormData, a URLSearchParams, string object or literal, or a ReadableStream object. This latest possibility is still experimental; check the compatibility information to verify you can use it. Note that a request using the GET or HEAD method cannot have a body.
Notice that a plain object is not on that list.
You're not checking for HTTP errors. This is unfortunately a footgun in the fetch API (I wrote about it here): It only rejects its promise on network errors, not HTTP errors like 404.
I'm going to assume that your API accepts JSON. If so, you need to include the Content-Type header and call JSON.stringify:
let response = await fetch("https://online.yoco.com/v1/charges/", {
method: "POST",
headers: {
"X-Auth-Secret-Key": process.env.SECRET_KEY,
"Content-Type": "application/json", // ***
},
body: JSON.stringify({ // ***
token: paymentToken,
amountInCents: 2799,
currency: "ZAR",
}), // ***
});
if (!response.ok) { // ***
throw new Error(`HTTP error ${response.status}`); // ***
} // ***
let responseData = await response.json();

POST req: Only absolute URLs are supported

I am writing this app.js client file that performs a post request to a server (code below):
const fetch = require('node-fetch');
/* Function to POST data */
const postData = async ( url = 'http://localhost/8000/add/', data = {})=>{
console.log(data)
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
try {
const newData = await response.json();
console.log(newData);
return newData
}catch(error) {
console.log("errors", error);
// appropriately handle the error
}
}
// TODO-Call Function
postData('/addAnimal', {animal: 'girrafe'});
I keep on getting this error when I run with node app.js:
node .\app.js
{ animal: 'girrafe' }
D:\Downloads\FEWD\WebAPIs\N&E\node_modules\node-fetch\lib\index.js:1305
throw new TypeError('Only absolute URLs are supported');
^
TypeError: Only absolute URLs are supported
at getNodeRequestOptions (D:\Downloads\FEWD\WebAPIs\N&E\node_modules\node-fetch\lib\index.js:1305:9)
D:\Downloads\FEWD\WebAPIs\N&E\node_modules\node-fetch\lib\index.js:1305
throw new TypeError('Only absolute URLs are supported');
^
TypeError: Only absolute URLs are supported
at getNodeRequestOptions (D:\Downloads\FEWD\WebAPIs\N&E\node_modules\node-fetch\lib\index.js:1305:9)
at D:\Downloads\FEWD\WebAPIs\N&E\node_modules\node-fetch\lib\index.js:1410:19
at new Promise (<anonymous>)
at fetch (D:\Downloads\FEWD\WebAPIs\N&E\node_modules\node-fetch\lib\index.js:1407:9)
at postData (D:\Downloads\FEWD\WebAPIs\N&E\demo\app.js:22:31)
at Object.<anonymous> (D:\Downloads\FEWD\WebAPIs\N&E\demo\app.js:42:3)
Any suggestion as to why, would be much appreciated.
Thank you
Your url = 'http://localhost/8000/add' sets the default parameter to that URL, then you overwrite it with '/addAnimal' when you provide that as an argument. You should provide an absolute URL:
postData('http://localhost/8000/addAnimal', {animal: 'girrafe'});
As a side note, I'm pretty sure localhost/8000 is a typo and should be localhost:8000.

javascript fetch() works with breakpoints, but fails with TypeError when run normally

I'm trying to fetch() text/plain data from a remote service. If I place a breakpoint in the promise "then" chain, the text data from the server is available. Without the breakpoint, I get a fetch() exception.
I am using a prototype design pattern (see below). When I place a breakpoint in the "then" chain as shown below, the data from the remote service is successfully retrieved. Without the breakpoint, the catch() is executed and the error is:
TypeError: Failed to fetch
I'm totally stumped and would appreciate any help!
Note, the server (a python app) sends back html, with
self.send_header("Access-Control-Allow-Origin", "*")
Also, if I use Ajax (FWIW, it works). I'd like to get it working with fetch() however.
function Fetch(Msg) {
// Msg contains some info on how to construct the JSON message to transmit -- not relevant here.
this.help = `
The Fetch object specifies communication basics using
the fetch(...) mechanism.
`;
// some misc object vars...
}
Fetch.prototype = {
constructor: Fetch,
postData: async function (url = '', data = {}) {
const response = await fetch(url, {
method: 'POST,
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'text/plain',
},
redirect: 'follow',
referrerPolicy: 'no-referrer',
// body data type must match "Content-Type" header
body: JSON.stringify(data)
});
return await response.text(); //
},
handleErrorsInResponse: function (response) {
var debug = new Debug("Fetch.handleErrorsInResponse");
debug.entering();
debug.leaving();
},
handleReponse: function (response) {
var debug = new Debug("Fetch.handleResponse");
debug.entering();
console.log(response);
debug.leaving();
},
handleErrorsInFetch: function (response) {
var debug = new Debug("Fetch.handleErrorsInFetch");
debug.entering();
console.log(response);
debug.leaving();
},
call: function (payload) {
this.postData(
'http://some.url/',
payload)
.then(this.handleErrorsInResponse) // If I place a breakpoint here it works!
.then(this.handleReponse)
.catch(this.handleErrorsInFetch);
},
}
// Ultimately called by something like
comms = new Fetch();
someData = {"key": someJSON};
comms.call(someData);
Remove the wait on the response.
Replace
return await response.text();
by
return response.text();

asp.net API cookie authentication in custom function

How can I get data from an asp.net API that uses cookie authentication from inside a custom function.
I followed the examples from https://learn.microsoft.com/en-us/office/dev/add-ins/excel/custom-functions-web-reqs. I can make requests but fetch does not seem to be including the cookies in subsequent requests. It seems like fetch has been nerfed in custom functions.
/**
* #customfunction
*/
async function CalcbenchData(): Promise<number> {
let batchURL = 'https://www.calcbench.com/api/NormalizedAPIBatch'
let data = [{ "metric": "revenue", "ticker": "msft", "year": 2015, "period": 1, "datatype": 1 }]
await login()
return postData(batchURL, data)
}
/**
* the reponse from this function sets the ASP.net authentication token cookie
*/
async function login() {
let email = encodeURIComponent('username')
let password = encodeURIComponent('password')
let url = `https://www.calcbench.com/account/LogOn?email=${email}&password=${password}`
await fetch(url,{
method: 'GET',
mode: 'same-origin'
});
}
function postData(url = '', data = {}): Promise<number> {
return fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'same-origin', // no-cors, cors, *same-origin
headers: {
'Content-Type': 'application/json',
},
redirect: 'follow', // manual, *follow, error
referrer: 'no-referrer', // no-referrer, *client
body: JSON.stringify(data), // body data type must match "Content-Type" header
}).then(response => {
return response.json()
}).then(json => {
return json.value
}) // parses JSON response into native JavaScript objects
}
7/25/2019 17:49:54 Verbose Runtime [Console] [Log] Unexpected CustomFunctions [Execution] [End] [Failure] [RejectedPromise] Function=CALCBENCHDATA TypeError: Network request failed {}
this is currently not possible with the custom functions runtime on windows (as it is a seperate process from the authentication dialog) but is under active development on how we enable this. Please watch this item on GitHub for upcoming updates: https://github.com/OfficeDev/Excel-Custom-Functions/issues/118. We'll likely update it in a couple of weeks time.
Thanks

res.json() is undefined when mocking post request with fetch-mock and isomrphic-fetch

I'm using fetch-mock to test my client action creators in cases where there is an async call being made to the BE.
While all get requests are working well I'm having hard time doing the same to post and put requests.
Attached here a code example that if works I believe that my actual code will work as well.
I'm using import fetchMock from 'fetch-mock' for mocking the response and require('isomorphic-fetch') directly to replace the default fetch
I added some comments but I do get a response with status 200 (if I change the mocked response status to 400 I get it as well. The problem is that res.json() resulted with undefined instead of the mocked result body.
Using JSON.stringify is something that I used after not being able to make it work without it.
const responseBody = {response: 'data from the server'};
fetchMock.once('http://test.url', {
status: 200,
body: JSON.stringify(responseBody),
statusText: 'OK',
headers: {'Content-Type': 'application/json'},
sendAsJson: false
}, {method: 'POST'});
fetch('http://test.url',
{
method: 'post',
body: JSON.stringify({data: 'Sent payload'}),
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.then(function (res) {
expect(res.status).toEqual(200); // Pass
res.json();
})
.then(function (json) {
console.log(json); // print undefine
expect(json).toEqual(responseBody); // Fail expected value to equal: {"response": "data from the server"} Received: undefined
done();
})
Mocking GET requests is working just fine
I also tried using it with fetchMock.post but had no luck
Would also appreciate if someone knows how I can test the post request sent payload as well (can't see any reference for that in the documentation)
In your first then, you don't have an explicit return, with the keyword return
If you don't do a return, the next then doesn't know the value. That's why your json is undefined.
For example:
var myInit = { method: 'GET', mode: 'cors', cache: 'default' };
fetch('https://randomuser.me/api/',myInit)
.then(function(res) {
return res.json()
})
.then(function(r) {
console.log(r)
})
So, for you:
const responseBody = {response: 'data from the server'};
fetchMock.once('http://test.url', {
status: 200,
body: JSON.stringify(responseBody),
statusText: 'OK',
headers: {'Content-Type': 'application/json'},
sendAsJson: false
}, {method: 'POST'});
fetch('http://test.url',
{
method: 'post',
body: JSON.stringify({data: 'Sent payload'}),
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.then(function (res) {
expect(res.status).toEqual(200); // Pass
return res.json(); // return here
})
.then(function (json) {
console.log(json); // print undefine
expect(json).toEqual(responseBody); // Fail expected value to equal: {"response": "data from the server"} Received: undefined
done();
})

Categories

Resources