How do I access an environment variable from within the public folder? - reactjs

In my create-react-app app I have a javascript file in my public folder. Within it, I need to access an environment variable named REACT_APP_ACTUAL_ENV but I'm not sure how I can. Trying the usual process.env.REACT_APP_ACTUAL_ENV doesn't work because process is undefined in the public folder. Looking at https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables, I can do %REACT_APP_ACTUAL_ENV% within an HTML file in the public folder and it works just fine. But the problem is I need to do this within a javascript file somehow, though I'm not sure if it's possible.

In my case, I have to reference REACT_APP_FACEBOOK_APP_ID environment variable to initialize Facebook SDK inside public/index.html file.
I simply assign the variable to HTML element's property then access it using JavaScript like so:
...
<meta property="fb:app_id" content="%REACT_APP_FACEBOOK_APP_ID%" />
<script>
const facebookAppId = document.querySelector('[property="fb:app_id"]').content;
// use `facebookAppId` here
</script>

Related

How to use global variables in Storybook with React

I found this answer, but I am not able to solve the issue with it.
The component I trying to load in Storybook depends on a global variable that is injected via a CDN in index.html.
To access the variable in the component I added this comment at the top of the file
/*global <variable name>*/
It's working fine in the React app, but Storybook throwing this error: <variable name> is not defined.
I tried adding that comment at the top of the stories.js file and at the top of the config file. - no luck.
The URL for the CDN is in an env file. From looking at this doc I tried adding a second script in the HTML file with an env variable that is prepended with STORYBOOK_. That didn't work either.
Any ideas on what I can do to get past this?
I've solved this by adding custom head tags: https://storybook.js.org/docs/configurations/add-custom-head-tags/#docs-content
Then adding my global variables there, for example:
// preview-head.html
<script>
var foo = bar
</script>

download sample file in public folder (react)

I want to put a sample xlsx file in my public folder (react project) and others can download this file.
<Button><link rel="chargeSample" href="%PUBLIC_URL%/chargeSample.xlsx"></link></Button>
How can I do this?
The tag defines a link between a document and an external resource.
To let download funcionality on your website you should change link tag
import chargeSample from './public/chargeSample.xlsx';
<Button>Download</Button>
First of all, we have to think about where you store the file, thinking about what react is going to do in build time. In develop, you can't trust 100% that the paths you use are going to be the same after building the app.
Here in the create react app doc there is some info about when to use the public folder and how to use it.
To download a file stored in the public folder, you have to reference it with the PUBLIC_URL. There are two ways of doing this:
Reference a file from inside the public folder
You will have to use de %PUBLIC_URL% as you mentioned.
For example, if you want to use a fav icon in the main HTML file, you have to add the icon in the public folder and then in the index.html you will reference this file with the %PUBLIC_URL% prefix.
// public/index.html
// ...other stuff
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
// ...
In build time, React will replace this hash with the path to that folder
Reference a file in the src folder
To reference a file from inside the src folder, you have to access the public folder URL. React saves this path in an environment variable. To be able to use that file you have to use the process.env.PUBLIC_URL path.
To download a file from the public folder, you can access it like this:
<a
href={process.env.PUBLIC_URL + "/my-file.txt"}
download={"file-name-to-use.txt"}
>
Download file
</a>
When clicking the anchor tag it will try to download the file stored in /public with the name my-file.txt and it will use as a placeholder name for that file the one specified in the download property.
If you are using creat react app, you can pass public path into your components at build time by using
process.env.PUBLIC_URL
I believe that Lucas gave the best answer. Just to add since I was looking for a way to programmatically create a link element (let's say when you received a new excel file from an API call in runtime/deployment) then you can do something as follows:
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `${Date.now()}.xlsx`); //set the attribute of the <a> link tag to be downloadable when clicked and name the sheet based on the date and time right now.
document.body.appendChild(link);
link.click(); //programmatically click the link so the user doesn't have to
document.body.removeChild(link);
URL.revokeObjectURL(url); //important for optimization and preventing memory leak even though link element has already been removed.
Credits to top answers here:
How to download files using axios
How to download excel in response from api react.js

Call a Angular js page in Play framework

I am finding trouble to display my AngularJs page from Play framework 2.2
The Angular js page is located in the same project directory which is
C:\webProj\test\app\www\index.html
Note this index.html is not the index.scala.html that we have in play views directory
I need to render this page from my Play project.
I have tried this
GET /masterid controller.Assets.at("/app/www/",index.html)
but it gives a compilation error.
Explanation of the error
There are some syntax errors in this route configuration:
GET /masterid controller.Assets.at("/app/www/",index.html)
It should be controllers instead of controller, the path is wrong, and the parameters are not specified correctly. It could be written as:
GET /masterid controllers.Assets.at(path="/app/www", file="index.html")
Note that as written, this route will map only to the index.html file, not to any other resources under /masterid.
Solution with a separate directory
To behave exactly as asked, with a separate directory and a custom URL, you would need to specity a second asset route in addition to the default one. This would also require changing all usages of #routes.Assets.at to specify two parameters (folder and file), and adding a configuration to build.sbt:
playAssetsDirectories <+= baseDirectory / "app/www"
Solution using the public directory and a custom URL
The path of least resistance is to create the custom index.html file in the project's public directory. To use a custom URL as asked in the question, you could change the default asset path to "masterid" by changing this line in the routes file:
GET /assets/*file controllers.Assets.at(path="/public", file)
to this:
GET /masterid/*file controllers.Assets.at(path="/public", file)
In this case the custom index.html file could be accessed as:
http://localhost:9000/masterid/index.html
Relative URLs to other resources under the /public folder would work as well.
Solution using the public directory and the default URL
If you don't require the /masterid URL under the root, you can save your index.html file under public/app and refer to it as:
#routes.Assets.at("app/index.html")
This will resolve to:
http://localhost:9000/assets/app/index.html
Documentation
For more extensive instructions see Working with public assets.
Make it faster, just place your file in i.e.: /public/angular-app/index.html, so you can use it via:
#routes.Assets.at("angular-app/index.html")
Next (assuming that you have standard routes) you can just use static paths to your public assets, i.e. if image is placed in folder public/img/logo.png you can access it with:
<img src="/assets/img/logo.png" alt=""/>
So just by replacing public/ to /assets/ (slash at beginning to make sure you don't need to use base tag in head of document).

Loading an external script using <script src="..."> in Angular

I need to include a script that has a session ID in the URL (I wouldn't normally do this, but I'm using Crocodoc to embed documents into the page and they don't seem to have another way of doing it without using an iFrame which isn't customizable):
<!--sets a global variable "_doc" that is needed for initialization-->
<script src="//crocodoc.com/webservice/document.js?session=tohY5vh3dPjUbmW6_imSQFshvQUsJ3fuJFyG7CxBU-E3AArTbELI3U0bSJBm6z5ZKtXpJQCnJ-EU1J2WGbuu6WH4e3Bglcy38TplHg"></script>
I tried simple things like:
<script ng-src="//crocodoc.com/webservice/document.js?session={{ file.crocodoc_session }}"></script>
This writes the tag out fine, but the script is never requested. I also tried using just "src" instead of "ng-src" but that makes a request with "{{ file.crocodoc_session }}" in the URL, and doesn't make another request once the session ID value is actually written.
The last thing I tried was to make a directive with a compile function, in which I use jQuery to set the src attribute. That worked, expect that I couldn't figure out how to pass the session ID to the compile function. I used a "session" attribute on the element, but when I pass a variable (or use session="{{ file.crocodoc_session }}") I get the variable name as a string instead of it's value.
Try evaluating the link inside the controller, assigning it to a scope variable and then referencing it in the ng-src.

How to insert tags in static html in play framework

I create a tag whose content is static,
for example: header.html
then I insert to a static html eg: about.htm,
when open:
http://localhost:9000/about.htm
still get #{header /} in the browser.
how to solve it?
Did you put your header.html file in the app/views/tags directory?
update: Since you said you did, it's probably because you need to render the html server side via a controller.
So try creating a controller and putting it in the controllers package. Something like this:
package controllers;
public final class About extends Controller {
public static void about() {
render();
}
}
And then make sure that about.htm lives in the folder app/views/About. Note: I'm not entirely sure, but you might need to rename about.htm to be about.html (but probably not, but just keep it in mind if it doesn't work for you).
So to get the controller to render the about.htm with the resolved header.html, you will need to hit the url http://localhost:9000/About/about
of course, you can clean that url up by adding this to the routes file:
GET /about About.about
Using the above, you can simply hit this url http://localhost:9000/about.

Resources