Dynamically Updating Image SRC using ES6 - javascript

I have global JavaScript variable that is defined in PHP for use in a WordPress Block.
When the page initially loads, the "stars" image appears as expected. When a change event is fired, a 404 error appears in the console with "https://site.dev/img/var_set_in_php.imageSunset" as the URL instead of "https://site.dev/img/sunset.jpg".
How can this be updated to pull in the value that is set in PHP? I'm new to ES6, so hoping it's just something simple that I'm missing.
wp_localize_script(
'image-js',
'var_set_in_php', // Array containing dynamic data for a JS Global.
array(
'imageStars' => '/img/stars.jpg',
'imageSunset' => '/img/sunset.jpg',
)
);
function onChangeFunction(name) {
// name is set to "Sunset"
document.getElementById('image').src = `var_set_in_php.image${name}`;
}
<img src={var_set_in_php.imageStars} id="image" />

I think you have a
var var_set_in_php = {
'imageStars' :'/img/stars.jpg',
'imageSunset' : '/img/sunset.jpg'
}
and if you do, you need this to access the object with a compound variable
document.getElementById('image').src = var_set_in_php[`image${name}`];

Related

Rendering image dynamically is so hard in React

After trying various ways for hours and checking every relatable link, I couldn't find any proper way to render image dynamically in React.
Here is what i am trying to do.
I have an array of objects in which each object has a attribute called name. I am using map function map to loop over this array and returning of array of img element like shown below.
<img className="img-thumbnail" src={require('../../public/images/'+item.name+'.png')}/>
where item.name is the name of image file I want to display, for which require is giving me error "cannot find module".
Moreover I need to implement some fallback option, where rather showing broken images incase image file does not exist, i want to display default image
Here are the things I have tried:
using try and catch block over require and calling this function from img element
setImage(data){
try{
return require( '../../public/images/'+data+'.png' ) //actual image
}catch(err){
console.log(err);
return require('../../public/images/fallback.png'); //fallback
}
<img className="img-thumbnail" src={this.setImage(item)}/>
using import, inside same function above, got error import cannot be called from inside of function
using react-image library. Turned out it does not support local images.
Any help ?
Here a tricky way to handle this. Use react state to check if there's error.
If true, show fallback, otherwise, show actual image.
setImage = (data) => {
const image = new Image();
image.src = '../../public/images/'+data+'.png';
this.setState({
hasError: false
})
image.onerror = () => {
this.setState({
hasError: true
})
}
return image.src;
}
// into render
this.state.hasError
? <img src="../../public/images/fallback.png" />
: <img className="img-thumbnail" src={this.setImage(item)}/>
Update: Example
var image = new Image();
image.src = 'fake.jpg';
image.onerror = () => {
console.log('image doesn t exist');
}
I dont know why you need required it could be done simply like this. You can import something like this. Import image like this
import fallback from '../../public/images/fallback.png';
and for dynamic image i would suggest either make some key value pair. For ex :
let data = {
image1 : ../../public/images/image1.png,
image2 : ../../public/images/image1.png
}
and import it normal
and something in render
it could be something like this.
render(){
return(
<img className="img-thumbnail" src={img?img[type]:fallback}/> //something its just refrence(where type is something which you want dynamically add image)
)
}
Requires are statically checked during compile time. The path of requires cannot be dynamic. Since you have static images in your bundle and the object maps to one of these you can follow a solution to something as follows
const images = {
image1: require('local/path/to/image1'),
image2: require('local/path/to/image2'),
image3: require('local/path/to/image3'),
}
const defaultImage = require('local/path/to/defaultImage');
const Img = ({ name }) => {
// here name is the name for the image you get from api..
// This should match with the keys listed the iages object
return <img src={images[name] ? images[name] : defaultImage}/>
}
Above all answers were helpful but unforutnaley none of the method worked for me. So again digging little deep I found that require was giving error "cannot find module" because after webpack bundles my code, require lost the context. Which means the given relative path was no longer valid.
What i needed to do was preserve context which I did by using require.context;
Here is the final code that worked.
//getting the context of image folder
const imageFolderContext = require.context('realtive/path/to/image/folder')
//function to check if image exist
checkFile(data){
try{
let pathToImage = './path/to/image/relative/to/image/folder/context
imageFolderContext(pathToImage) //will check if Image exist
return true //return true if exist
}catch(err){return false}
}
//rendering image element dynamically based on item name and if exist or not
<img src={this.checkFile(itemName)?imageFolderContext('path/to/image/relative/to/context'):imageFolderContext('default/image/path/) />
don't forget to bind checkFile function

Creating a reusable javascript function instead of copy/paste

I made a page I need to have in different instances. In short it is used to fill in different parts of a script and then display said script on the page for the user to copy it.
This script below handles the main part of the job, getting a field from HTML and then i can call the result in html to be displayed.
var urlField = document.getElementById('urlField').value;
var resultUrl = document.getElementById('resultUrl');
resultUrl.textContent = urlField;
Problem: there are different fields, eg. url, startdate, enddate, adschedule, etc. so I would like to have a reusable script that just says get the respective field and result the value which is assigned to it in html.
Can I do this somehow? I was researching the function "this" in javascript, but it is too complicated for my current knowledge. Bear in mind that I am in only a very basic level.
You can find the whole codepen to understand the issue better here: https://codepen.io/kmb5/pen/GxZbZq
Add parameters to your re-usable function and then call it whenever you need to use it. Use javascript to get the required data and pass it in as parameters.
reusable.js:
function myFuncWithParameters(parm1, parm2, parm3){
}
Alternatively:
function myFuncWithParameters(myObject){
//access properties from the object: myObject.parm1, myObject.parm2, myObject.parm3
}
Using the object route might make it easier since the order of the properties will not matter like parameters. Regardless of either method you will have to validate the input.
In your html pages, you will need some More JavaScript and HTML to bring in the JS and call it.
<html>
<head>
<title>my page</title>
<script scr="path to reusable js"></script>
<script src="path to this path's js"></script>
</head>
<body>
my page
</body>
</html>
If you look at the script tags, by importing the reusable js you can use it in javascript that was written / imported further down into the page.
In order to ensure you have access to an imported function, you can check if the function you need is defined:
if(typeof(myFuncWithParameters) !== 'undefined' && typeof(myFuncWithParameters) == typeof(Function){
//myFuncWithParameters will definitely be defined and is a function, if we get in here
}else{
//myFuncWithParameters is not defined and/or is not a function
}
In your html page to call the re-usable function...
var parm1 = value;
var parm2 = value;
var parm3 = value;
myFuncWithParameters(parm1, parm2, parm3);
In you decide to use the object:
var myObject = {
'parm1' : 4,
'parm2' : 6
}
//myObject.parm1 == 4
myFuncWithParameters(myObject);

Adding a variable into a page - wordpress

When I create pages within Wordpress, the call to action links on those pages always have the same URL. I want to be able to globalize this variable but am struggling to find a good way to do it.
If I were making simple PHP pages I could simply include e.g.
$URLpath = "http://example.com/my/page";
Then call this in the html:
Call to action
Obviously I can't do this within the Wordpress CMS as it renders as <?=$URLpath?>
I could add, say, Call to action and replace after the page loads using javascript replace over the whole block of html, but it doesn't feel efficient to do this.
Is there a better way? I'm pretty new to Wordpress.
You can add a shortcode in your functions.php file that prints your cta, or better create a plugin with some parameter that manages this link.
For example in functions.php you could add
function cta_func( $atts ){
$URLpath = "http://example.com/my/page";
return 'Call to action';
}
add_shortcode( 'cta', 'cta_func' );
inside your pages/post you can write simply this shortcode.
...
[cta]
...
Further infos about shortcodes are in the reference of codex
https://codex.wordpress.org/Shortcode_API
A good way to do this within WordPress is to use their wp_localize_script()
In your functions.php file you could use as:
// For sake of example I will put your data inside an array,
// but you can set a single value.
$dataForJS = array(
$URLPath => "http://example.com/my/page"
);
// wp_localize_script() takes 3 parameters:
// 1. Name of the registered script, this is the name you used in wp_register_script()
// here I am naming it "main" but it can be anything.
// 2. Name of the variable.
// This name is then available in your JS and will contain your data.
// 3. The data you want to pass, it can be a single value or array
wp_localize_script( 'main', 'd', $dataForJS );
In your JavaScript, you will be able to access this data by just calling the variable d.
What this does is that if the page requests the "main" script, WordPress will add a script tag with your data inside it and makes sure it is placed before your "main" script runs.

Accessing custom defined variable/object in javascript in for...in loop

Let me explain the whole problem. I was trying to avoid writing this as it could be a long explanation.
I am working with a tool called Lectora. This is an authoring tool which generates HTML pages and SCORM compliant packages to be deployed to the LMS.
When I insert a button in the Lectora, the code that is generated is something like this...
<script>
// some code here...
button63 = new ObjButton('button63', ....);
button63.setImages('images/btn_next_en.png','images/btn_next_en.png','images/btn_next_mouseover_en.png');
button63.build();
button64 = new ObjButton('button64', ....);
button64.setImages('images/btn_back_en.png','images/btn_back_en.png','images/btn_back_mouseover_en.png');
button64.build();
button65897 = new ObjButton('button65897', ....);
button65897.setImages('images/btn_submit_en.png','images/btn_submit_en.png','images/btn_submit_mouseover_en.png');
button65897.build();
// some more code here...
</script>
So I try to write:
<script>
var arr_buttons = [];
for(var i in window)
{
if(window[i] typeof object)
{
if(window[i] != null)
{
if(window[i] instanceof ObjButton)
{
arr_buttons.push(i);
}
}
}
}
alert(arr_buttons.length); // gives me 845 in IE11 and it gives me 44 in IE8
</script>
And when I check the contents of arr_buttons in console or by any other method, I do not find button65897 of any other button object in it. Which makes me think that it is not iterated at all!! This is my problem.
ObjButton is a Lectora created javascript object and I cannot edit it.
Now, I have set the language option in another variable and depending on the variable value for language, I want to get hold of the object 'button65897' and change its images. Now I am finding it difficult to get hold of 'button65897' in IE8.
Isn't there any way to get hold of the object 'button65897' in IE8?

How would I pass data to an external script loaded with $.getScript()?

So I'm trying to load a javascript remotely using jquery's $.getScript, but I'm puzzled on how I can pass data to the external script.
I've tried setting variables before the call but they aren't available in the script that gets loaded, and when I try to send/retrieve them using the query string, the remote script tries to read the querystring of the base file that it gets called from, not itself. Is there any other way to do this? Or is it possible to have a javascript file read its own querystring rather than the file it's called from (that's loaded in the browser)?
// editor ini
var editor_ini = { page: current_page, action: 'edit' };
var foo = 'bar';
// load the editor
$.getScript('assets/desktop/desklets/'+launcher.config.editor+'/execute.js', function(){});
In the execute.js file, the editor_ini and foo are both unavailable, I get the same result with:
// load the editor
$.getScript('assets/desktop/desklets/'+launcher.config.editor+'/execute.js', { page: current_page, action: 'edit', foo: 'bar' }, function(){});
because the remote script seems to be getting the query string from the original document rather than the one used when calling the file.
If it matters, I was trying to use the query object plugin for jquery for reading the query string.
global variable declared in inline javascript is accessible in external javascript page loaded using $.getScript().
I bet that your var foo='bar' is inside a function, so not visible in global scope. Try:
window.foo = 'bar'
Truly global variables will be accessible to your script. So, if they aren't, then it's probably because your variables that you think are global actually aren't. You can either move them to the top level scope or set them on the window object like Alexei suggested.
There are other ways to share data.
1) You can put an id on the <script> tag that loads the code and then have the code get the .src value from that tag and get the query string off the script's actual URL. I like this option, but I don't know if you can do it using jQuery.getScript() since I don't think it exposes that as an option.
2) You can have the loading script call a function that you provide and return an object with the desired data from that function.
3) Once the new script is loaded, you can call a setXXX() function in that script to set the state that it needs.
4) You can set information into a cookie that the other script can read.
5) You can encode data into a URL hash value that the other script can read.

Categories

Resources