I am creating an R package which provides some helper functions to build a Shiny app.
One of the JS files packaged with the app needs to reference an image file. But I can't figure out how to reference it.
Currently, the js file is located in
my_package/inst/www/js/my_jsfile.js
This file needs to reference
my_package/inst/www/img/my_img.gif
In the JS file, what should the relative URL to the image be?
I tried various options, such as the following, which do not work, when launching in a Shiny app built with the package:
../my_img.gif
www/img/my_img.gif
My JS looks like this:
function showRecordingIcon() {
var img = document.createElement("img");
img.style.display = "block";
img.src = "img/record.gif";
img.width = "280";
img.height = "280";
}
This was working before I packaged it.
If your goal is to get file path from the inst folder in your package on the user system, try:
system.file('www/js/my_file.js', package = 'NAMEOFYOURPACKAGE', mustWork = T)
Did you use shiny::addResourcePath("img", "/path/to/img/folder")
Something like shiny::addResourcePath("img", system.file('www', 'img', package = 'NAMEOFYOURPACKAGE', mustWork = T)
Next, you can refer to it as "img/record.gif"
The ../ means that it goes to the parent directory.
../img/my_img.gif
I have a webcomponent where I need to add a link tag to the head and set the href equal to a folder inside that node module.
Right now I'm in the building phase of this component where my structure look like this:
So I need to add the fontawsome.css script to the head of my page. I've created the following script:
constructor() {
super();
if (!this.isFontAwesomeLoaded()) {
this.iclass = '';
const fontEl = document.createElement('link');
fontEl.rel = 'stylesheet';
fontEl.href = "./fontawesome/css/all.css";
document.head.appendChild(fontEl);
}
}
Now there is a problem with this the path ./fontawesome/css/all.css won't work when it hits the head tag because the index.html file that attempts to load it doesn't have the folder in its project. instead when it hits product it needs to find the absolute path to my module and then to the fontawesome folder.
My question is how can I get that path?
There is a lot of things that should be avoided:
External dependencies from within web-component is a bad idea, especially something big like fontawesome. You said that you try to avoid coupling, but actually you introduce it with such dependency.
Web-components rarely should be used without shadow-dom (IMHO), by accepting fontawesome you basically ignore that functionality of web-components.
There are a couple of ways you could handle such scenario:
extract what you need from fontawesome's all.css into your web-component.
state in your component's docs that it depends on fontawesome and that the client should provide it on their side
use CDN (really bad decision, avoid this):
constructor() {
super();
if (!this.isFontAwesomeLoaded()) {
this.iclass = '';
const fontEl = document.createElement('link');
fontEl.rel = 'stylesheet';
fontEl.href = "https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css";
document.head.appendChild(fontEl);
}
}
Basically, I have a html file called panel containing a simple DIV that I would like to insert into another main HTML file.
Instead of using web components, I'd like to implement a simple solution as described in this answer.
So, here is what I am doing for testing (just logging the panel to console):
panel.html
<div id="panel">
<h1>It works...</h1>
</div>
get-template.ts
export async function getTemplate(filepath: string, selectors: string) {
let response = await fetch(filepath);
let txt = await response.text();
let html = new DOMParser().parseFromString(txt, 'text/html');
return html.querySelector(selectors);
}
main.ts
import { getTemplate } from './get-template'
getTemplate('/path/to/panel.html','#panel').then((panel) => {console.log(panel);})
The console logs "null".
If this info could make any difference, I am using parcel-bundler to build the application.
The actual problem was determined by #CBroe and was about the fact that when parcel builds my application, the file path of my panel.html resource changes to be relative to the built dist folder.
Just to clarify:
before building the path is relative to the main.ts file
after building the path is relative to the dist folder
So the solution is to think about the final URL the panel.html will have, and refer to it in advance before building with parcel.
Something like this would work in my case:
main.ts (new)
import { getTemplate } from './get-template'
getTemplate('./panel.html','#panel').then((panel) => {console.log(panel);})
Then of course, the other step will be to copy the actual panel.hml file into the dist directory, otherwise the URL will point to a non existing file.
I see there was a github issue about automatically copy static (or assets) files in the parcel repository, and one of the solution provided is to use the plugin parcel-plugin-static-files-copy.
I know that to use a static image in react native you need to do a require to that image specifically, but I am trying to load a random image based on a number. For example I have 100 images called img1.png - img100.png in my directory. I am trying to figure out a way to do the following
<Image source={require(`./img${Math.floor(Math.random() * 100)}.png`)}/>
I know this intentionally does not work, but any workarounds would be greatly appreciated.
For anyone getting to know the react-native beast, this should help :)
I visited a couple of sites in the past too, but found it increasingly frustrating. Until I read this site here.
It's a different approach but it eventually does pay off in the end.
Basically, the best approach would be to load all your resources in one place.
Consider the following structure
app
|--img
|--image1.jpg
|--image2.jpg
|--profile
|--profile.png
|--comments.png
|--index.js
In index.js, you can do this:
const images = {
profile: {
profile: require('./profile/profile.png'),
comments: require('./profile/comments.png'),
},
image1: require('./image1.jpg'),
image2: require('./image2.jpg'),
};
export default images;
In your views, you have to import the images component like this:
import Images from './img/index';
render() {
<Image source={Images.profile.comments} />
}
Everybody has different means to an end, just pick the one that suits you best.
Da Man - Q: How is this answer using a variable?
Well, since require only accepts a literal string, you can't use variables, concatenated strings, etc. This is the next best thing. Yes, it still is a lot of work, but now you can do something resembling the OP's question:
render() {
var images = { test100: "image100" };
return (
<View>
<Text>
test {images["test" + "100"]}
</Text>
</View>
);
}
In JS require statements are resolved at bundle time (when the JS bundle is calculated). Therefore it's not supported to put variable expression as an argument for require.
In case of requiring resources it's even more trickier. When you have require('./someimage.png'), React Native packager will locale required image and it will be then bundled together with the app so that it can be used as a "static" resource when your app is running (in fact in dev mode it won't bundle the image with your app but instead the image will be served from the server, but this doesn't matter in your case).
If you want to use random image as a static resource you'd need to tell your app to bundle that image. You can do it in a few ways:
1) Add it as a static asset of your app, then reference to it with <Image src={{uri:'name_of_the_image_in_assets.png'}}/> (here is how you can add it to the native iOS app)
2) Require all the images upfront statically. Sth in a form of:
var randomImages = [
require('./image1.png'),
require('./image2.png'),
require('./image3.png'),
...
];
Then in your code you can do:
<Image src={randomImages[Math.floor(Math.random()*randomImages.length)]}/>
3) Use network image with <Image src={{uri:'http://i.imgur.com/random.jpg'}}/>
class ImageContainer extends Component {
this.state ={
image:require('default-img')
}
<View>
<Image source={this.state.image} />
</View>
}
In the context of this discussion,I had this case where wanted to dynamically assign images for a particular background. Here I change state like this
this.setState({
image:require('new-image')
})
I came to this thread looking for a way to add images in a dynamic way. I quickly found that passing in a variable to the Image -> require() was not working.
Thanks to DerpyNerd for getting me on the correct path.
After implementing the resources in one place I then found it easy to add the Images. But, I still needed a way to dynamically assign these images based on changing state in my application.
I created a function that would accept a string from a state value and would then return the Image that matched that string logically.
Setup
Image structure:
app
|--src
|--assets
|--images
|--logos
|--small_kl_logo.png
|--small_a1_logo.png
|--small_kc_logo.png
|--small_nv_logo.png
|--small_other_logo.png
|--index.js
|--SearchableList.js
In index.js, I have this:
const images = {
logos: {
kl: require('./logos/small_kl_logo.png'),
a1: require('./logos/small_a1_logo.png'),
kc: require('./logos/small_kc_logo.png'),
nv: require('./logos/small_nv_logo.png'),
other: require('./logos/small_other_logo.png'),
}
};
export default images;
In my SearchableList.js component, I then imported the Images component like this:
import Images from './assets/images';
I then created a new function imageSelect in my component:
imageSelect = network => {
if (network === null) {
return Images.logos.other;
}
const networkArray = {
'KL': Images.logos.kl,
'A1': Images.logos.a1,
'KC': Images.logos.kc,
'NV': Images.logos.nv,
'Other': Images.logos.other,
};
return networkArray[network];
};
Then in my components render function I call this new imageSelect function to dynamically assign the desired Image based on the value in the this.state.network:
render() {
<Image source={this.imageSelect(this.state.network)} />
}
Once again, thanks to DerpyNerd for getting me on the correct path. I hope this answer helps others. :)
Here is a simple and truly dynamic solution(no renaming or import required) to the problem if you have a bigger no of files.
[Won't work for Expo Managed]
Although the question is old I think this is the simpler solution and might be helpful. But I beg a pardon for any terminological mistakes, correct me please if I do any.
INSTEAD OF USING REQUIRE WE CAN USE THE URI WITH NATIVE APP ASSETS FOR ANDROID (AND/OR iOS). HERE WE WILL DISCUSS ABOUT ANDROID ONLY
URI can easily be manipulated as per the requirement but normally it's used for network/remote assets only but works for local and native assets too. Whereas require can not be used for dynamic file names and dirs
STEPS
Open android/app/src/main/assets folder from your App.js or index.js containing directory, if the assets folder doesn't exist create one.
Make a folder named images or any NAME of your choice inside assets, and paste all the images there.
Create a file named react-native.config.js in the main app folder containing App.js or index.js.
Add these lines to the new js file:
module.exports = {
project: {
ios: {},
android: {},
},
assets: ['./assets/YOUR_FOLDER_NAME/'],
};
at the place of YOUR_FOLDER_NAME use the newly created folder's name images or any given NAME
Now run npx react-native link in your terminal from main app folder, this will link/add the assets folder in the android bundle. Then rebuild the debug app.
From now on you can access all the files from inside android/app/src/main/assets in your react-native app.
For example:
<Image
style={styles.ImageStyle}
source={{ uri: 'asset:/YOUR_FOLDER_NAME/img' + Math.floor(Math.random() * 100) + '.png' }}
/>
I´ve added to my template.tpl.php file inside my drupal theme this line to elimiante the calling to a specific css file:
remove-stylesheets[all][] = modules/system/system.css
If I want to do that with a specific js file, could I just do this?:
remove-scripts[] = whatever.js
I´ve tried it, but it doesn´t seems to work...
Thanks for your help!
Try this code in your template file.
function phptemplate_preprocess_page(&$vars) {
$js = drupal_add_js();
unset($js['module']['sites/all/modules/yourmodule/yourjs.js']);
$vars['scripts'] = $js;
}
This function will be called before the template is processed and rendered to the browser. If you are not sure about the path to your js file, print the drupal_add_js() array and find the path to the required js.